| /* | |
| * Copyright (c) 2002, 2025, 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.util.Arrays; | |
| import java.util.Collections; | |
| import java.util.Map; | |
| import java.util.Set; | |
| import java.util.concurrent.CompletionException; | |
| import javax.management.*; | |
| import javax.management.remote.JMXServerErrorException; | |
| import javax.management.remote.NotificationResult; | |
| import javax.security.auth.Subject; | |
| 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.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; | |
| /** | |
| * <p>Implementation of the {@link RMIConnection} interface. User | |
| * code will not usually reference this class.</p> | |
| * | |
| * @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 | |
| * <code>RMIServerImpl</code>. Can be null, equivalent to an | |
| * empty map. | |
| */ | |
| public RMIConnectionImpl(RMIServerImpl rmiServer, | |
| String connectionId, | |
| ClassLoader defaultClassLoader, | |
| Subject subject, | |
| Map<String,?> 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.subject = subject; | |
| this.mbeanServer = rmiServer.getMBeanServer(); | |
| final ClassLoader dcl = defaultClassLoader; | |
| ClassLoaderRepository repository = mbeanServer.getClassLoaderRepository(); | |
| classLoaderWithRepository = new ClassLoaderWithRepository(repository, dcl); | |
| defaultContextClassLoader = new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), dcl); | |
| serverCommunicatorAdmin = new RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env)); | |
| this.env = env; | |
| } | |
| 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 { | |
| // reqIncoming()/rspOutgoing() could be here, but never have been. | |
| 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 | |
| //------------------------------------------------------------------------- | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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) | |
| doOperation( | |
| CREATE_MBEAN, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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) | |
| doOperation( | |
| CREATE_MBEAN_LOADER, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @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) | |
| doOperation( | |
| CREATE_MBEAN_PARAMS, | |
| params2, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @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, | |
| mbeanServer.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) | |
| doOperation( | |
| CREATE_MBEAN_LOADER_PARAMS, | |
| params2, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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); | |
| doOperation( | |
| UNREGISTER_MBEAN, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof MBeanRegistrationException) | |
| throw (MBeanRegistrationException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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) | |
| doOperation( | |
| GET_OBJECT_INSTANCE, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @SuppressWarnings("rawtypes") // MarshalledObject | |
| public Set<ObjectInstance> | |
| 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( | |
| doOperation( | |
| QUERY_MBEANS, | |
| params, | |
| delegationSubject)); | |
| } catch (Exception e) { | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @SuppressWarnings("rawtypes") // MarshalledObject | |
| public Set<ObjectName> | |
| 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( | |
| doOperation( | |
| QUERY_NAMES, | |
| params, | |
| delegationSubject)); | |
| } catch (Exception e) { | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| public boolean isRegistered(ObjectName name, | |
| Subject delegationSubject) throws IOException { | |
| try { | |
| final Object params[] = new Object[] { name }; | |
| return ((Boolean) | |
| doOperation( | |
| IS_REGISTERED, | |
| params, | |
| delegationSubject)).booleanValue(); | |
| } catch (Exception e) { | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| public Integer getMBeanCount(Subject delegationSubject) | |
| throws IOException { | |
| try { | |
| final Object params[] = new Object[] { }; | |
| if (logger.debugOn()) logger.debug("getMBeanCount", | |
| "connectionId=" + connectionId); | |
| return (Integer) | |
| doOperation( | |
| GET_MBEAN_COUNT, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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 | |
| doOperation( | |
| GET_ATTRIBUTE, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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) | |
| doOperation( | |
| GET_ATTRIBUTES, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof ReflectionException) | |
| throw (ReflectionException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @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()); | |
| doOperation( | |
| SET_ATTRIBUTE, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @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) | |
| doOperation( | |
| SET_ATTRIBUTES, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof ReflectionException) | |
| throw (ReflectionException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @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 | |
| doOperation( | |
| INVOKE, | |
| params2, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| public String getDefaultDomain(Subject delegationSubject) | |
| throws IOException { | |
| try { | |
| final Object params[] = new Object[] { }; | |
| if (logger.debugOn()) logger.debug("getDefaultDomain", | |
| "connectionId=" + connectionId); | |
| return (String) | |
| doOperation( | |
| GET_DEFAULT_DOMAIN, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| public String[] getDomains(Subject delegationSubject) throws IOException { | |
| try { | |
| final Object params[] = new Object[] { }; | |
| if (logger.debugOn()) logger.debug("getDomains", | |
| "connectionId=" + connectionId); | |
| return (String[]) | |
| doOperation( | |
| GET_DOMAINS, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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) | |
| doOperation( | |
| GET_MBEAN_INFO, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| 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) | |
| doOperation( | |
| IS_INSTANCE_OF, | |
| params, | |
| delegationSubject)).booleanValue(); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @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."); | |
| } | |
| // Accept an array of delegationSubjects from e.g. earlier JDKs, | |
| // but throw if it contains any non-null values. | |
| if (delegationSubjects != null) { | |
| for (Subject s: delegationSubjects) { | |
| if (s != null) { | |
| throw new UnsupportedOperationException("Subject Delegation has been removed."); | |
| } | |
| } | |
| } | |
| if (names.length != filters.length) { | |
| final String msg = "The lengths of names and filters parameters are not same."; | |
| throw new IllegalArgumentException(msg); | |
| } | |
| for (int i=0; i<names.length; i++) { | |
| if (names[i] == null) { | |
| throw new IllegalArgumentException("Null Object name."); | |
| } | |
| } | |
| int i=0; | |
| ClassLoader targetCl; | |
| NotificationFilter[] filterValues = | |
| new NotificationFilter[names.length]; | |
| Integer[] ids = new Integer[names.length]; | |
| final boolean debug=logger.debugOn(); | |
| try { | |
| for (; i<names.length; i++) { | |
| targetCl = getClassLoaderFor(names[i]); | |
| if (debug) logger.debug("addNotificationListener"+ | |
| "(ObjectName,NotificationFilter)", | |
| "connectionId=" + connectionId + | |
| " unwrapping filter with target extended ClassLoader."); | |
| filterValues[i] = | |
| unwrap(filters[i], targetCl, defaultClassLoader, | |
| NotificationFilter.class, null); | |
| if (debug) logger.debug("addNotificationListener"+ | |
| "(ObjectName,NotificationFilter)", | |
| "connectionId=" + connectionId | |
| +", name=" + names[i] | |
| +", filter=" + filterValues[i]); | |
| ids[i] = (Integer) | |
| doOperation(ADD_NOTIFICATION_LISTENERS, | |
| new Object[] { names[i], | |
| filterValues[i] }, | |
| null); | |
| } | |
| return ids; | |
| } catch (Exception e) { | |
| // remove all registered listeners | |
| for (int j=0; j<i; j++) { | |
| try { | |
| getServerNotifFwd().removeNotificationListener(names[j], | |
| ids[j]); | |
| } catch (Exception eee) { | |
| // strange | |
| } | |
| } | |
| if (e instanceof ClassCastException) { | |
| throw (ClassCastException) e; | |
| } else if (e instanceof IOException) { | |
| throw (IOException)e; | |
| } else if (e instanceof InstanceNotFoundException) { | |
| throw (InstanceNotFoundException) e; | |
| } else if (e instanceof RuntimeException) { | |
| throw (RuntimeException) e; | |
| } else { | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @SuppressWarnings("rawtypes") // MarshalledObject | |
| public void addNotificationListener(ObjectName name, | |
| ObjectName listener, | |
| MarshalledObject filter, | |
| MarshalledObject handback, | |
| Subject delegationSubject) | |
| throws InstanceNotFoundException, IOException { | |
| checkNonNull("Target MBean name", name); | |
| checkNonNull("Listener MBean name", listener); | |
| final NotificationFilter filterValue; | |
| final Object handbackValue; | |
| final boolean debug=logger.debugOn(); | |
| final ClassLoader targetCl = getClassLoaderFor(name); | |
| if (debug) logger.debug("addNotificationListener"+ | |
| "(ObjectName,ObjectName,NotificationFilter,Object)", | |
| "connectionId=" + connectionId | |
| +" unwrapping filter with target extended ClassLoader."); | |
| filterValue = | |
| unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject); | |
| if (debug) logger.debug("addNotificationListener"+ | |
| "(ObjectName,ObjectName,NotificationFilter,Object)", | |
| "connectionId=" + connectionId | |
| +" unwrapping handback with target extended ClassLoader."); | |
| handbackValue = | |
| unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject); | |
| try { | |
| final Object params[] = | |
| new Object[] { name, listener, filterValue, handbackValue }; | |
| if (debug) logger.debug("addNotificationListener"+ | |
| "(ObjectName,ObjectName,NotificationFilter,Object)", | |
| "connectionId=" + connectionId | |
| +", name=" + name | |
| +", listenerName=" + listener | |
| +", filter=" + filterValue | |
| +", handback=" + handbackValue); | |
| doOperation( | |
| ADD_NOTIFICATION_LISTENER_OBJECTNAME, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| public void removeNotificationListeners(ObjectName name, | |
| Integer[] listenerIDs, | |
| Subject delegationSubject) | |
| throws | |
| InstanceNotFoundException, | |
| ListenerNotFoundException, | |
| IOException { | |
| if (name == null || listenerIDs == null) | |
| throw new IllegalArgumentException("Illegal null parameter"); | |
| for (int i = 0; i < listenerIDs.length; i++) { | |
| if (listenerIDs[i] == null) | |
| throw new IllegalArgumentException("Null listener ID"); | |
| } | |
| try { | |
| final Object params[] = new Object[] { name, listenerIDs }; | |
| if (logger.debugOn()) logger.debug("removeNotificationListener"+ | |
| "(ObjectName,Integer[])", | |
| "connectionId=" + connectionId | |
| +", name=" + name | |
| +", listenerIDs=" + objects(listenerIDs)); | |
| doOperation( | |
| REMOVE_NOTIFICATION_LISTENER, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof ListenerNotFoundException) | |
| throw (ListenerNotFoundException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| public void removeNotificationListener(ObjectName name, | |
| ObjectName listener, | |
| Subject delegationSubject) | |
| throws | |
| InstanceNotFoundException, | |
| ListenerNotFoundException, | |
| IOException { | |
| checkNonNull("Target MBean name", name); | |
| checkNonNull("Listener MBean name", listener); | |
| try { | |
| final Object params[] = new Object[] { name, listener }; | |
| if (logger.debugOn()) logger.debug("removeNotificationListener"+ | |
| "(ObjectName,ObjectName)", | |
| "connectionId=" + connectionId | |
| +", name=" + name | |
| +", listenerName=" + listener); | |
| doOperation( | |
| REMOVE_NOTIFICATION_LISTENER_OBJECTNAME, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof ListenerNotFoundException) | |
| throw (ListenerNotFoundException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| @SuppressWarnings("rawtypes") // MarshalledObject | |
| public void removeNotificationListener(ObjectName name, | |
| ObjectName listener, | |
| MarshalledObject filter, | |
| MarshalledObject handback, | |
| Subject delegationSubject) | |
| throws | |
| InstanceNotFoundException, | |
| ListenerNotFoundException, | |
| IOException { | |
| checkNonNull("Target MBean name", name); | |
| checkNonNull("Listener MBean name", listener); | |
| final NotificationFilter filterValue; | |
| final Object handbackValue; | |
| final boolean debug=logger.debugOn(); | |
| final ClassLoader targetCl = getClassLoaderFor(name); | |
| if (debug) logger.debug("removeNotificationListener"+ | |
| "(ObjectName,ObjectName,NotificationFilter,Object)", | |
| "connectionId=" + connectionId | |
| +" unwrapping filter with target extended ClassLoader."); | |
| filterValue = | |
| unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject); | |
| if (debug) logger.debug("removeNotificationListener"+ | |
| "(ObjectName,ObjectName,NotificationFilter,Object)", | |
| "connectionId=" + connectionId | |
| +" unwrapping handback with target extended ClassLoader."); | |
| handbackValue = | |
| unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject); | |
| try { | |
| final Object params[] = | |
| new Object[] { name, listener, filterValue, handbackValue }; | |
| if (debug) logger.debug("removeNotificationListener"+ | |
| "(ObjectName,ObjectName,NotificationFilter,Object)", | |
| "connectionId=" + connectionId | |
| +", name=" + name | |
| +", listenerName=" + listener | |
| +", filter=" + filterValue | |
| +", handback=" + handbackValue); | |
| doOperation( | |
| REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK, | |
| params, | |
| delegationSubject); | |
| } catch (Exception e) { | |
| if (e instanceof InstanceNotFoundException) | |
| throw (InstanceNotFoundException) e; | |
| if (e instanceof ListenerNotFoundException) | |
| throw (ListenerNotFoundException) e; | |
| if (e instanceof IOException) | |
| throw (IOException) e; | |
| if (e instanceof RuntimeException) | |
| throw (RuntimeException) e; | |
| throw new IOException("Got unexpected server exception: " + e, e); | |
| } | |
| } | |
| public NotificationResult fetchNotifications(long clientSequenceNumber, | |
| int maxNotifications, | |
| long timeout) | |
| throws IOException { | |
| if (logger.debugOn()) logger.debug("fetchNotifications", | |
| "connectionId=" + connectionId | |
| +", timeout=" + timeout); | |
| if (maxNotifications < 0 || timeout < 0) | |
| throw new IllegalArgumentException("Illegal negative argument"); | |
| final boolean serverTerminated = | |
| serverCommunicatorAdmin.reqIncoming(); | |
| try { | |
| if (serverTerminated) { | |
| // we must not call fetchNotifs() if the server is | |
| // terminated (timeout elapsed). | |
| // returns null to force the client to stop fetching | |
| if (logger.debugOn()) logger.debug("fetchNotifications", | |
| "The notification server has been closed, " | |
| + "returns null to force the client to stop fetching"); | |
| return null; | |
| } | |
| if (subject == null) { | |
| return getServerNotifFwd().fetchNotifs(clientSequenceNumber, timeout, maxNotifications); | |
| } else { | |
| try { | |
| return Subject.callAs(subject, () -> getServerNotifFwd().fetchNotifs(clientSequenceNumber, timeout, maxNotifications)); | |
| } catch (CompletionException ce) { | |
| Throwable thr = ce.getCause(); | |
| if (thr instanceof SecurityException se) { | |
| throw se; | |
| } else if (thr instanceof IOException ioe) { | |
| throw ioe; | |
| } else { | |
| throw new RuntimeException(thr); | |
| } | |
| } | |
| } | |
| } finally { | |
| serverCommunicatorAdmin.rspOutgoing(); | |
| } | |
| } | |
| /** | |
| * <p>Returns a string representation of this object. In general, | |
| * the <code>toString</code> 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.</p> | |
| * | |
| * @return a String representation of this object. | |
| **/ | |
| @Override | |
| public String toString() { | |
| return super.toString() + ": connectionId=" + connectionId; | |
| } | |
| //------------------------------------------------------------------------ | |
| // 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 getClassLoaderFor(final ObjectName name) | |
| throws InstanceNotFoundException { | |
| return mbeanServer.getClassLoaderFor(name); | |
| } | |
| /** @throws UnsupportedOperationException {@inheritDoc} */ | |
| private Object doOperation(final int operation, | |
| final Object[] params, | |
| final Subject delegationSubject) | |
| throws Exception { | |
| // Subject Delegation is removed: locally this is caught earlier, in getMBeanServerConnection, | |
| // but remote connections call into RMIConnectionImpl over RMI, so deny them here: | |
| if (delegationSubject != null) { | |
| throw new UnsupportedOperationException("Subject Delegation has been removed."); | |
| } | |
| serverCommunicatorAdmin.reqIncoming(); | |
| try { | |
| if (subject == null) { | |
| return doOperationInner(operation, params); | |
| } else { | |
| try { | |
| return Subject.callAs(subject, () -> doOperationInner(operation, params)); | |
| } catch (CompletionException ce) { | |
| Throwable thr = ce.getCause(); | |
| if (thr instanceof Exception e) { | |
| throw e; | |
| } else { | |
| throw new RuntimeException(thr); | |
| } | |
| } | |
| } | |
| } catch (Error e) { | |
| throw new JMXServerErrorException(e.toString(),e); | |
| } finally { | |
| serverCommunicatorAdmin.rspOutgoing(); | |
| } | |
| } | |
| private Object doOperationInner(int operation, Object[] params) | |
| throws Exception { | |
| // Renamed this method to ensure nothing accidentally calls it. | |
| // All calls are to the 3-argument doOperation(), except those from that method. | |
| 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 ClassLoader setCcl(ClassLoader classLoader) { | |
| Thread currentThread = Thread.currentThread(); | |
| ClassLoader old = currentThread.getContextClassLoader(); | |
| if (classLoader != old) { | |
| currentThread.setContextClassLoader(classLoader); | |
| } | |
| return old; | |
| } | |
| private <T> T unwrap(final MarshalledObject<?> mo, | |
| final ClassLoader cl, | |
| final Class<T> wrappedClass, | |
| Subject delegationSubject) | |
| throws IOException { | |
| // Subject Delegation is removed: locally this is caught earlier, in getMBeanServerConnection, | |
| // but remote connections call into RMIConnectionImpl over RMI, so deny them here: | |
| if (delegationSubject != null) { | |
| throw new UnsupportedOperationException("Subject Delegation has been removed."); | |
| } | |
| if (mo == null) { | |
| return null; | |
| } | |
| try { | |
| ClassLoader old = setCcl(cl); | |
| try { | |
| return wrappedClass.cast(mo.get()); | |
| } finally { | |
| setCcl(old); | |
| } | |
| } catch (Exception e) { | |
| if (e instanceof IOException) { | |
| throw (IOException) e; | |
| } | |
| logger.warning("unwrap", "Failed to unmarshall object: " + e); | |
| logger.debug("unwrap", e); | |
| throw new UnmarshalException(e.toString(), e); | |
| } | |
| } | |
| private <T> T unwrap(final MarshalledObject<?> mo, | |
| final ClassLoader cl1, | |
| final ClassLoader cl2, | |
| final Class<T> wrappedClass, | |
| Subject delegationSubject) | |
| throws IOException { | |
| if (mo == null) { | |
| return null; | |
| } | |
| try { | |
| ClassLoader orderCL = new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), | |
| new OrderClassLoaders(cl1, cl2)); | |
| return unwrap(mo, orderCL, wrappedClass,delegationSubject); | |
| } catch (Exception e) { | |
| 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; | |
| } | |
| 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 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 static final int | |
| ADD_NOTIFICATION_LISTENERS = 1; | |
| private static final int | |
| ADD_NOTIFICATION_LISTENER_OBJECTNAME = 2; | |
| private static final int | |
| CREATE_MBEAN = 3; | |
| private static final int | |
| CREATE_MBEAN_PARAMS = 4; | |
| private static final int | |
| CREATE_MBEAN_LOADER = 5; | |
| private static final int | |
| CREATE_MBEAN_LOADER_PARAMS = 6; | |
| private static final int | |
| GET_ATTRIBUTE = 7; | |
| private static final int | |
| GET_ATTRIBUTES = 8; | |
| private static final int | |
| GET_DEFAULT_DOMAIN = 9; | |
| private static final int | |
| GET_DOMAINS = 10; | |
| private static final int | |
| GET_MBEAN_COUNT = 11; | |
| private static final int | |
| GET_MBEAN_INFO = 12; | |
| private static final int | |
| GET_OBJECT_INSTANCE = 13; | |
| private static final int | |
| INVOKE = 14; | |
| private static final int | |
| IS_INSTANCE_OF = 15; | |
| private static final int | |
| IS_REGISTERED = 16; | |
| private static final int | |
| QUERY_MBEANS = 17; | |
| private static final int | |
| QUERY_NAMES = 18; | |
| private static final int | |
| REMOVE_NOTIFICATION_LISTENER = 19; | |
| private static final int | |
| REMOVE_NOTIFICATION_LISTENER_OBJECTNAME = 20; | |
| private static final int | |
| REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 21; | |
| private static final int | |
| SET_ATTRIBUTE = 22; | |
| private static final int | |
| SET_ATTRIBUTES = 23; | |
| private static final int | |
| UNREGISTER_MBEAN = 24; | |
| // SERVER NOTIFICATION | |
| //-------------------- | |
| private ServerNotifForwarder serverNotifForwarder; | |
| private Map<String, ?> 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 static final 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 { | |
| 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; | |
| } | |
| } | |
| } |