/* * 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; } } }