2576 lines · 101.7 KB · Java
RawDownload
/* * Copyright (c) 2002, 2010, 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 com.sun.jmx.mbeanserver.Util;import com.sun.jmx.remote.internal.ClientCommunicatorAdmin;import com.sun.jmx.remote.internal.ClientListenerInfo;import com.sun.jmx.remote.internal.ClientNotifForwarder;import com.sun.jmx.remote.internal.ProxyRef;import com.sun.jmx.remote.internal.IIOPHelper;import com.sun.jmx.remote.util.ClassLogger;import com.sun.jmx.remote.util.EnvHelp;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InvalidObjectException;import java.io.NotSerializableException;import java.io.ObjectInputStream;import java.io.ObjectStreamClass;import java.io.Serializable;import java.io.WriteAbortedException;import java.lang.ref.WeakReference;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Proxy;import java.net.MalformedURLException;import java.rmi.MarshalException;import java.rmi.MarshalledObject;import java.rmi.NoSuchObjectException;import java.rmi.Remote;import java.rmi.ServerException;import java.rmi.UnmarshalException;import java.rmi.server.RMIClientSocketFactory;import java.rmi.server.RemoteObject;import java.rmi.server.RemoteObjectInvocationHandler;import java.rmi.server.RemoteRef;import java.security.AccessController;import java.security.PrivilegedAction;import java.security.PrivilegedExceptionAction;import java.security.ProtectionDomain;import java.util.Arrays;import java.util.Collections;import java.util.HashMap;import java.util.Map;import java.util.Properties;import java.util.Set;import java.util.WeakHashMap;import javax.management.Attribute;import javax.management.AttributeList;import javax.management.AttributeNotFoundException;import javax.management.InstanceAlreadyExistsException;import javax.management.InstanceNotFoundException;import javax.management.IntrospectionException;import javax.management.InvalidAttributeValueException;import javax.management.ListenerNotFoundException;import javax.management.MBeanException;import javax.management.MBeanInfo;import javax.management.MBeanRegistrationException;import javax.management.MBeanServerConnection;import javax.management.MBeanServerDelegate;import javax.management.MBeanServerNotification;import javax.management.NotCompliantMBeanException;import javax.management.Notification;import javax.management.NotificationBroadcasterSupport;import javax.management.NotificationFilter;import javax.management.NotificationFilterSupport;import javax.management.NotificationListener;import javax.management.ObjectInstance;import javax.management.ObjectName;import javax.management.QueryExp;import javax.management.ReflectionException;import javax.management.remote.JMXConnectionNotification;import javax.management.remote.JMXConnector;import javax.management.remote.JMXConnectorFactory;import javax.management.remote.JMXServiceURL;import javax.management.remote.NotificationResult;import javax.management.remote.JMXAddressable;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.rmi.ssl.SslRMIClientSocketFactory;import javax.security.auth.Subject;import sun.rmi.server.UnicastRef2;import sun.rmi.transport.LiveRef; /** * <p>A connection to a remote RMI connector.  Usually, such * connections are made using {@link * javax.management.remote.JMXConnectorFactory JMXConnectorFactory}. * However, specialized applications can use this class directly, for * example with an {@link RMIServer} stub obtained without going * through JNDI.</p> * * @since 1.5 */public class RMIConnector implements JMXConnector, Serializable, JMXAddressable {     private static final ClassLogger logger =            new ClassLogger("javax.management.remote.rmi", "RMIConnector");     private static final long serialVersionUID = 817323035842634473L;     private RMIConnector(RMIServer rmiServer, JMXServiceURL address,            Map<String, ?> environment) {        if (rmiServer == null && address == null) throw new                IllegalArgumentException("rmiServer and jmxServiceURL both null");         initTransients();         this.rmiServer = rmiServer;        this.jmxServiceURL = address;        if (environment == null) {            this.env = Collections.emptyMap();        } else {            EnvHelp.checkAttributes(environment);            this.env = Collections.unmodifiableMap(environment);        }    }     /**     * <p>Constructs an <code>RMIConnector</code> that will connect     * the RMI connector server with the given address.</p>     *     * <p>The address can refer directly to the connector server,     * using one of the following syntaxes:</p>     *     * <pre>     * service:jmx:rmi://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>     * service:jmx:iiop://<em>[host[:port]]</em>/ior/<em>encoded-IOR</em>     * </pre>     *     * <p>(Here, the square brackets <code>[]</code> are not part of the     * address but indicate that the host and port are optional.)</p>     *     * <p>The address can instead indicate where to find an RMI stub     * through JNDI, using one of the following syntaxes:</p>     *     * <pre>     * service:jmx:rmi://<em>[host[:port]]</em>/jndi/<em>jndi-name</em>     * service:jmx:iiop://<em>[host[:port]]</em>/jndi/<em>jndi-name</em>     * </pre>     *     * <p>An implementation may also recognize additional address     * syntaxes, for example:</p>     *     * <pre>     * service:jmx:iiop://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>     * </pre>     *     * @param url the address of the RMI connector server.     *     * @param environment additional attributes specifying how to make     * the connection.  For JNDI-based addresses, these attributes can     * usefully include JNDI attributes recognized by {@link     * InitialContext#InitialContext(Hashtable) InitialContext}.  This     * parameter can be null, which is equivalent to an empty Map.     *     * @exception IllegalArgumentException if <code>url</code>     * is null.     */    public RMIConnector(JMXServiceURL url, Map<String,?> environment) {        this(null, url, environment);    }     /**     * <p>Constructs an <code>RMIConnector</code> using the given RMI stub.     *     * @param rmiServer an RMI stub representing the RMI connector server.     * @param environment additional attributes specifying how to make     * the connection.  This parameter can be null, which is     * equivalent to an empty Map.     *     * @exception IllegalArgumentException if <code>rmiServer</code>     * is null.     */    public RMIConnector(RMIServer rmiServer, Map<String,?> environment) {        this(rmiServer, null, environment);    }     /**     * <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() {        final StringBuilder b = new StringBuilder(this.getClass().getName());        b.append(":");        if (rmiServer != null) {            b.append(" rmiServer=").append(rmiServer.toString());        }        if (jmxServiceURL != null) {            if (rmiServer!=null) b.append(",");            b.append(" jmxServiceURL=").append(jmxServiceURL.toString());        }        return b.toString();    }     /**     * <p>The address of this connector.</p>     *     * @return the address of this connector, or null if it     * does not have one.     *     * @since 1.6     */    public JMXServiceURL getAddress() {        return jmxServiceURL;    }     //--------------------------------------------------------------------    // implements JMXConnector interface    //--------------------------------------------------------------------    public void connect() throws IOException {        connect(null);    }     public synchronized void connect(Map<String,?> environment)    throws IOException {        final boolean tracing = logger.traceOn();        String        idstr   = (tracing?"["+this.toString()+"]":null);         if (terminated) {            logger.trace("connect",idstr + " already closed.");            throw new IOException("Connector closed");        }        if (connected) {            logger.trace("connect",idstr + " already connected.");            return;        }         try {            if (tracing) logger.trace("connect",idstr + " connecting...");             final Map<String, Object> usemap =                    new HashMap<String, Object>((this.env==null) ?                        Collections.<String, Object>emptyMap() : this.env);              if (environment != null) {                EnvHelp.checkAttributes(environment);                usemap.putAll(environment);            }             // Get RMIServer stub from directory or URL encoding if needed.            if (tracing) logger.trace("connect",idstr + " finding stub...");            RMIServer stub = (rmiServer!=null)?rmiServer:                findRMIServer(jmxServiceURL, usemap);             // Check for secure RMIServer stub if the corresponding            // client-side environment property is set to "true".            //            boolean checkStub = EnvHelp.computeBooleanFromString(                    usemap,                    "jmx.remote.x.check.stub",false);            if (checkStub) checkStub(stub, rmiServerImplStubClass);             // Connect IIOP Stub if needed.            if (tracing) logger.trace("connect",idstr + " connecting stub...");            stub = connectStub(stub,usemap);            idstr = (tracing?"["+this.toString()+"]":null);             // Calling newClient on the RMIServer stub.            if (tracing)                logger.trace("connect",idstr + " getting connection...");            Object credentials = usemap.get(CREDENTIALS);             try {                connection = getConnection(stub, credentials, checkStub);            } catch (java.rmi.RemoteException re) {                if (jmxServiceURL != null) {                    final String pro = jmxServiceURL.getProtocol();                    final String path = jmxServiceURL.getURLPath();                     if ("rmi".equals(pro) &&                        path.startsWith("/jndi/iiop:")) {                        MalformedURLException mfe = new MalformedURLException(                              "Protocol is rmi but JNDI scheme is iiop: " + jmxServiceURL);                        mfe.initCause(re);                        throw mfe;                    }                }                throw re;            }             // Always use one of:            //   ClassLoader provided in Map at connect time,            //   or contextClassLoader at connect time.            if (tracing)                logger.trace("connect",idstr + " getting class loader...");            defaultClassLoader = EnvHelp.resolveClientClassLoader(usemap);             usemap.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,                    defaultClassLoader);             rmiNotifClient = new RMINotifClient(defaultClassLoader, usemap);             env = usemap;            final long checkPeriod = EnvHelp.getConnectionCheckPeriod(usemap);            communicatorAdmin = new RMIClientCommunicatorAdmin(checkPeriod);             connected = true;             // The connectionId variable is used in doStart(), when            // reconnecting, to identify the "old" connection.            //            connectionId = getConnectionId();             Notification connectedNotif =                    new JMXConnectionNotification(JMXConnectionNotification.OPENED,                    this,                    connectionId,                    clientNotifSeqNo++,                    "Successful connection",                    null);            sendNotification(connectedNotif);             if (tracing) logger.trace("connect",idstr + " done...");        } catch (IOException e) {            if (tracing)                logger.trace("connect",idstr + " failed to connect: " + e);            throw e;        } catch (RuntimeException e) {            if (tracing)                logger.trace("connect",idstr + " failed to connect: " + e);            throw e;        } catch (NamingException e) {            final String msg = "Failed to retrieve RMIServer stub: " + e;            if (tracing) logger.trace("connect",idstr + " " + msg);            throw EnvHelp.initCause(new IOException(msg),e);        }    }     public synchronized String getConnectionId() throws IOException {        if (terminated || !connected) {            if (logger.traceOn())                logger.trace("getConnectionId","["+this.toString()+                        "] not connected.");             throw new IOException("Not connected");        }         // we do a remote call to have an IOException if the connection is broken.        // see the bug 4939578        return connection.getConnectionId();    }     public synchronized MBeanServerConnection getMBeanServerConnection()    throws IOException {        return getMBeanServerConnection(null);    }     public synchronized MBeanServerConnection            getMBeanServerConnection(Subject delegationSubject)            throws IOException {         if (terminated) {            if (logger.traceOn())                logger.trace("getMBeanServerConnection","[" + this.toString() +                        "] already closed.");            throw new IOException("Connection closed");        } else if (!connected) {            if (logger.traceOn())                logger.trace("getMBeanServerConnection","[" + this.toString() +                        "] is not connected.");            throw new IOException("Not connected");        }         MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject);        if (rmbsc != null) {            return rmbsc;        }         rmbsc = new RemoteMBeanServerConnection(delegationSubject);        rmbscMap.put(delegationSubject, rmbsc);        return rmbsc;    }     public void            addConnectionNotificationListener(NotificationListener listener,            NotificationFilter filter,            Object handback) {        if (listener == null)            throw new NullPointerException("listener");        connectionBroadcaster.addNotificationListener(listener, filter,                handback);    }     public void            removeConnectionNotificationListener(NotificationListener listener)            throws ListenerNotFoundException {        if (listener == null)            throw new NullPointerException("listener");        connectionBroadcaster.removeNotificationListener(listener);    }     public void            removeConnectionNotificationListener(NotificationListener listener,            NotificationFilter filter,            Object handback)            throws ListenerNotFoundException {        if (listener == null)            throw new NullPointerException("listener");        connectionBroadcaster.removeNotificationListener(listener, filter,                handback);    }     private void sendNotification(Notification n) {        connectionBroadcaster.sendNotification(n);    }     public synchronized void close() throws IOException {        close(false);    }     // allows to do close after setting the flag "terminated" to true.    // It is necessary to avoid a deadlock, see 6296324    private synchronized void close(boolean intern) throws IOException {        final boolean tracing = logger.traceOn();        final boolean debug   = logger.debugOn();        final String  idstr   = (tracing?"["+this.toString()+"]":null);         if (!intern) {            // Return if already cleanly closed.            //            if (terminated) {                if (closeException == null) {                    if (tracing) logger.trace("close",idstr + " already closed.");                    return;                }            } else {                terminated = true;            }        }         if (closeException != null && tracing) {            // Already closed, but not cleanly. Attempt again.            //            if (tracing) {                logger.trace("close",idstr + " had failed: " + closeException);                logger.trace("close",idstr + " attempting to close again.");            }        }         String savedConnectionId = null;        if (connected) {            savedConnectionId = connectionId;        }         closeException = null;         if (tracing) logger.trace("close",idstr + " closing.");         if (communicatorAdmin != null) {            communicatorAdmin.terminate();        }         if (rmiNotifClient != null) {            try {                rmiNotifClient.terminate();                if (tracing) logger.trace("close",idstr +                        " RMI Notification client terminated.");            } catch (RuntimeException x) {                closeException = x;                if (tracing) logger.trace("close",idstr +                        " Failed to terminate RMI Notification client: " + x);                if (debug) logger.debug("close",x);            }        }         if (connection != null) {            try {                connection.close();

Lines 1–500 of 2576.