diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,1834 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.management.remote.rmi; + +import java.io.IOException; +import java.rmi.MarshalledObject; +import java.rmi.UnmarshalException; +import java.rmi.server.Unreferenced; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permission; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import javax.management.*; +import javax.management.remote.JMXServerErrorException; +import javax.management.remote.NotificationResult; +import javax.security.auth.Subject; +import sun.reflect.misc.ReflectUtil; + +import static javax.management.remote.rmi.RMIConnector.Util.cast; +import com.sun.jmx.remote.internal.ServerCommunicatorAdmin; +import com.sun.jmx.remote.internal.ServerNotifForwarder; +import com.sun.jmx.remote.security.JMXSubjectDomainCombiner; +import com.sun.jmx.remote.security.SubjectDelegator; +import com.sun.jmx.remote.util.ClassLoaderWithRepository; +import com.sun.jmx.remote.util.ClassLogger; +import com.sun.jmx.remote.util.EnvHelp; +import com.sun.jmx.remote.util.OrderClassLoaders; +import javax.management.loading.ClassLoaderRepository; + +/** + *

Implementation of the {@link RMIConnection} interface. User + * code will not usually reference this class.

+ * + * @since 1.5 + */ +/* + * Notice that we omit the type parameter from MarshalledObject everywhere, + * even though it would add useful information to the documentation. The + * reason is that it was only added in Mustang (Java SE 6), whereas versions + * 1.4 and 2.0 of the JMX API must be implementable on Tiger per our + * commitments for JSR 255. + */ +public class RMIConnectionImpl implements RMIConnection, Unreferenced { + + /** + * Constructs a new {@link RMIConnection}. This connection can be + * used with the JRMP transport. This object does + * not export itself: it is the responsibility of the caller to + * export it appropriately (see {@link + * RMIJRMPServerImpl#makeClient(String,Subject)}). + * + * @param rmiServer The RMIServerImpl object for which this + * connection is created. The behavior is unspecified if this + * parameter is null. + * @param connectionId The ID for this connection. The behavior + * is unspecified if this parameter is null. + * @param defaultClassLoader The default ClassLoader to be used + * when deserializing marshalled objects. Can be null, to signify + * the bootstrap class loader. + * @param subject the authenticated subject to be used for + * authorization. Can be null, to signify that no subject has + * been authenticated. + * @param env the environment containing attributes for the new + * RMIServerImpl. Can be null, equivalent to an + * empty map. + */ + public RMIConnectionImpl(RMIServerImpl rmiServer, + String connectionId, + ClassLoader defaultClassLoader, + Subject subject, + Map env) { + if (rmiServer == null || connectionId == null) + throw new NullPointerException("Illegal null argument"); + if (env == null) + env = Collections.emptyMap(); + this.rmiServer = rmiServer; + this.connectionId = connectionId; + this.defaultClassLoader = defaultClassLoader; + + this.subjectDelegator = new SubjectDelegator(); + this.subject = subject; + if (subject == null) { + this.acc = null; + this.removeCallerContext = false; + } else { + this.removeCallerContext = + SubjectDelegator.checkRemoveCallerContext(subject); + if (this.removeCallerContext) { + this.acc = + JMXSubjectDomainCombiner.getDomainCombinerContext(subject); + } else { + this.acc = + JMXSubjectDomainCombiner.getContext(subject); + } + } + this.mbeanServer = rmiServer.getMBeanServer(); + + final ClassLoader dcl = defaultClassLoader; + + ClassLoaderRepository repository = AccessController.doPrivileged( + new PrivilegedAction() { + public ClassLoaderRepository run() { + return mbeanServer.getClassLoaderRepository(); + } + }, + withPermissions(new MBeanPermission("*", "getClassLoaderRepository")) + ); + this.classLoaderWithRepository = AccessController.doPrivileged( + new PrivilegedAction() { + public ClassLoaderWithRepository run() { + return new ClassLoaderWithRepository( + repository, + dcl); + } + }, + withPermissions(new RuntimePermission("createClassLoader")) + ); + + this.defaultContextClassLoader = + AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public ClassLoader run() { + return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), + dcl); + } + }); + + serverCommunicatorAdmin = new + RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env)); + + this.env = env; + } + + private static AccessControlContext withPermissions(Permission ... perms){ + Permissions col = new Permissions(); + + for (Permission thePerm : perms ) { + col.add(thePerm); + } + + final ProtectionDomain pd = new ProtectionDomain(null, col); + return new AccessControlContext( new ProtectionDomain[] { pd }); + } + + private synchronized ServerNotifForwarder getServerNotifFwd() { + // Lazily created when first use. Mainly when + // addNotificationListener is first called. + if (serverNotifForwarder == null) + serverNotifForwarder = + new ServerNotifForwarder(mbeanServer, + env, + rmiServer.getNotifBuffer(), + connectionId); + return serverNotifForwarder; + } + + public String getConnectionId() throws IOException { + // We should call reqIncomming() here... shouldn't we? + return connectionId; + } + + public void close() throws IOException { + final boolean debug = logger.debugOn(); + final String idstr = (debug?"["+this.toString()+"]":null); + + synchronized (this) { + if (terminated) { + if (debug) logger.debug("close",idstr + " already terminated."); + return; + } + + if (debug) logger.debug("close",idstr + " closing."); + + terminated = true; + + if (serverCommunicatorAdmin != null) { + serverCommunicatorAdmin.terminate(); + } + + if (serverNotifForwarder != null) { + serverNotifForwarder.terminate(); + } + } + + rmiServer.clientClosed(this); + + if (debug) logger.debug("close",idstr + " closed."); + } + + public void unreferenced() { + logger.debug("unreferenced", "called"); + try { + close(); + logger.debug("unreferenced", "done"); + } catch (IOException e) { + logger.fine("unreferenced", e); + } + } + + //------------------------------------------------------------------------- + // MBeanServerConnection Wrapper + //------------------------------------------------------------------------- + + public ObjectInstance createMBean(String className, + ObjectName name, + Subject delegationSubject) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + IOException { + try { + final Object params[] = + new Object[] { className, name }; + + if (logger.debugOn()) + logger.debug("createMBean(String,ObjectName)", + "connectionId=" + connectionId +", className=" + + className+", name=" + name); + + return (ObjectInstance) + doPrivilegedOperation( + CREATE_MBEAN, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof InstanceAlreadyExistsException) + throw (InstanceAlreadyExistsException) e; + if (e instanceof MBeanRegistrationException) + throw (MBeanRegistrationException) e; + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof NotCompliantMBeanException) + throw (NotCompliantMBeanException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName, + Subject delegationSubject) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException, + IOException { + try { + final Object params[] = + new Object[] { className, name, loaderName }; + + if (logger.debugOn()) + logger.debug("createMBean(String,ObjectName,ObjectName)", + "connectionId=" + connectionId + +", className=" + className + +", name=" + name + +", loaderName=" + loaderName); + + return (ObjectInstance) + doPrivilegedOperation( + CREATE_MBEAN_LOADER, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof InstanceAlreadyExistsException) + throw (InstanceAlreadyExistsException) e; + if (e instanceof MBeanRegistrationException) + throw (MBeanRegistrationException) e; + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof NotCompliantMBeanException) + throw (NotCompliantMBeanException) e; + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public ObjectInstance createMBean(String className, + ObjectName name, + MarshalledObject params, + String signature[], + Subject delegationSubject) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + IOException { + + final Object[] values; + final boolean debug = logger.debugOn(); + + if (debug) logger.debug( + "createMBean(String,ObjectName,Object[],String[])", + "connectionId=" + connectionId + +", unwrapping parameters using classLoaderWithRepository."); + + values = + nullIsEmpty(unwrap(params, classLoaderWithRepository, Object[].class,delegationSubject)); + + try { + final Object params2[] = + new Object[] { className, name, values, + nullIsEmpty(signature) }; + + if (debug) + logger.debug("createMBean(String,ObjectName,Object[],String[])", + "connectionId=" + connectionId + +", className=" + className + +", name=" + name + +", signature=" + strings(signature)); + + return (ObjectInstance) + doPrivilegedOperation( + CREATE_MBEAN_PARAMS, + params2, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof InstanceAlreadyExistsException) + throw (InstanceAlreadyExistsException) e; + if (e instanceof MBeanRegistrationException) + throw (MBeanRegistrationException) e; + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof NotCompliantMBeanException) + throw (NotCompliantMBeanException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName, + MarshalledObject params, + String signature[], + Subject delegationSubject) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException, + IOException { + + final Object[] values; + final boolean debug = logger.debugOn(); + + if (debug) logger.debug( + "createMBean(String,ObjectName,ObjectName,Object[],String[])", + "connectionId=" + connectionId + +", unwrapping params with MBean extended ClassLoader."); + + values = nullIsEmpty(unwrap(params, + getClassLoader(loaderName), + defaultClassLoader, + Object[].class,delegationSubject)); + + try { + final Object params2[] = + new Object[] { className, name, loaderName, values, + nullIsEmpty(signature) }; + + if (debug) logger.debug( + "createMBean(String,ObjectName,ObjectName,Object[],String[])", + "connectionId=" + connectionId + +", className=" + className + +", name=" + name + +", loaderName=" + loaderName + +", signature=" + strings(signature)); + + return (ObjectInstance) + doPrivilegedOperation( + CREATE_MBEAN_LOADER_PARAMS, + params2, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof InstanceAlreadyExistsException) + throw (InstanceAlreadyExistsException) e; + if (e instanceof MBeanRegistrationException) + throw (MBeanRegistrationException) e; + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof NotCompliantMBeanException) + throw (NotCompliantMBeanException) e; + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public void unregisterMBean(ObjectName name, Subject delegationSubject) + throws + InstanceNotFoundException, + MBeanRegistrationException, + IOException { + try { + final Object params[] = new Object[] { name }; + + if (logger.debugOn()) logger.debug("unregisterMBean", + "connectionId=" + connectionId + +", name="+name); + + doPrivilegedOperation( + UNREGISTER_MBEAN, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof MBeanRegistrationException) + throw (MBeanRegistrationException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public ObjectInstance getObjectInstance(ObjectName name, + Subject delegationSubject) + throws + InstanceNotFoundException, + IOException { + + checkNonNull("ObjectName", name); + + try { + final Object params[] = new Object[] { name }; + + if (logger.debugOn()) logger.debug("getObjectInstance", + "connectionId=" + connectionId + +", name="+name); + + return (ObjectInstance) + doPrivilegedOperation( + GET_OBJECT_INSTANCE, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public Set + queryMBeans(ObjectName name, + MarshalledObject query, + Subject delegationSubject) + throws IOException { + final QueryExp queryValue; + final boolean debug=logger.debugOn(); + + if (debug) logger.debug("queryMBeans", + "connectionId=" + connectionId + +" unwrapping query with defaultClassLoader."); + + queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject); + + try { + final Object params[] = new Object[] { name, queryValue }; + + if (debug) logger.debug("queryMBeans", + "connectionId=" + connectionId + +", name="+name +", query="+query); + + return cast( + doPrivilegedOperation( + QUERY_MBEANS, + params, + delegationSubject)); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public Set + queryNames(ObjectName name, + MarshalledObject query, + Subject delegationSubject) + throws IOException { + final QueryExp queryValue; + final boolean debug=logger.debugOn(); + + if (debug) logger.debug("queryNames", + "connectionId=" + connectionId + +" unwrapping query with defaultClassLoader."); + + queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject); + + try { + final Object params[] = new Object[] { name, queryValue }; + + if (debug) logger.debug("queryNames", + "connectionId=" + connectionId + +", name="+name +", query="+query); + + return cast( + doPrivilegedOperation( + QUERY_NAMES, + params, + delegationSubject)); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public boolean isRegistered(ObjectName name, + Subject delegationSubject) throws IOException { + try { + final Object params[] = new Object[] { name }; + return ((Boolean) + doPrivilegedOperation( + IS_REGISTERED, + params, + delegationSubject)).booleanValue(); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public Integer getMBeanCount(Subject delegationSubject) + throws IOException { + try { + final Object params[] = new Object[] { }; + + if (logger.debugOn()) logger.debug("getMBeanCount", + "connectionId=" + connectionId); + + return (Integer) + doPrivilegedOperation( + GET_MBEAN_COUNT, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public Object getAttribute(ObjectName name, + String attribute, + Subject delegationSubject) + throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException, + IOException { + try { + final Object params[] = new Object[] { name, attribute }; + if (logger.debugOn()) logger.debug("getAttribute", + "connectionId=" + connectionId + +", name=" + name + +", attribute="+ attribute); + + return + doPrivilegedOperation( + GET_ATTRIBUTE, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof AttributeNotFoundException) + throw (AttributeNotFoundException) e; + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public AttributeList getAttributes(ObjectName name, + String[] attributes, + Subject delegationSubject) + throws + InstanceNotFoundException, + ReflectionException, + IOException { + try { + final Object params[] = new Object[] { name, attributes }; + + if (logger.debugOn()) logger.debug("getAttributes", + "connectionId=" + connectionId + +", name=" + name + +", attributes="+ strings(attributes)); + + return (AttributeList) + doPrivilegedOperation( + GET_ATTRIBUTES, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public void setAttribute(ObjectName name, + MarshalledObject attribute, + Subject delegationSubject) + throws + InstanceNotFoundException, + AttributeNotFoundException, + InvalidAttributeValueException, + MBeanException, + ReflectionException, + IOException { + final Attribute attr; + final boolean debug=logger.debugOn(); + + if (debug) logger.debug("setAttribute", + "connectionId=" + connectionId + +" unwrapping attribute with MBean extended ClassLoader."); + + attr = unwrap(attribute, + getClassLoaderFor(name), + defaultClassLoader, + Attribute.class, delegationSubject); + + try { + final Object params[] = new Object[] { name, attr }; + + if (debug) logger.debug("setAttribute", + "connectionId=" + connectionId + +", name="+name + +", attribute name="+attr.getName()); + + doPrivilegedOperation( + SET_ATTRIBUTE, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof AttributeNotFoundException) + throw (AttributeNotFoundException) e; + if (e instanceof InvalidAttributeValueException) + throw (InvalidAttributeValueException) e; + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public AttributeList setAttributes(ObjectName name, + MarshalledObject attributes, + Subject delegationSubject) + throws + InstanceNotFoundException, + ReflectionException, + IOException { + final AttributeList attrlist; + final boolean debug=logger.debugOn(); + + if (debug) logger.debug("setAttributes", + "connectionId=" + connectionId + +" unwrapping attributes with MBean extended ClassLoader."); + + attrlist = + unwrap(attributes, + getClassLoaderFor(name), + defaultClassLoader, + AttributeList.class, delegationSubject); + + try { + final Object params[] = new Object[] { name, attrlist }; + + if (debug) logger.debug("setAttributes", + "connectionId=" + connectionId + +", name="+name + +", attribute names="+RMIConnector.getAttributesNames(attrlist)); + + return (AttributeList) + doPrivilegedOperation( + SET_ATTRIBUTES, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public Object invoke(ObjectName name, + String operationName, + MarshalledObject params, + String signature[], + Subject delegationSubject) + throws + InstanceNotFoundException, + MBeanException, + ReflectionException, + IOException { + + checkNonNull("ObjectName", name); + checkNonNull("Operation name", operationName); + + final Object[] values; + final boolean debug=logger.debugOn(); + + if (debug) logger.debug("invoke", + "connectionId=" + connectionId + +" unwrapping params with MBean extended ClassLoader."); + + values = nullIsEmpty(unwrap(params, + getClassLoaderFor(name), + defaultClassLoader, + Object[].class, delegationSubject)); + + try { + final Object params2[] = + new Object[] { name, operationName, values, + nullIsEmpty(signature) }; + + if (debug) logger.debug("invoke", + "connectionId=" + connectionId + +", name="+name + +", operationName="+operationName + +", signature="+strings(signature)); + + return + doPrivilegedOperation( + INVOKE, + params2, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof MBeanException) + throw (MBeanException) e; + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public String getDefaultDomain(Subject delegationSubject) + throws IOException { + try { + final Object params[] = new Object[] { }; + + if (logger.debugOn()) logger.debug("getDefaultDomain", + "connectionId=" + connectionId); + + return (String) + doPrivilegedOperation( + GET_DEFAULT_DOMAIN, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public String[] getDomains(Subject delegationSubject) throws IOException { + try { + final Object params[] = new Object[] { }; + + if (logger.debugOn()) logger.debug("getDomains", + "connectionId=" + connectionId); + + return (String[]) + doPrivilegedOperation( + GET_DOMAINS, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject) + throws + InstanceNotFoundException, + IntrospectionException, + ReflectionException, + IOException { + + checkNonNull("ObjectName", name); + + try { + final Object params[] = new Object[] { name }; + + if (logger.debugOn()) logger.debug("getMBeanInfo", + "connectionId=" + connectionId + +", name="+name); + + return (MBeanInfo) + doPrivilegedOperation( + GET_MBEAN_INFO, + params, + delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof IntrospectionException) + throw (IntrospectionException) e; + if (e instanceof ReflectionException) + throw (ReflectionException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + public boolean isInstanceOf(ObjectName name, + String className, + Subject delegationSubject) + throws InstanceNotFoundException, IOException { + + checkNonNull("ObjectName", name); + + try { + final Object params[] = new Object[] { name, className }; + + if (logger.debugOn()) logger.debug("isInstanceOf", + "connectionId=" + connectionId + +", name="+name + +", className="+className); + + return ((Boolean) + doPrivilegedOperation( + IS_INSTANCE_OF, + params, + delegationSubject)).booleanValue(); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof InstanceNotFoundException) + throw (InstanceNotFoundException) e; + if (e instanceof IOException) + throw (IOException) e; + throw newIOException("Got unexpected server exception: " + e, e); + } + } + + @SuppressWarnings("rawtypes") // MarshalledObject + public Integer[] addNotificationListeners(ObjectName[] names, + MarshalledObject[] filters, + Subject[] delegationSubjects) + throws InstanceNotFoundException, IOException { + + if (names == null || filters == null) { + throw new IllegalArgumentException("Got null arguments."); + } + + Subject[] sbjs = (delegationSubjects != null) ? delegationSubjects : + new Subject[names.length]; + if (names.length != filters.length || filters.length != sbjs.length) { + final String msg = + "The value lengths of 3 parameters are not same."; + throw new IllegalArgumentException(msg); + } + + for (int i=0; i action = + new PrivilegedAction() { + public NotificationResult run() { + return getServerNotifFwd().fetchNotifs(csn, t, mn); + } + }; + if (acc == null) + return action.run(); + else + return AccessController.doPrivileged(action, acc); + } finally { + serverCommunicatorAdmin.rspOutgoing(); + } + } + + /** + *

Returns a string representation of this object. In general, + * the toString method returns a string that + * "textually represents" this object. The result should be a + * concise but informative representation that is easy for a + * person to read.

+ * + * @return a String representation of this object. + **/ + @Override + public String toString() { + return super.toString() + ": connectionId=" + connectionId; + } + + //------------------------------------------------------------------------ + // private classes + //------------------------------------------------------------------------ + + private class PrivilegedOperation + implements PrivilegedExceptionAction { + + public PrivilegedOperation(int operation, Object[] params) { + this.operation = operation; + this.params = params; + } + + public Object run() throws Exception { + return doOperation(operation, params); + } + + private int operation; + private Object[] params; + } + + //------------------------------------------------------------------------ + // private classes + //------------------------------------------------------------------------ + private class RMIServerCommunicatorAdmin extends ServerCommunicatorAdmin { + public RMIServerCommunicatorAdmin(long timeout) { + super(timeout); + } + + protected void doStop() { + try { + close(); + } catch (IOException ie) { + logger.warning("RMIServerCommunicatorAdmin-doStop", + "Failed to close: " + ie); + logger.debug("RMIServerCommunicatorAdmin-doStop",ie); + } + } + + } + + + //------------------------------------------------------------------------ + // private methods + //------------------------------------------------------------------------ + + private ClassLoader getClassLoader(final ObjectName name) + throws InstanceNotFoundException { + try { + return + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public ClassLoader run() throws InstanceNotFoundException { + return mbeanServer.getClassLoader(name); + } + }, + withPermissions(new MBeanPermission("*", "getClassLoader")) + ); + } catch (PrivilegedActionException pe) { + throw (InstanceNotFoundException) extractException(pe); + } + } + + private ClassLoader getClassLoaderFor(final ObjectName name) + throws InstanceNotFoundException { + try { + return (ClassLoader) + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public Object run() throws InstanceNotFoundException { + return mbeanServer.getClassLoaderFor(name); + } + }, + withPermissions(new MBeanPermission("*", "getClassLoaderFor")) + ); + } catch (PrivilegedActionException pe) { + throw (InstanceNotFoundException) extractException(pe); + } + } + + private Object doPrivilegedOperation(final int operation, + final Object[] params, + final Subject delegationSubject) + throws PrivilegedActionException, IOException { + + serverCommunicatorAdmin.reqIncoming(); + try { + + final AccessControlContext reqACC; + if (delegationSubject == null) + reqACC = acc; + else { + if (subject == null) { + final String msg = + "Subject delegation cannot be enabled unless " + + "an authenticated subject is put in place"; + throw new SecurityException(msg); + } + reqACC = subjectDelegator.delegatedContext( + acc, delegationSubject, removeCallerContext); + } + + PrivilegedOperation op = + new PrivilegedOperation(operation, params); + if (reqACC == null) { + try { + return op.run(); + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + throw new PrivilegedActionException(e); + } + } else { + return AccessController.doPrivileged(op, reqACC); + } + } catch (Error e) { + throw new JMXServerErrorException(e.toString(),e); + } finally { + serverCommunicatorAdmin.rspOutgoing(); + } + } + + private Object doOperation(int operation, Object[] params) + throws Exception { + + switch (operation) { + + case CREATE_MBEAN: + return mbeanServer.createMBean((String)params[0], + (ObjectName)params[1]); + + case CREATE_MBEAN_LOADER: + return mbeanServer.createMBean((String)params[0], + (ObjectName)params[1], + (ObjectName)params[2]); + + case CREATE_MBEAN_PARAMS: + return mbeanServer.createMBean((String)params[0], + (ObjectName)params[1], + (Object[])params[2], + (String[])params[3]); + + case CREATE_MBEAN_LOADER_PARAMS: + return mbeanServer.createMBean((String)params[0], + (ObjectName)params[1], + (ObjectName)params[2], + (Object[])params[3], + (String[])params[4]); + + case GET_ATTRIBUTE: + return mbeanServer.getAttribute((ObjectName)params[0], + (String)params[1]); + + case GET_ATTRIBUTES: + return mbeanServer.getAttributes((ObjectName)params[0], + (String[])params[1]); + + case GET_DEFAULT_DOMAIN: + return mbeanServer.getDefaultDomain(); + + case GET_DOMAINS: + return mbeanServer.getDomains(); + + case GET_MBEAN_COUNT: + return mbeanServer.getMBeanCount(); + + case GET_MBEAN_INFO: + return mbeanServer.getMBeanInfo((ObjectName)params[0]); + + case GET_OBJECT_INSTANCE: + return mbeanServer.getObjectInstance((ObjectName)params[0]); + + case INVOKE: + return mbeanServer.invoke((ObjectName)params[0], + (String)params[1], + (Object[])params[2], + (String[])params[3]); + + case IS_INSTANCE_OF: + return mbeanServer.isInstanceOf((ObjectName)params[0], + (String)params[1]) + ? Boolean.TRUE : Boolean.FALSE; + + case IS_REGISTERED: + return mbeanServer.isRegistered((ObjectName)params[0]) + ? Boolean.TRUE : Boolean.FALSE; + + case QUERY_MBEANS: + return mbeanServer.queryMBeans((ObjectName)params[0], + (QueryExp)params[1]); + + case QUERY_NAMES: + return mbeanServer.queryNames((ObjectName)params[0], + (QueryExp)params[1]); + + case SET_ATTRIBUTE: + mbeanServer.setAttribute((ObjectName)params[0], + (Attribute)params[1]); + return null; + + case SET_ATTRIBUTES: + return mbeanServer.setAttributes((ObjectName)params[0], + (AttributeList)params[1]); + + case UNREGISTER_MBEAN: + mbeanServer.unregisterMBean((ObjectName)params[0]); + return null; + + case ADD_NOTIFICATION_LISTENERS: + return getServerNotifFwd().addNotificationListener( + (ObjectName)params[0], + (NotificationFilter)params[1]); + + case ADD_NOTIFICATION_LISTENER_OBJECTNAME: + mbeanServer.addNotificationListener((ObjectName)params[0], + (ObjectName)params[1], + (NotificationFilter)params[2], + params[3]); + return null; + + case REMOVE_NOTIFICATION_LISTENER: + getServerNotifFwd().removeNotificationListener( + (ObjectName)params[0], + (Integer[])params[1]); + return null; + + case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME: + mbeanServer.removeNotificationListener((ObjectName)params[0], + (ObjectName)params[1]); + return null; + + case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK: + mbeanServer.removeNotificationListener( + (ObjectName)params[0], + (ObjectName)params[1], + (NotificationFilter)params[2], + params[3]); + return null; + + default: + throw new IllegalArgumentException("Invalid operation"); + } + } + + private static class SetCcl implements PrivilegedExceptionAction { + private final ClassLoader classLoader; + + SetCcl(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public ClassLoader run() { + Thread currentThread = Thread.currentThread(); + ClassLoader old = currentThread.getContextClassLoader(); + currentThread.setContextClassLoader(classLoader); + return old; + } + } + + private T unwrap(final MarshalledObject mo, + final ClassLoader cl, + final Class wrappedClass, + Subject delegationSubject) + throws IOException { + if (mo == null) { + return null; + } + try { + final ClassLoader old = AccessController.doPrivileged(new SetCcl(cl)); + try{ + final AccessControlContext reqACC; + if (delegationSubject == null) + reqACC = acc; + else { + if (subject == null) { + final String msg = + "Subject delegation cannot be enabled unless " + + "an authenticated subject is put in place"; + throw new SecurityException(msg); + } + reqACC = subjectDelegator.delegatedContext( + acc, delegationSubject, removeCallerContext); + } + if(reqACC != null){ + return AccessController.doPrivileged( + (PrivilegedExceptionAction) () -> + wrappedClass.cast(mo.get()), reqACC); + }else{ + return wrappedClass.cast(mo.get()); + } + }finally{ + AccessController.doPrivileged(new SetCcl(old)); + } + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) { + throw (IOException) e; + } + if (e instanceof ClassNotFoundException) { + throw new UnmarshalException(e.toString(), e); + } + logger.warning("unwrap", "Failed to unmarshall object: " + e); + logger.debug("unwrap", e); + }catch (ClassNotFoundException ex) { + logger.warning("unwrap", "Failed to unmarshall object: " + ex); + logger.debug("unwrap", ex); + throw new UnmarshalException(ex.toString(), ex); + } + return null; + } + + private T unwrap(final MarshalledObject mo, + final ClassLoader cl1, + final ClassLoader cl2, + final Class wrappedClass, + Subject delegationSubject) + throws IOException { + if (mo == null) { + return null; + } + try { + ClassLoader orderCL = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public ClassLoader run() throws Exception { + return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), + new OrderClassLoaders(cl1, cl2)); + } + } + ); + return unwrap(mo, orderCL, wrappedClass,delegationSubject); + } catch (PrivilegedActionException pe) { + Exception e = extractException(pe); + if (e instanceof IOException) { + throw (IOException) e; + } + if (e instanceof ClassNotFoundException) { + throw new UnmarshalException(e.toString(), e); + } + logger.warning("unwrap", "Failed to unmarshall object: " + e); + logger.debug("unwrap", e); + } + return null; + } + + /** + * Construct a new IOException with a nested exception. + * The nested exception is set only if JDK {@literal >= 1.4} + */ + private static IOException newIOException(String message, + Throwable cause) { + final IOException x = new IOException(message); + return EnvHelp.initCause(x,cause); + } + + /** + * Iterate until we extract the real exception + * from a stack of PrivilegedActionExceptions. + */ + private static Exception extractException(Exception e) { + while (e instanceof PrivilegedActionException) { + e = ((PrivilegedActionException)e).getException(); + } + return e; + } + + private static final Object[] NO_OBJECTS = new Object[0]; + private static final String[] NO_STRINGS = new String[0]; + + /* + * The JMX spec doesn't explicitly say that a null Object[] or + * String[] in e.g. MBeanServer.invoke is equivalent to an empty + * array, but the RI behaves that way. In the interests of + * maximal interoperability, we make it so even when we're + * connected to some other JMX implementation that might not do + * that. This should be clarified in the next version of JMX. + */ + private static Object[] nullIsEmpty(Object[] array) { + return (array == null) ? NO_OBJECTS : array; + } + + private static String[] nullIsEmpty(String[] array) { + return (array == null) ? NO_STRINGS : array; + } + + /* + * Similarly, the JMX spec says for some but not all methods in + * MBeanServer that take an ObjectName target, that if it's null + * you get this exception. We specify it for all of them, and + * make it so for the ones where it's not specified in JMX even if + * the JMX implementation doesn't do so. + */ + private static void checkNonNull(String what, Object x) { + if (x == null) { + RuntimeException wrapped = + new IllegalArgumentException(what + " must not be null"); + throw new RuntimeOperationsException(wrapped); + } + } + + //------------------------------------------------------------------------ + // private variables + //------------------------------------------------------------------------ + + private final Subject subject; + + private final SubjectDelegator subjectDelegator; + + private final boolean removeCallerContext; + + private final AccessControlContext acc; + + private final RMIServerImpl rmiServer; + + private final MBeanServer mbeanServer; + + private final ClassLoader defaultClassLoader; + + private final ClassLoader defaultContextClassLoader; + + private final ClassLoaderWithRepository classLoaderWithRepository; + + private boolean terminated = false; + + private final String connectionId; + + private final ServerCommunicatorAdmin serverCommunicatorAdmin; + + // Method IDs for doOperation + //--------------------------- + + private final static int + ADD_NOTIFICATION_LISTENERS = 1; + private final static int + ADD_NOTIFICATION_LISTENER_OBJECTNAME = 2; + private final static int + CREATE_MBEAN = 3; + private final static int + CREATE_MBEAN_PARAMS = 4; + private final static int + CREATE_MBEAN_LOADER = 5; + private final static int + CREATE_MBEAN_LOADER_PARAMS = 6; + private final static int + GET_ATTRIBUTE = 7; + private final static int + GET_ATTRIBUTES = 8; + private final static int + GET_DEFAULT_DOMAIN = 9; + private final static int + GET_DOMAINS = 10; + private final static int + GET_MBEAN_COUNT = 11; + private final static int + GET_MBEAN_INFO = 12; + private final static int + GET_OBJECT_INSTANCE = 13; + private final static int + INVOKE = 14; + private final static int + IS_INSTANCE_OF = 15; + private final static int + IS_REGISTERED = 16; + private final static int + QUERY_MBEANS = 17; + private final static int + QUERY_NAMES = 18; + private final static int + REMOVE_NOTIFICATION_LISTENER = 19; + private final static int + REMOVE_NOTIFICATION_LISTENER_OBJECTNAME = 20; + private final static int + REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 21; + private final static int + SET_ATTRIBUTE = 22; + private final static int + SET_ATTRIBUTES = 23; + private final static int + UNREGISTER_MBEAN = 24; + + // SERVER NOTIFICATION + //-------------------- + + private ServerNotifForwarder serverNotifForwarder; + private Map env; + + // TRACES & DEBUG + //--------------- + + private static String objects(final Object[] objs) { + if (objs == null) + return "null"; + else + return Arrays.asList(objs).toString(); + } + + private static String strings(final String[] strs) { + return objects(strs); + } + + private static final ClassLogger logger = + new ClassLogger("javax.management.remote.rmi", "RMIConnectionImpl"); + + private static final class CombinedClassLoader extends ClassLoader { + + private final static class ClassLoaderWrapper extends ClassLoader { + ClassLoaderWrapper(ClassLoader cl) { + super(cl); + } + + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + return super.loadClass(name, resolve); + } + }; + + final ClassLoaderWrapper defaultCL; + + private CombinedClassLoader(ClassLoader parent, ClassLoader defaultCL) { + super(parent); + this.defaultCL = new ClassLoaderWrapper(defaultCL); + } + + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + ReflectUtil.checkPackageAccess(name); + try { + super.loadClass(name, resolve); + } catch(Exception e) { + for(Throwable t = e; t != null; t = t.getCause()) { + if(t instanceof SecurityException) { + throw t==e?(SecurityException)t:new SecurityException(t.getMessage(), e); + } + } + } + final Class cl = defaultCL.loadClass(name, resolve); + return cl; + } + + } +}