jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java
changeset 43503 bc7f8619ab70
parent 40742 3697a4ff4721
child 43712 5dfd0950317c
equal deleted inserted replaced
43502:aec39566b45e 43503:bc7f8619ab70
       
     1 /*
       
     2  * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package javax.management.remote.rmi;
       
    27 
       
    28 import com.sun.jmx.remote.internal.ClientCommunicatorAdmin;
       
    29 import com.sun.jmx.remote.internal.ClientListenerInfo;
       
    30 import com.sun.jmx.remote.internal.ClientNotifForwarder;
       
    31 import com.sun.jmx.remote.internal.rmi.ProxyRef;
       
    32 import com.sun.jmx.remote.util.ClassLogger;
       
    33 import com.sun.jmx.remote.util.EnvHelp;
       
    34 import java.io.ByteArrayInputStream;
       
    35 import java.io.IOException;
       
    36 import java.io.InputStream;
       
    37 import java.io.InvalidObjectException;
       
    38 import java.io.ObjectInputStream;
       
    39 import java.io.ObjectStreamClass;
       
    40 import java.io.Serializable;
       
    41 import java.lang.ref.WeakReference;
       
    42 import java.lang.reflect.Constructor;
       
    43 import java.lang.reflect.InvocationHandler;
       
    44 import java.lang.reflect.InvocationTargetException;
       
    45 import java.lang.reflect.Module;
       
    46 import java.lang.reflect.Proxy;
       
    47 import java.net.MalformedURLException;
       
    48 import java.rmi.MarshalledObject;
       
    49 import java.rmi.NoSuchObjectException;
       
    50 import java.rmi.Remote;
       
    51 import java.rmi.ServerException;
       
    52 import java.rmi.UnmarshalException;
       
    53 import java.rmi.server.RMIClientSocketFactory;
       
    54 import java.rmi.server.RemoteObject;
       
    55 import java.rmi.server.RemoteObjectInvocationHandler;
       
    56 import java.rmi.server.RemoteRef;
       
    57 import java.security.AccessController;
       
    58 import java.security.PrivilegedAction;
       
    59 import java.security.PrivilegedExceptionAction;
       
    60 import java.security.ProtectionDomain;
       
    61 import java.util.Arrays;
       
    62 import java.util.Collections;
       
    63 import java.util.HashMap;
       
    64 import java.util.Hashtable;
       
    65 import java.util.Map;
       
    66 import java.util.Objects;
       
    67 import java.util.Set;
       
    68 import java.util.WeakHashMap;
       
    69 import java.util.stream.Collectors;
       
    70 import javax.management.Attribute;
       
    71 import javax.management.AttributeList;
       
    72 import javax.management.AttributeNotFoundException;
       
    73 import javax.management.InstanceAlreadyExistsException;
       
    74 import javax.management.InstanceNotFoundException;
       
    75 import javax.management.IntrospectionException;
       
    76 import javax.management.InvalidAttributeValueException;
       
    77 import javax.management.ListenerNotFoundException;
       
    78 import javax.management.MBeanException;
       
    79 import javax.management.MBeanInfo;
       
    80 import javax.management.MBeanRegistrationException;
       
    81 import javax.management.MBeanServerConnection;
       
    82 import javax.management.MBeanServerDelegate;
       
    83 import javax.management.MBeanServerNotification;
       
    84 import javax.management.NotCompliantMBeanException;
       
    85 import javax.management.Notification;
       
    86 import javax.management.NotificationBroadcasterSupport;
       
    87 import javax.management.NotificationFilter;
       
    88 import javax.management.NotificationFilterSupport;
       
    89 import javax.management.NotificationListener;
       
    90 import javax.management.ObjectInstance;
       
    91 import javax.management.ObjectName;
       
    92 import javax.management.QueryExp;
       
    93 import javax.management.ReflectionException;
       
    94 import javax.management.remote.JMXConnectionNotification;
       
    95 import javax.management.remote.JMXConnector;
       
    96 import javax.management.remote.JMXConnectorFactory;
       
    97 import javax.management.remote.JMXServiceURL;
       
    98 import javax.management.remote.NotificationResult;
       
    99 import javax.management.remote.JMXAddressable;
       
   100 import javax.naming.InitialContext;
       
   101 import javax.naming.NamingException;
       
   102 import javax.rmi.ssl.SslRMIClientSocketFactory;
       
   103 import javax.security.auth.Subject;
       
   104 import jdk.internal.module.Modules;
       
   105 import sun.reflect.misc.ReflectUtil;
       
   106 import sun.rmi.server.UnicastRef2;
       
   107 import sun.rmi.transport.LiveRef;
       
   108 import java.io.NotSerializableException;
       
   109 
       
   110 /**
       
   111  * <p>A connection to a remote RMI connector.  Usually, such
       
   112  * connections are made using {@link
       
   113  * javax.management.remote.JMXConnectorFactory JMXConnectorFactory}.
       
   114  * However, specialized applications can use this class directly, for
       
   115  * example with an {@link RMIServer} stub obtained without going
       
   116  * through JNDI.</p>
       
   117  *
       
   118  * @since 1.5
       
   119  */
       
   120 public class RMIConnector implements JMXConnector, Serializable, JMXAddressable {
       
   121 
       
   122     private static final ClassLogger logger =
       
   123             new ClassLogger("javax.management.remote.rmi", "RMIConnector");
       
   124 
       
   125     private static final long serialVersionUID = 817323035842634473L;
       
   126 
       
   127     static final class Util {
       
   128         private Util() {}
       
   129 
       
   130         /* This method can be used by code that is deliberately violating the
       
   131          * allowed checked casts.  Rather than marking the whole method containing
       
   132          * the code with @SuppressWarnings, you can use a call to this method for
       
   133          * the exact place where you need to escape the constraints.  Typically
       
   134          * you will "import static" this method and then write either
       
   135          *    X x = cast(y);
       
   136          * or, if that doesn't work (e.g. X is a type variable)
       
   137          *    Util.<X>cast(y);
       
   138          */
       
   139         @SuppressWarnings("unchecked")
       
   140         public static <T> T cast(Object x) {
       
   141             return (T) x;
       
   142         }
       
   143     }
       
   144 
       
   145     private RMIConnector(RMIServer rmiServer, JMXServiceURL address,
       
   146             Map<String, ?> environment) {
       
   147         if (rmiServer == null && address == null) throw new
       
   148                 IllegalArgumentException("rmiServer and jmxServiceURL both null");
       
   149         initTransients();
       
   150 
       
   151         this.rmiServer = rmiServer;
       
   152         this.jmxServiceURL = address;
       
   153         if (environment == null) {
       
   154             this.env = Collections.emptyMap();
       
   155         } else {
       
   156             EnvHelp.checkAttributes(environment);
       
   157             this.env = Collections.unmodifiableMap(environment);
       
   158         }
       
   159     }
       
   160 
       
   161     /**
       
   162      * <p>Constructs an {@code RMIConnector} that will connect
       
   163      * the RMI connector server with the given address.</p>
       
   164      *
       
   165      * <p>The address can refer directly to the connector server,
       
   166      * using the following syntax:</p>
       
   167      *
       
   168      * <pre>
       
   169      * service:jmx:rmi://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>
       
   170      * </pre>
       
   171      *
       
   172      * <p>(Here, the square brackets {@code []} are not part of the
       
   173      * address but indicate that the host and port are optional.)</p>
       
   174      *
       
   175      * <p>The address can instead indicate where to find an RMI stub
       
   176      * through JNDI, using the following syntax:</p>
       
   177      *
       
   178      * <pre>
       
   179      * service:jmx:rmi://<em>[host[:port]]</em>/jndi/<em>jndi-name</em>
       
   180      * </pre>
       
   181      *
       
   182      * <p>An implementation may also recognize additional address
       
   183      * syntaxes, for example:</p>
       
   184      *
       
   185      * <pre>
       
   186      * service:jmx:iiop://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>
       
   187      * </pre>
       
   188      *
       
   189      * @param url the address of the RMI connector server.
       
   190      *
       
   191      * @param environment additional attributes specifying how to make
       
   192      * the connection.  For JNDI-based addresses, these attributes can
       
   193      * usefully include JNDI attributes recognized by {@link
       
   194      * InitialContext#InitialContext(Hashtable) InitialContext}.  This
       
   195      * parameter can be null, which is equivalent to an empty Map.
       
   196      *
       
   197      * @exception IllegalArgumentException if {@code url}
       
   198      * is null.
       
   199      */
       
   200     public RMIConnector(JMXServiceURL url, Map<String,?> environment) {
       
   201         this(null, url, environment);
       
   202     }
       
   203 
       
   204     /**
       
   205      * <p>Constructs an {@code RMIConnector} using the given RMI stub.
       
   206      *
       
   207      * @param rmiServer an RMI stub representing the RMI connector server.
       
   208      * @param environment additional attributes specifying how to make
       
   209      * the connection.  This parameter can be null, which is
       
   210      * equivalent to an empty Map.
       
   211      *
       
   212      * @exception IllegalArgumentException if {@code rmiServer}
       
   213      * is null.
       
   214      */
       
   215     public RMIConnector(RMIServer rmiServer, Map<String,?> environment) {
       
   216         this(rmiServer, null, environment);
       
   217     }
       
   218 
       
   219     /**
       
   220      * <p>Returns a string representation of this object.  In general,
       
   221      * the {@code toString} method returns a string that
       
   222      * "textually represents" this object. The result should be a
       
   223      * concise but informative representation that is easy for a
       
   224      * person to read.</p>
       
   225      *
       
   226      * @return a String representation of this object.
       
   227      **/
       
   228     @Override
       
   229     public String toString() {
       
   230         final StringBuilder b = new StringBuilder(this.getClass().getName());
       
   231         b.append(":");
       
   232         if (rmiServer != null) {
       
   233             b.append(" rmiServer=").append(rmiServer.toString());
       
   234         }
       
   235         if (jmxServiceURL != null) {
       
   236             if (rmiServer!=null) b.append(",");
       
   237             b.append(" jmxServiceURL=").append(jmxServiceURL.toString());
       
   238         }
       
   239         return b.toString();
       
   240     }
       
   241 
       
   242     /**
       
   243      * <p>The address of this connector.</p>
       
   244      *
       
   245      * @return the address of this connector, or null if it
       
   246      * does not have one.
       
   247      *
       
   248      * @since 1.6
       
   249      */
       
   250     public JMXServiceURL getAddress() {
       
   251         return jmxServiceURL;
       
   252     }
       
   253 
       
   254     //--------------------------------------------------------------------
       
   255     // implements JMXConnector interface
       
   256     //--------------------------------------------------------------------
       
   257 
       
   258     /**
       
   259      * @throws IOException if the connection could not be made because of a
       
   260      *   communication problem
       
   261      */
       
   262     public void connect() throws IOException {
       
   263         connect(null);
       
   264     }
       
   265 
       
   266     /**
       
   267      * @throws IOException if the connection could not be made because of a
       
   268      *   communication problem
       
   269      */
       
   270     public synchronized void connect(Map<String,?> environment)
       
   271     throws IOException {
       
   272         final boolean tracing = logger.traceOn();
       
   273         String        idstr   = (tracing?"["+this.toString()+"]":null);
       
   274 
       
   275         if (terminated) {
       
   276             logger.trace("connect",idstr + " already closed.");
       
   277             throw new IOException("Connector closed");
       
   278         }
       
   279         if (connected) {
       
   280             logger.trace("connect",idstr + " already connected.");
       
   281             return;
       
   282         }
       
   283 
       
   284         try {
       
   285             if (tracing) logger.trace("connect",idstr + " connecting...");
       
   286 
       
   287             final Map<String, Object> usemap =
       
   288                     new HashMap<String, Object>((this.env==null) ?
       
   289                         Collections.<String, Object>emptyMap() : this.env);
       
   290 
       
   291 
       
   292             if (environment != null) {
       
   293                 EnvHelp.checkAttributes(environment);
       
   294                 usemap.putAll(environment);
       
   295             }
       
   296 
       
   297             // Get RMIServer stub from directory or URL encoding if needed.
       
   298             if (tracing) logger.trace("connect",idstr + " finding stub...");
       
   299             RMIServer stub = (rmiServer!=null)?rmiServer:
       
   300                 findRMIServer(jmxServiceURL, usemap);
       
   301 
       
   302             // Check for secure RMIServer stub if the corresponding
       
   303             // client-side environment property is set to "true".
       
   304             //
       
   305             String stringBoolean =  (String) usemap.get("jmx.remote.x.check.stub");
       
   306             boolean checkStub = EnvHelp.computeBooleanFromString(stringBoolean);
       
   307 
       
   308             if (checkStub) checkStub(stub, rmiServerImplStubClass);
       
   309 
       
   310             if (tracing) logger.trace("connect",idstr + " connecting stub...");
       
   311             idstr = (tracing?"["+this.toString()+"]":null);
       
   312 
       
   313             // Calling newClient on the RMIServer stub.
       
   314             if (tracing)
       
   315                 logger.trace("connect",idstr + " getting connection...");
       
   316             Object credentials = usemap.get(CREDENTIALS);
       
   317 
       
   318             try {
       
   319                 connection = getConnection(stub, credentials, checkStub);
       
   320             } catch (java.rmi.RemoteException re) {
       
   321                 throw re;
       
   322             }
       
   323 
       
   324             // Always use one of:
       
   325             //   ClassLoader provided in Map at connect time,
       
   326             //   or contextClassLoader at connect time.
       
   327             if (tracing)
       
   328                 logger.trace("connect",idstr + " getting class loader...");
       
   329             defaultClassLoader = EnvHelp.resolveClientClassLoader(usemap);
       
   330 
       
   331             usemap.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,
       
   332                     defaultClassLoader);
       
   333 
       
   334             rmiNotifClient = new RMINotifClient(defaultClassLoader, usemap);
       
   335 
       
   336             env = usemap;
       
   337             final long checkPeriod = EnvHelp.getConnectionCheckPeriod(usemap);
       
   338             communicatorAdmin = new RMIClientCommunicatorAdmin(checkPeriod);
       
   339 
       
   340             connected = true;
       
   341 
       
   342             // The connectionId variable is used in doStart(), when
       
   343             // reconnecting, to identify the "old" connection.
       
   344             //
       
   345             connectionId = getConnectionId();
       
   346 
       
   347             Notification connectedNotif =
       
   348                     new JMXConnectionNotification(JMXConnectionNotification.OPENED,
       
   349                     this,
       
   350                     connectionId,
       
   351                     clientNotifSeqNo++,
       
   352                     "Successful connection",
       
   353                     null);
       
   354             sendNotification(connectedNotif);
       
   355 
       
   356             if (tracing) logger.trace("connect",idstr + " done...");
       
   357         } catch (IOException e) {
       
   358             if (tracing)
       
   359                 logger.trace("connect",idstr + " failed to connect: " + e);
       
   360             throw e;
       
   361         } catch (RuntimeException e) {
       
   362             if (tracing)
       
   363                 logger.trace("connect",idstr + " failed to connect: " + e);
       
   364             throw e;
       
   365         } catch (NamingException e) {
       
   366             final String msg = "Failed to retrieve RMIServer stub: " + e;
       
   367             if (tracing) logger.trace("connect",idstr + " " + msg);
       
   368             throw EnvHelp.initCause(new IOException(msg),e);
       
   369         }
       
   370     }
       
   371 
       
   372     public synchronized String getConnectionId() throws IOException {
       
   373         if (terminated || !connected) {
       
   374             if (logger.traceOn())
       
   375                 logger.trace("getConnectionId","["+this.toString()+
       
   376                         "] not connected.");
       
   377 
       
   378             throw new IOException("Not connected");
       
   379         }
       
   380 
       
   381         // we do a remote call to have an IOException if the connection is broken.
       
   382         // see the bug 4939578
       
   383         return connection.getConnectionId();
       
   384     }
       
   385 
       
   386     public synchronized MBeanServerConnection getMBeanServerConnection()
       
   387     throws IOException {
       
   388         return getMBeanServerConnection(null);
       
   389     }
       
   390 
       
   391     public synchronized MBeanServerConnection
       
   392             getMBeanServerConnection(Subject delegationSubject)
       
   393             throws IOException {
       
   394 
       
   395         if (terminated) {
       
   396             if (logger.traceOn())
       
   397                 logger.trace("getMBeanServerConnection","[" + this.toString() +
       
   398                         "] already closed.");
       
   399             throw new IOException("Connection closed");
       
   400         } else if (!connected) {
       
   401             if (logger.traceOn())
       
   402                 logger.trace("getMBeanServerConnection","[" + this.toString() +
       
   403                         "] is not connected.");
       
   404             throw new IOException("Not connected");
       
   405         }
       
   406 
       
   407         return getConnectionWithSubject(delegationSubject);
       
   408     }
       
   409 
       
   410     public void
       
   411             addConnectionNotificationListener(NotificationListener listener,
       
   412             NotificationFilter filter,
       
   413             Object handback) {
       
   414         if (listener == null)
       
   415             throw new NullPointerException("listener");
       
   416         connectionBroadcaster.addNotificationListener(listener, filter,
       
   417                 handback);
       
   418     }
       
   419 
       
   420     public void
       
   421             removeConnectionNotificationListener(NotificationListener listener)
       
   422             throws ListenerNotFoundException {
       
   423         if (listener == null)
       
   424             throw new NullPointerException("listener");
       
   425         connectionBroadcaster.removeNotificationListener(listener);
       
   426     }
       
   427 
       
   428     public void
       
   429             removeConnectionNotificationListener(NotificationListener listener,
       
   430             NotificationFilter filter,
       
   431             Object handback)
       
   432             throws ListenerNotFoundException {
       
   433         if (listener == null)
       
   434             throw new NullPointerException("listener");
       
   435         connectionBroadcaster.removeNotificationListener(listener, filter,
       
   436                 handback);
       
   437     }
       
   438 
       
   439     private void sendNotification(Notification n) {
       
   440         connectionBroadcaster.sendNotification(n);
       
   441     }
       
   442 
       
   443     public synchronized void close() throws IOException {
       
   444         close(false);
       
   445     }
       
   446 
       
   447     // allows to do close after setting the flag "terminated" to true.
       
   448     // It is necessary to avoid a deadlock, see 6296324
       
   449     private synchronized void close(boolean intern) throws IOException {
       
   450         final boolean tracing = logger.traceOn();
       
   451         final boolean debug   = logger.debugOn();
       
   452         final String  idstr   = (tracing?"["+this.toString()+"]":null);
       
   453 
       
   454         if (!intern) {
       
   455             // Return if already cleanly closed.
       
   456             //
       
   457             if (terminated) {
       
   458                 if (closeException == null) {
       
   459                     if (tracing) logger.trace("close",idstr + " already closed.");
       
   460                     return;
       
   461                 }
       
   462             } else {
       
   463                 terminated = true;
       
   464             }
       
   465         }
       
   466 
       
   467         if (closeException != null && tracing) {
       
   468             // Already closed, but not cleanly. Attempt again.
       
   469             //
       
   470             if (tracing) {
       
   471                 logger.trace("close",idstr + " had failed: " + closeException);
       
   472                 logger.trace("close",idstr + " attempting to close again.");
       
   473             }
       
   474         }
       
   475 
       
   476         String savedConnectionId = null;
       
   477         if (connected) {
       
   478             savedConnectionId = connectionId;
       
   479         }
       
   480 
       
   481         closeException = null;
       
   482 
       
   483         if (tracing) logger.trace("close",idstr + " closing.");
       
   484 
       
   485         if (communicatorAdmin != null) {
       
   486             communicatorAdmin.terminate();
       
   487         }
       
   488 
       
   489         if (rmiNotifClient != null) {
       
   490             try {
       
   491                 rmiNotifClient.terminate();
       
   492                 if (tracing) logger.trace("close",idstr +
       
   493                         " RMI Notification client terminated.");
       
   494             } catch (RuntimeException x) {
       
   495                 closeException = x;
       
   496                 if (tracing) logger.trace("close",idstr +
       
   497                         " Failed to terminate RMI Notification client: " + x);
       
   498                 if (debug) logger.debug("close",x);
       
   499             }
       
   500         }
       
   501 
       
   502         if (connection != null) {
       
   503             try {
       
   504                 connection.close();
       
   505                 if (tracing) logger.trace("close",idstr + " closed.");
       
   506             } catch (NoSuchObjectException nse) {
       
   507                 // OK, the server maybe closed itself.
       
   508             } catch (IOException e) {
       
   509                 closeException = e;
       
   510                 if (tracing) logger.trace("close",idstr +
       
   511                         " Failed to close RMIServer: " + e);
       
   512                 if (debug) logger.debug("close",e);
       
   513             }
       
   514         }
       
   515 
       
   516         // Clean up MBeanServerConnection table
       
   517         //
       
   518         rmbscMap.clear();
       
   519 
       
   520         /* Send notification of closure.  We don't do this if the user
       
   521          * never called connect() on the connector, because there's no
       
   522          * connection id in that case.  */
       
   523 
       
   524         if (savedConnectionId != null) {
       
   525             Notification closedNotif =
       
   526                     new JMXConnectionNotification(JMXConnectionNotification.CLOSED,
       
   527                     this,
       
   528                     savedConnectionId,
       
   529                     clientNotifSeqNo++,
       
   530                     "Client has been closed",
       
   531                     null);
       
   532             sendNotification(closedNotif);
       
   533         }
       
   534 
       
   535         // throw exception if needed
       
   536         //
       
   537         if (closeException != null) {
       
   538             if (tracing) logger.trace("close",idstr + " failed to close: " +
       
   539                     closeException);
       
   540             if (closeException instanceof IOException)
       
   541                 throw (IOException) closeException;
       
   542             if (closeException instanceof RuntimeException)
       
   543                 throw (RuntimeException) closeException;
       
   544             final IOException x =
       
   545                     new IOException("Failed to close: " + closeException);
       
   546             throw EnvHelp.initCause(x,closeException);
       
   547         }
       
   548     }
       
   549 
       
   550     // added for re-connection
       
   551     private Integer addListenerWithSubject(ObjectName name,
       
   552                                            MarshalledObject<NotificationFilter> filter,
       
   553                                            Subject delegationSubject,
       
   554                                            boolean reconnect)
       
   555         throws InstanceNotFoundException, IOException {
       
   556 
       
   557         final boolean debug = logger.debugOn();
       
   558         if (debug)
       
   559             logger.debug("addListenerWithSubject",
       
   560                     "(ObjectName,MarshalledObject,Subject)");
       
   561 
       
   562         final ObjectName[] names = new ObjectName[] {name};
       
   563         final MarshalledObject<NotificationFilter>[] filters =
       
   564                 Util.cast(new MarshalledObject<?>[] {filter});
       
   565         final Subject[] delegationSubjects = new Subject[] {
       
   566             delegationSubject
       
   567         };
       
   568 
       
   569         final Integer[] listenerIDs =
       
   570                 addListenersWithSubjects(names,filters,delegationSubjects,
       
   571                 reconnect);
       
   572 
       
   573         if (debug) logger.debug("addListenerWithSubject","listenerID="
       
   574                 + listenerIDs[0]);
       
   575         return listenerIDs[0];
       
   576     }
       
   577 
       
   578     // added for re-connection
       
   579     private Integer[] addListenersWithSubjects(ObjectName[]       names,
       
   580                              MarshalledObject<NotificationFilter>[] filters,
       
   581                              Subject[]          delegationSubjects,
       
   582                              boolean            reconnect)
       
   583         throws InstanceNotFoundException, IOException {
       
   584 
       
   585         final boolean debug = logger.debugOn();
       
   586         if (debug)
       
   587             logger.debug("addListenersWithSubjects",
       
   588                     "(ObjectName[],MarshalledObject[],Subject[])");
       
   589 
       
   590         final ClassLoader old = pushDefaultClassLoader();
       
   591         Integer[] listenerIDs = null;
       
   592 
       
   593         try {
       
   594             listenerIDs = connection.addNotificationListeners(names,
       
   595                     filters,
       
   596                     delegationSubjects);
       
   597         } catch (NoSuchObjectException noe) {
       
   598             // maybe reconnect
       
   599             if (reconnect) {
       
   600                 communicatorAdmin.gotIOException(noe);
       
   601 
       
   602                 listenerIDs = connection.addNotificationListeners(names,
       
   603                         filters,
       
   604                         delegationSubjects);
       
   605             } else {
       
   606                 throw noe;
       
   607             }
       
   608         } catch (IOException ioe) {
       
   609             // send a failed notif if necessary
       
   610             communicatorAdmin.gotIOException(ioe);
       
   611         } finally {
       
   612             popDefaultClassLoader(old);
       
   613         }
       
   614 
       
   615         if (debug) logger.debug("addListenersWithSubjects","registered "
       
   616                 + ((listenerIDs==null)?0:listenerIDs.length)
       
   617                 + " listener(s)");
       
   618         return listenerIDs;
       
   619     }
       
   620 
       
   621     //--------------------------------------------------------------------
       
   622     // Implementation of MBeanServerConnection
       
   623     //--------------------------------------------------------------------
       
   624     private class RemoteMBeanServerConnection implements MBeanServerConnection {
       
   625         private Subject delegationSubject;
       
   626 
       
   627         public RemoteMBeanServerConnection() {
       
   628             this(null);
       
   629         }
       
   630 
       
   631         public RemoteMBeanServerConnection(Subject delegationSubject) {
       
   632             this.delegationSubject = delegationSubject;
       
   633         }
       
   634 
       
   635         public ObjectInstance createMBean(String className,
       
   636                 ObjectName name)
       
   637                 throws ReflectionException,
       
   638                 InstanceAlreadyExistsException,
       
   639                 MBeanRegistrationException,
       
   640                 MBeanException,
       
   641                 NotCompliantMBeanException,
       
   642                 IOException {
       
   643             if (logger.debugOn())
       
   644                 logger.debug("createMBean(String,ObjectName)",
       
   645                         "className=" + className + ", name=" +
       
   646                         name);
       
   647 
       
   648             final ClassLoader old = pushDefaultClassLoader();
       
   649             try {
       
   650                 return connection.createMBean(className,
       
   651                         name,
       
   652                         delegationSubject);
       
   653             } catch (IOException ioe) {
       
   654                 communicatorAdmin.gotIOException(ioe);
       
   655 
       
   656                 return connection.createMBean(className,
       
   657                         name,
       
   658                         delegationSubject);
       
   659             } finally {
       
   660                 popDefaultClassLoader(old);
       
   661             }
       
   662         }
       
   663 
       
   664         public ObjectInstance createMBean(String className,
       
   665                 ObjectName name,
       
   666                 ObjectName loaderName)
       
   667                 throws ReflectionException,
       
   668                 InstanceAlreadyExistsException,
       
   669                 MBeanRegistrationException,
       
   670                 MBeanException,
       
   671                 NotCompliantMBeanException,
       
   672                 InstanceNotFoundException,
       
   673                 IOException {
       
   674 
       
   675             if (logger.debugOn())
       
   676                 logger.debug("createMBean(String,ObjectName,ObjectName)",
       
   677                         "className=" + className + ", name="
       
   678                         + name + ", loaderName="
       
   679                         + loaderName + ")");
       
   680 
       
   681             final ClassLoader old = pushDefaultClassLoader();
       
   682             try {
       
   683                 return connection.createMBean(className,
       
   684                         name,
       
   685                         loaderName,
       
   686                         delegationSubject);
       
   687 
       
   688             } catch (IOException ioe) {
       
   689                 communicatorAdmin.gotIOException(ioe);
       
   690 
       
   691                 return connection.createMBean(className,
       
   692                         name,
       
   693                         loaderName,
       
   694                         delegationSubject);
       
   695 
       
   696             } finally {
       
   697                 popDefaultClassLoader(old);
       
   698             }
       
   699         }
       
   700 
       
   701         public ObjectInstance createMBean(String className,
       
   702                 ObjectName name,
       
   703                 Object params[],
       
   704                 String signature[])
       
   705                 throws ReflectionException,
       
   706                 InstanceAlreadyExistsException,
       
   707                 MBeanRegistrationException,
       
   708                 MBeanException,
       
   709                 NotCompliantMBeanException,
       
   710                 IOException {
       
   711             if (logger.debugOn())
       
   712                 logger.debug("createMBean(String,ObjectName,Object[],String[])",
       
   713                         "className=" + className + ", name="
       
   714                         + name + ", signature=" + strings(signature));
       
   715 
       
   716             final MarshalledObject<Object[]> sParams =
       
   717                     new MarshalledObject<Object[]>(params);
       
   718             final ClassLoader old = pushDefaultClassLoader();
       
   719             try {
       
   720                 return connection.createMBean(className,
       
   721                         name,
       
   722                         sParams,
       
   723                         signature,
       
   724                         delegationSubject);
       
   725             } catch (IOException ioe) {
       
   726                 communicatorAdmin.gotIOException(ioe);
       
   727 
       
   728                 return connection.createMBean(className,
       
   729                         name,
       
   730                         sParams,
       
   731                         signature,
       
   732                         delegationSubject);
       
   733             } finally {
       
   734                 popDefaultClassLoader(old);
       
   735             }
       
   736         }
       
   737 
       
   738         public ObjectInstance createMBean(String className,
       
   739                 ObjectName name,
       
   740                 ObjectName loaderName,
       
   741                 Object params[],
       
   742                 String signature[])
       
   743                 throws ReflectionException,
       
   744                 InstanceAlreadyExistsException,
       
   745                 MBeanRegistrationException,
       
   746                 MBeanException,
       
   747                 NotCompliantMBeanException,
       
   748                 InstanceNotFoundException,
       
   749                 IOException {
       
   750             if (logger.debugOn()) logger.debug(
       
   751                     "createMBean(String,ObjectName,ObjectName,Object[],String[])",
       
   752                     "className=" + className + ", name=" + name + ", loaderName="
       
   753                     + loaderName + ", signature=" + strings(signature));
       
   754 
       
   755             final MarshalledObject<Object[]> sParams =
       
   756                     new MarshalledObject<Object[]>(params);
       
   757             final ClassLoader old = pushDefaultClassLoader();
       
   758             try {
       
   759                 return connection.createMBean(className,
       
   760                         name,
       
   761                         loaderName,
       
   762                         sParams,
       
   763                         signature,
       
   764                         delegationSubject);
       
   765             } catch (IOException ioe) {
       
   766                 communicatorAdmin.gotIOException(ioe);
       
   767 
       
   768                 return connection.createMBean(className,
       
   769                         name,
       
   770                         loaderName,
       
   771                         sParams,
       
   772                         signature,
       
   773                         delegationSubject);
       
   774             } finally {
       
   775                 popDefaultClassLoader(old);
       
   776             }
       
   777         }
       
   778 
       
   779         public void unregisterMBean(ObjectName name)
       
   780         throws InstanceNotFoundException,
       
   781                 MBeanRegistrationException,
       
   782                 IOException {
       
   783             if (logger.debugOn())
       
   784                 logger.debug("unregisterMBean", "name=" + name);
       
   785 
       
   786             final ClassLoader old = pushDefaultClassLoader();
       
   787             try {
       
   788                 connection.unregisterMBean(name, delegationSubject);
       
   789             } catch (IOException ioe) {
       
   790                 communicatorAdmin.gotIOException(ioe);
       
   791 
       
   792                 connection.unregisterMBean(name, delegationSubject);
       
   793             } finally {
       
   794                 popDefaultClassLoader(old);
       
   795             }
       
   796         }
       
   797 
       
   798         public ObjectInstance getObjectInstance(ObjectName name)
       
   799         throws InstanceNotFoundException,
       
   800                 IOException {
       
   801             if (logger.debugOn())
       
   802                 logger.debug("getObjectInstance", "name=" + name);
       
   803 
       
   804             final ClassLoader old = pushDefaultClassLoader();
       
   805             try {
       
   806                 return connection.getObjectInstance(name, delegationSubject);
       
   807             } catch (IOException ioe) {
       
   808                 communicatorAdmin.gotIOException(ioe);
       
   809 
       
   810                 return connection.getObjectInstance(name, delegationSubject);
       
   811             } finally {
       
   812                 popDefaultClassLoader(old);
       
   813             }
       
   814         }
       
   815 
       
   816         public Set<ObjectInstance> queryMBeans(ObjectName name,
       
   817                 QueryExp query)
       
   818                 throws IOException {
       
   819             if (logger.debugOn()) logger.debug("queryMBeans",
       
   820                     "name=" + name + ", query=" + query);
       
   821 
       
   822             final MarshalledObject<QueryExp> sQuery =
       
   823                     new MarshalledObject<QueryExp>(query);
       
   824             final ClassLoader old = pushDefaultClassLoader();
       
   825             try {
       
   826                 return connection.queryMBeans(name, sQuery, delegationSubject);
       
   827             } catch (IOException ioe) {
       
   828                 communicatorAdmin.gotIOException(ioe);
       
   829 
       
   830                 return connection.queryMBeans(name, sQuery, delegationSubject);
       
   831             } finally {
       
   832                 popDefaultClassLoader(old);
       
   833             }
       
   834         }
       
   835 
       
   836         public Set<ObjectName> queryNames(ObjectName name,
       
   837                 QueryExp query)
       
   838                 throws IOException {
       
   839             if (logger.debugOn()) logger.debug("queryNames",
       
   840                     "name=" + name + ", query=" + query);
       
   841 
       
   842             final MarshalledObject<QueryExp> sQuery =
       
   843                     new MarshalledObject<QueryExp>(query);
       
   844             final ClassLoader old = pushDefaultClassLoader();
       
   845             try {
       
   846                 return connection.queryNames(name, sQuery, delegationSubject);
       
   847             } catch (IOException ioe) {
       
   848                 communicatorAdmin.gotIOException(ioe);
       
   849 
       
   850                 return connection.queryNames(name, sQuery, delegationSubject);
       
   851             } finally {
       
   852                 popDefaultClassLoader(old);
       
   853             }
       
   854         }
       
   855 
       
   856         public boolean isRegistered(ObjectName name)
       
   857         throws IOException {
       
   858             if (logger.debugOn())
       
   859                 logger.debug("isRegistered", "name=" + name);
       
   860 
       
   861             final ClassLoader old = pushDefaultClassLoader();
       
   862             try {
       
   863                 return connection.isRegistered(name, delegationSubject);
       
   864             } catch (IOException ioe) {
       
   865                 communicatorAdmin.gotIOException(ioe);
       
   866 
       
   867                 return connection.isRegistered(name, delegationSubject);
       
   868             } finally {
       
   869                 popDefaultClassLoader(old);
       
   870             }
       
   871         }
       
   872 
       
   873         public Integer getMBeanCount()
       
   874         throws IOException {
       
   875             if (logger.debugOn()) logger.debug("getMBeanCount", "");
       
   876 
       
   877             final ClassLoader old = pushDefaultClassLoader();
       
   878             try {
       
   879                 return connection.getMBeanCount(delegationSubject);
       
   880             } catch (IOException ioe) {
       
   881                 communicatorAdmin.gotIOException(ioe);
       
   882 
       
   883                 return connection.getMBeanCount(delegationSubject);
       
   884             } finally {
       
   885                 popDefaultClassLoader(old);
       
   886             }
       
   887         }
       
   888 
       
   889         public Object getAttribute(ObjectName name,
       
   890                 String attribute)
       
   891                 throws MBeanException,
       
   892                 AttributeNotFoundException,
       
   893                 InstanceNotFoundException,
       
   894                 ReflectionException,
       
   895                 IOException {
       
   896             if (logger.debugOn()) logger.debug("getAttribute",
       
   897                     "name=" + name + ", attribute="
       
   898                     + attribute);
       
   899 
       
   900             final ClassLoader old = pushDefaultClassLoader();
       
   901             try {
       
   902                 return connection.getAttribute(name,
       
   903                         attribute,
       
   904                         delegationSubject);
       
   905             } catch (IOException ioe) {
       
   906                 communicatorAdmin.gotIOException(ioe);
       
   907 
       
   908                 return connection.getAttribute(name,
       
   909                         attribute,
       
   910                         delegationSubject);
       
   911             } finally {
       
   912                 popDefaultClassLoader(old);
       
   913             }
       
   914         }
       
   915 
       
   916         public AttributeList getAttributes(ObjectName name,
       
   917                 String[] attributes)
       
   918                 throws InstanceNotFoundException,
       
   919                 ReflectionException,
       
   920                 IOException {
       
   921             if (logger.debugOn()) logger.debug("getAttributes",
       
   922                     "name=" + name + ", attributes="
       
   923                     + strings(attributes));
       
   924 
       
   925             final ClassLoader old = pushDefaultClassLoader();
       
   926             try {
       
   927                 return connection.getAttributes(name,
       
   928                         attributes,
       
   929                         delegationSubject);
       
   930 
       
   931             } catch (IOException ioe) {
       
   932                 communicatorAdmin.gotIOException(ioe);
       
   933 
       
   934                 return connection.getAttributes(name,
       
   935                         attributes,
       
   936                         delegationSubject);
       
   937             } finally {
       
   938                 popDefaultClassLoader(old);
       
   939             }
       
   940         }
       
   941 
       
   942 
       
   943         public void setAttribute(ObjectName name,
       
   944                 Attribute attribute)
       
   945                 throws InstanceNotFoundException,
       
   946                 AttributeNotFoundException,
       
   947                 InvalidAttributeValueException,
       
   948                 MBeanException,
       
   949                 ReflectionException,
       
   950                 IOException {
       
   951 
       
   952             if (logger.debugOn()) logger.debug("setAttribute",
       
   953                     "name=" + name + ", attribute name="
       
   954                     + attribute.getName());
       
   955 
       
   956             final MarshalledObject<Attribute> sAttribute =
       
   957                     new MarshalledObject<Attribute>(attribute);
       
   958             final ClassLoader old = pushDefaultClassLoader();
       
   959             try {
       
   960                 connection.setAttribute(name, sAttribute, delegationSubject);
       
   961             } catch (IOException ioe) {
       
   962                 communicatorAdmin.gotIOException(ioe);
       
   963 
       
   964                 connection.setAttribute(name, sAttribute, delegationSubject);
       
   965             } finally {
       
   966                 popDefaultClassLoader(old);
       
   967             }
       
   968         }
       
   969 
       
   970         public AttributeList setAttributes(ObjectName name,
       
   971                 AttributeList attributes)
       
   972                 throws InstanceNotFoundException,
       
   973                 ReflectionException,
       
   974                 IOException {
       
   975 
       
   976             if (logger.debugOn()) {
       
   977                 logger.debug("setAttributes",
       
   978                     "name=" + name + ", attribute names="
       
   979                     + getAttributesNames(attributes));
       
   980             }
       
   981 
       
   982             final MarshalledObject<AttributeList> sAttributes =
       
   983                     new MarshalledObject<AttributeList>(attributes);
       
   984             final ClassLoader old = pushDefaultClassLoader();
       
   985             try {
       
   986                 return connection.setAttributes(name,
       
   987                         sAttributes,
       
   988                         delegationSubject);
       
   989             } catch (IOException ioe) {
       
   990                 communicatorAdmin.gotIOException(ioe);
       
   991 
       
   992                 return connection.setAttributes(name,
       
   993                         sAttributes,
       
   994                         delegationSubject);
       
   995             } finally {
       
   996                 popDefaultClassLoader(old);
       
   997             }
       
   998         }
       
   999 
       
  1000 
       
  1001         public Object invoke(ObjectName name,
       
  1002                 String operationName,
       
  1003                 Object params[],
       
  1004                 String signature[])
       
  1005                 throws InstanceNotFoundException,
       
  1006                 MBeanException,
       
  1007                 ReflectionException,
       
  1008                 IOException {
       
  1009 
       
  1010             if (logger.debugOn()) logger.debug("invoke",
       
  1011                     "name=" + name
       
  1012                     + ", operationName=" + operationName
       
  1013                     + ", signature=" + strings(signature));
       
  1014 
       
  1015             final MarshalledObject<Object[]> sParams =
       
  1016                     new MarshalledObject<Object[]>(params);
       
  1017             final ClassLoader old = pushDefaultClassLoader();
       
  1018             try {
       
  1019                 return connection.invoke(name,
       
  1020                         operationName,
       
  1021                         sParams,
       
  1022                         signature,
       
  1023                         delegationSubject);
       
  1024             } catch (IOException ioe) {
       
  1025                 communicatorAdmin.gotIOException(ioe);
       
  1026 
       
  1027                 return connection.invoke(name,
       
  1028                         operationName,
       
  1029                         sParams,
       
  1030                         signature,
       
  1031                         delegationSubject);
       
  1032             } finally {
       
  1033                 popDefaultClassLoader(old);
       
  1034             }
       
  1035         }
       
  1036 
       
  1037 
       
  1038         public String getDefaultDomain()
       
  1039         throws IOException {
       
  1040             if (logger.debugOn()) logger.debug("getDefaultDomain", "");
       
  1041 
       
  1042             final ClassLoader old = pushDefaultClassLoader();
       
  1043             try {
       
  1044                 return connection.getDefaultDomain(delegationSubject);
       
  1045             } catch (IOException ioe) {
       
  1046                 communicatorAdmin.gotIOException(ioe);
       
  1047 
       
  1048                 return connection.getDefaultDomain(delegationSubject);
       
  1049             } finally {
       
  1050                 popDefaultClassLoader(old);
       
  1051             }
       
  1052         }
       
  1053 
       
  1054         public String[] getDomains() throws IOException {
       
  1055             if (logger.debugOn()) logger.debug("getDomains", "");
       
  1056 
       
  1057             final ClassLoader old = pushDefaultClassLoader();
       
  1058             try {
       
  1059                 return connection.getDomains(delegationSubject);
       
  1060             } catch (IOException ioe) {
       
  1061                 communicatorAdmin.gotIOException(ioe);
       
  1062 
       
  1063                 return connection.getDomains(delegationSubject);
       
  1064             } finally {
       
  1065                 popDefaultClassLoader(old);
       
  1066             }
       
  1067         }
       
  1068 
       
  1069         public MBeanInfo getMBeanInfo(ObjectName name)
       
  1070         throws InstanceNotFoundException,
       
  1071                 IntrospectionException,
       
  1072                 ReflectionException,
       
  1073                 IOException {
       
  1074 
       
  1075             if (logger.debugOn()) logger.debug("getMBeanInfo", "name=" + name);
       
  1076             final ClassLoader old = pushDefaultClassLoader();
       
  1077             try {
       
  1078                 return connection.getMBeanInfo(name, delegationSubject);
       
  1079             } catch (IOException ioe) {
       
  1080                 communicatorAdmin.gotIOException(ioe);
       
  1081 
       
  1082                 return connection.getMBeanInfo(name, delegationSubject);
       
  1083             } finally {
       
  1084                 popDefaultClassLoader(old);
       
  1085             }
       
  1086         }
       
  1087 
       
  1088 
       
  1089         public boolean isInstanceOf(ObjectName name,
       
  1090                 String className)
       
  1091                 throws InstanceNotFoundException,
       
  1092                 IOException {
       
  1093             if (logger.debugOn())
       
  1094                 logger.debug("isInstanceOf", "name=" + name +
       
  1095                         ", className=" + className);
       
  1096 
       
  1097             final ClassLoader old = pushDefaultClassLoader();
       
  1098             try {
       
  1099                 return connection.isInstanceOf(name,
       
  1100                         className,
       
  1101                         delegationSubject);
       
  1102             } catch (IOException ioe) {
       
  1103                 communicatorAdmin.gotIOException(ioe);
       
  1104 
       
  1105                 return connection.isInstanceOf(name,
       
  1106                         className,
       
  1107                         delegationSubject);
       
  1108             } finally {
       
  1109                 popDefaultClassLoader(old);
       
  1110             }
       
  1111         }
       
  1112 
       
  1113         public void addNotificationListener(ObjectName name,
       
  1114                 ObjectName listener,
       
  1115                 NotificationFilter filter,
       
  1116                 Object handback)
       
  1117                 throws InstanceNotFoundException,
       
  1118                 IOException {
       
  1119 
       
  1120             if (logger.debugOn())
       
  1121                 logger.debug("addNotificationListener" +
       
  1122                         "(ObjectName,ObjectName,NotificationFilter,Object)",
       
  1123                         "name=" + name + ", listener=" + listener
       
  1124                         + ", filter=" + filter + ", handback=" + handback);
       
  1125 
       
  1126             final MarshalledObject<NotificationFilter> sFilter =
       
  1127                     new MarshalledObject<NotificationFilter>(filter);
       
  1128             final MarshalledObject<Object> sHandback =
       
  1129                     new MarshalledObject<Object>(handback);
       
  1130             final ClassLoader old = pushDefaultClassLoader();
       
  1131             try {
       
  1132                 connection.addNotificationListener(name,
       
  1133                         listener,
       
  1134                         sFilter,
       
  1135                         sHandback,
       
  1136                         delegationSubject);
       
  1137             } catch (IOException ioe) {
       
  1138                 communicatorAdmin.gotIOException(ioe);
       
  1139 
       
  1140                 connection.addNotificationListener(name,
       
  1141                         listener,
       
  1142                         sFilter,
       
  1143                         sHandback,
       
  1144                         delegationSubject);
       
  1145             } finally {
       
  1146                 popDefaultClassLoader(old);
       
  1147             }
       
  1148         }
       
  1149 
       
  1150         public void removeNotificationListener(ObjectName name,
       
  1151                 ObjectName listener)
       
  1152                 throws InstanceNotFoundException,
       
  1153                 ListenerNotFoundException,
       
  1154                 IOException {
       
  1155 
       
  1156             if (logger.debugOn()) logger.debug("removeNotificationListener" +
       
  1157                     "(ObjectName,ObjectName)",
       
  1158                     "name=" + name
       
  1159                     + ", listener=" + listener);
       
  1160 
       
  1161             final ClassLoader old = pushDefaultClassLoader();
       
  1162             try {
       
  1163                 connection.removeNotificationListener(name,
       
  1164                         listener,
       
  1165                         delegationSubject);
       
  1166             } catch (IOException ioe) {
       
  1167                 communicatorAdmin.gotIOException(ioe);
       
  1168 
       
  1169                 connection.removeNotificationListener(name,
       
  1170                         listener,
       
  1171                         delegationSubject);
       
  1172             } finally {
       
  1173                 popDefaultClassLoader(old);
       
  1174             }
       
  1175         }
       
  1176 
       
  1177         public void removeNotificationListener(ObjectName name,
       
  1178                 ObjectName listener,
       
  1179                 NotificationFilter filter,
       
  1180                 Object handback)
       
  1181                 throws InstanceNotFoundException,
       
  1182                 ListenerNotFoundException,
       
  1183                 IOException {
       
  1184             if (logger.debugOn())
       
  1185                 logger.debug("removeNotificationListener" +
       
  1186                         "(ObjectName,ObjectName,NotificationFilter,Object)",
       
  1187                         "name=" + name
       
  1188                         + ", listener=" + listener
       
  1189                         + ", filter=" + filter
       
  1190                         + ", handback=" + handback);
       
  1191 
       
  1192             final MarshalledObject<NotificationFilter> sFilter =
       
  1193                     new MarshalledObject<NotificationFilter>(filter);
       
  1194             final MarshalledObject<Object> sHandback =
       
  1195                     new MarshalledObject<Object>(handback);
       
  1196             final ClassLoader old = pushDefaultClassLoader();
       
  1197             try {
       
  1198                 connection.removeNotificationListener(name,
       
  1199                         listener,
       
  1200                         sFilter,
       
  1201                         sHandback,
       
  1202                         delegationSubject);
       
  1203             } catch (IOException ioe) {
       
  1204                 communicatorAdmin.gotIOException(ioe);
       
  1205 
       
  1206                 connection.removeNotificationListener(name,
       
  1207                         listener,
       
  1208                         sFilter,
       
  1209                         sHandback,
       
  1210                         delegationSubject);
       
  1211             } finally {
       
  1212                 popDefaultClassLoader(old);
       
  1213             }
       
  1214         }
       
  1215 
       
  1216         // Specific Notification Handle ----------------------------------
       
  1217 
       
  1218         public void addNotificationListener(ObjectName name,
       
  1219                 NotificationListener listener,
       
  1220                 NotificationFilter filter,
       
  1221                 Object handback)
       
  1222                 throws InstanceNotFoundException,
       
  1223                 IOException {
       
  1224 
       
  1225             final boolean debug = logger.debugOn();
       
  1226 
       
  1227             if (debug)
       
  1228                 logger.debug("addNotificationListener" +
       
  1229                         "(ObjectName,NotificationListener,"+
       
  1230                         "NotificationFilter,Object)",
       
  1231                         "name=" + name
       
  1232                         + ", listener=" + listener
       
  1233                         + ", filter=" + filter
       
  1234                         + ", handback=" + handback);
       
  1235 
       
  1236             final Integer listenerID =
       
  1237                     addListenerWithSubject(name,
       
  1238                     new MarshalledObject<NotificationFilter>(filter),
       
  1239                     delegationSubject,true);
       
  1240             rmiNotifClient.addNotificationListener(listenerID, name, listener,
       
  1241                     filter, handback,
       
  1242                     delegationSubject);
       
  1243         }
       
  1244 
       
  1245         public void removeNotificationListener(ObjectName name,
       
  1246                 NotificationListener listener)
       
  1247                 throws InstanceNotFoundException,
       
  1248                 ListenerNotFoundException,
       
  1249                 IOException {
       
  1250 
       
  1251             final boolean debug = logger.debugOn();
       
  1252 
       
  1253             if (debug) logger.debug("removeNotificationListener"+
       
  1254                     "(ObjectName,NotificationListener)",
       
  1255                     "name=" + name
       
  1256                     + ", listener=" + listener);
       
  1257 
       
  1258             final Integer[] ret =
       
  1259                     rmiNotifClient.removeNotificationListener(name, listener);
       
  1260 
       
  1261             if (debug) logger.debug("removeNotificationListener",
       
  1262                     "listenerIDs=" + objects(ret));
       
  1263 
       
  1264             final ClassLoader old = pushDefaultClassLoader();
       
  1265 
       
  1266             try {
       
  1267                 connection.removeNotificationListeners(name,
       
  1268                         ret,
       
  1269                         delegationSubject);
       
  1270             } catch (IOException ioe) {
       
  1271                 communicatorAdmin.gotIOException(ioe);
       
  1272 
       
  1273                 connection.removeNotificationListeners(name,
       
  1274                         ret,
       
  1275                         delegationSubject);
       
  1276             } finally {
       
  1277                 popDefaultClassLoader(old);
       
  1278             }
       
  1279 
       
  1280         }
       
  1281 
       
  1282         public void removeNotificationListener(ObjectName name,
       
  1283                 NotificationListener listener,
       
  1284                 NotificationFilter filter,
       
  1285                 Object handback)
       
  1286                 throws InstanceNotFoundException,
       
  1287                 ListenerNotFoundException,
       
  1288                 IOException {
       
  1289             final boolean debug = logger.debugOn();
       
  1290 
       
  1291             if (debug)
       
  1292                 logger.debug("removeNotificationListener"+
       
  1293                         "(ObjectName,NotificationListener,"+
       
  1294                         "NotificationFilter,Object)",
       
  1295                         "name=" + name
       
  1296                         + ", listener=" + listener
       
  1297                         + ", filter=" + filter
       
  1298                         + ", handback=" + handback);
       
  1299 
       
  1300             final Integer ret =
       
  1301                     rmiNotifClient.removeNotificationListener(name, listener,
       
  1302                     filter, handback);
       
  1303 
       
  1304             if (debug) logger.debug("removeNotificationListener",
       
  1305                     "listenerID=" + ret);
       
  1306 
       
  1307             final ClassLoader old = pushDefaultClassLoader();
       
  1308             try {
       
  1309                 connection.removeNotificationListeners(name,
       
  1310                         new Integer[] {ret},
       
  1311                         delegationSubject);
       
  1312             } catch (IOException ioe) {
       
  1313                 communicatorAdmin.gotIOException(ioe);
       
  1314 
       
  1315                 connection.removeNotificationListeners(name,
       
  1316                         new Integer[] {ret},
       
  1317                         delegationSubject);
       
  1318             } finally {
       
  1319                 popDefaultClassLoader(old);
       
  1320             }
       
  1321 
       
  1322         }
       
  1323     }
       
  1324 
       
  1325     //--------------------------------------------------------------------
       
  1326     private class RMINotifClient extends ClientNotifForwarder {
       
  1327         public RMINotifClient(ClassLoader cl, Map<String, ?> env) {
       
  1328             super(cl, env);
       
  1329         }
       
  1330 
       
  1331         protected NotificationResult fetchNotifs(long clientSequenceNumber,
       
  1332                 int maxNotifications,
       
  1333                 long timeout)
       
  1334                 throws IOException, ClassNotFoundException {
       
  1335 
       
  1336             boolean retried = false;
       
  1337             while (true) { // used for a successful re-connection
       
  1338                            // or a transient network problem
       
  1339                 try {
       
  1340                     return connection.fetchNotifications(clientSequenceNumber,
       
  1341                             maxNotifications,
       
  1342                             timeout); // return normally
       
  1343                 } catch (IOException ioe) {
       
  1344                     // Examine the chain of exceptions to determine whether this
       
  1345                     // is a deserialization issue. If so - we propagate the
       
  1346                     // appropriate exception to the caller, who will then
       
  1347                     // proceed with fetching notifications one by one
       
  1348                     rethrowDeserializationException(ioe);
       
  1349 
       
  1350                     try {
       
  1351                         communicatorAdmin.gotIOException(ioe);
       
  1352                         // reconnection OK, back to "while" to do again
       
  1353                     } catch (IOException ee) {
       
  1354                         boolean toClose = false;
       
  1355 
       
  1356                         synchronized (this) {
       
  1357                             if (terminated) {
       
  1358                                 // the connection is closed.
       
  1359                                 throw ioe;
       
  1360                             } else if (retried) {
       
  1361                                 toClose = true;
       
  1362                             }
       
  1363                         }
       
  1364 
       
  1365                         if (toClose) {
       
  1366                             // JDK-8049303
       
  1367                             // We received an IOException - but the communicatorAdmin
       
  1368                             // did not close the connection - possibly because
       
  1369                             // the original exception was raised by a transient network
       
  1370                             // problem?
       
  1371                             // We already know that this exception is not due to a deserialization
       
  1372                             // issue as we already took care of that before involving the
       
  1373                             // communicatorAdmin. Moreover - we already made one retry attempt
       
  1374                             // at fetching the same batch of notifications - and the
       
  1375                             // problem persisted.
       
  1376                             // Since trying again doesn't seem to solve the issue, we will now
       
  1377                             // close the connection. Doing otherwise might cause the
       
  1378                             // NotifFetcher thread to die silently.
       
  1379                             final Notification failedNotif =
       
  1380                                     new JMXConnectionNotification(
       
  1381                                     JMXConnectionNotification.FAILED,
       
  1382                                     this,
       
  1383                                     connectionId,
       
  1384                                     clientNotifSeqNo++,
       
  1385                                     "Failed to communicate with the server: " + ioe.toString(),
       
  1386                                     ioe);
       
  1387 
       
  1388                             sendNotification(failedNotif);
       
  1389 
       
  1390                             try {
       
  1391                                 close(true);
       
  1392                             } catch (Exception e) {
       
  1393                                 // OK.
       
  1394                                 // We are closing
       
  1395                             }
       
  1396                             throw ioe; // the connection is closed here.
       
  1397                         } else {
       
  1398                             // JDK-8049303 possible transient network problem,
       
  1399                             // let's try one more time
       
  1400                             retried = true;
       
  1401                         }
       
  1402                     }
       
  1403                 }
       
  1404             }
       
  1405         }
       
  1406 
       
  1407         private void rethrowDeserializationException(IOException ioe)
       
  1408                 throws ClassNotFoundException, IOException {
       
  1409             // specially treating for an UnmarshalException
       
  1410             if (ioe instanceof UnmarshalException) {
       
  1411                 NotSerializableException nse = new NotSerializableException();
       
  1412                 nse.initCause(ioe);
       
  1413                 throw nse; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs
       
  1414                            // fetch one by one with UnmarshalException
       
  1415             }
       
  1416 
       
  1417             // Not serialization problem, return.
       
  1418         }
       
  1419 
       
  1420         protected Integer addListenerForMBeanRemovedNotif()
       
  1421         throws IOException, InstanceNotFoundException {
       
  1422             NotificationFilterSupport clientFilter =
       
  1423                     new NotificationFilterSupport();
       
  1424             clientFilter.enableType(
       
  1425                     MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
       
  1426             MarshalledObject<NotificationFilter> sFilter =
       
  1427                 new MarshalledObject<NotificationFilter>(clientFilter);
       
  1428 
       
  1429             Integer[] listenerIDs;
       
  1430             final ObjectName[] names =
       
  1431                 new ObjectName[] {MBeanServerDelegate.DELEGATE_NAME};
       
  1432             final MarshalledObject<NotificationFilter>[] filters =
       
  1433                 Util.cast(new MarshalledObject<?>[] {sFilter});
       
  1434             final Subject[] subjects = new Subject[] {null};
       
  1435             try {
       
  1436                 listenerIDs =
       
  1437                         connection.addNotificationListeners(names,
       
  1438                         filters,
       
  1439                         subjects);
       
  1440 
       
  1441             } catch (IOException ioe) {
       
  1442                 communicatorAdmin.gotIOException(ioe);
       
  1443 
       
  1444                 listenerIDs =
       
  1445                         connection.addNotificationListeners(names,
       
  1446                         filters,
       
  1447                         subjects);
       
  1448             }
       
  1449             return listenerIDs[0];
       
  1450         }
       
  1451 
       
  1452         protected void removeListenerForMBeanRemovedNotif(Integer id)
       
  1453         throws IOException, InstanceNotFoundException,
       
  1454                 ListenerNotFoundException {
       
  1455             try {
       
  1456                 connection.removeNotificationListeners(
       
  1457                         MBeanServerDelegate.DELEGATE_NAME,
       
  1458                         new Integer[] {id},
       
  1459                         null);
       
  1460             } catch (IOException ioe) {
       
  1461                 communicatorAdmin.gotIOException(ioe);
       
  1462 
       
  1463                 connection.removeNotificationListeners(
       
  1464                         MBeanServerDelegate.DELEGATE_NAME,
       
  1465                         new Integer[] {id},
       
  1466                         null);
       
  1467             }
       
  1468 
       
  1469         }
       
  1470 
       
  1471         protected void lostNotifs(String message, long number) {
       
  1472             final String notifType = JMXConnectionNotification.NOTIFS_LOST;
       
  1473 
       
  1474             final JMXConnectionNotification n =
       
  1475                 new JMXConnectionNotification(notifType,
       
  1476                                               RMIConnector.this,
       
  1477                                               connectionId,
       
  1478                                               clientNotifCounter++,
       
  1479                                               message,
       
  1480                                               Long.valueOf(number));
       
  1481             sendNotification(n);
       
  1482         }
       
  1483     }
       
  1484 
       
  1485     private class RMIClientCommunicatorAdmin extends ClientCommunicatorAdmin {
       
  1486         public RMIClientCommunicatorAdmin(long period) {
       
  1487             super(period);
       
  1488         }
       
  1489 
       
  1490         @Override
       
  1491         public void gotIOException(IOException ioe) throws IOException {
       
  1492             if (ioe instanceof NoSuchObjectException) {
       
  1493                 // need to restart
       
  1494                 super.gotIOException(ioe);
       
  1495 
       
  1496                 return;
       
  1497             }
       
  1498 
       
  1499             // check if the connection is broken
       
  1500             try {
       
  1501                 connection.getDefaultDomain(null);
       
  1502             } catch (IOException ioexc) {
       
  1503                 boolean toClose = false;
       
  1504 
       
  1505                 synchronized(this) {
       
  1506                     if (!terminated) {
       
  1507                         terminated = true;
       
  1508 
       
  1509                         toClose = true;
       
  1510                     }
       
  1511                 }
       
  1512 
       
  1513                 if (toClose) {
       
  1514                     // we should close the connection,
       
  1515                     // but send a failed notif at first
       
  1516                     final Notification failedNotif =
       
  1517                             new JMXConnectionNotification(
       
  1518                             JMXConnectionNotification.FAILED,
       
  1519                             this,
       
  1520                             connectionId,
       
  1521                             clientNotifSeqNo++,
       
  1522                             "Failed to communicate with the server: "+ioe.toString(),
       
  1523                             ioe);
       
  1524 
       
  1525                     sendNotification(failedNotif);
       
  1526 
       
  1527                     try {
       
  1528                         close(true);
       
  1529                     } catch (Exception e) {
       
  1530                         // OK.
       
  1531                         // We are closing
       
  1532                     }
       
  1533                 }
       
  1534             }
       
  1535 
       
  1536             // forward the exception
       
  1537             if (ioe instanceof ServerException) {
       
  1538                 /* Need to unwrap the exception.
       
  1539                    Some user-thrown exception at server side will be wrapped by
       
  1540                    rmi into a ServerException.
       
  1541                    For example, a RMIConnnectorServer will wrap a
       
  1542                    ClassNotFoundException into a UnmarshalException, and rmi
       
  1543                    will throw a ServerException at client side which wraps this
       
  1544                    UnmarshalException.
       
  1545                    No failed notif here.
       
  1546                  */
       
  1547                 Throwable tt = ((ServerException)ioe).detail;
       
  1548 
       
  1549                 if (tt instanceof IOException) {
       
  1550                     throw (IOException)tt;
       
  1551                 } else if (tt instanceof RuntimeException) {
       
  1552                     throw (RuntimeException)tt;
       
  1553                 }
       
  1554             }
       
  1555 
       
  1556             throw ioe;
       
  1557         }
       
  1558 
       
  1559         public void reconnectNotificationListeners(ClientListenerInfo[] old) throws IOException {
       
  1560             final int len  = old.length;
       
  1561             int i;
       
  1562 
       
  1563             ClientListenerInfo[] clis = new ClientListenerInfo[len];
       
  1564 
       
  1565             final Subject[] subjects = new Subject[len];
       
  1566             final ObjectName[] names = new ObjectName[len];
       
  1567             final NotificationListener[] listeners = new NotificationListener[len];
       
  1568             final NotificationFilter[] filters = new NotificationFilter[len];
       
  1569             final MarshalledObject<NotificationFilter>[] mFilters =
       
  1570                     Util.cast(new MarshalledObject<?>[len]);
       
  1571             final Object[] handbacks = new Object[len];
       
  1572 
       
  1573             for (i=0;i<len;i++) {
       
  1574                 subjects[i]  = old[i].getDelegationSubject();
       
  1575                 names[i]     = old[i].getObjectName();
       
  1576                 listeners[i] = old[i].getListener();
       
  1577                 filters[i]   = old[i].getNotificationFilter();
       
  1578                 mFilters[i]  = new MarshalledObject<NotificationFilter>(filters[i]);
       
  1579                 handbacks[i] = old[i].getHandback();
       
  1580             }
       
  1581 
       
  1582             try {
       
  1583                 Integer[] ids = addListenersWithSubjects(names,mFilters,subjects,false);
       
  1584 
       
  1585                 for (i=0;i<len;i++) {
       
  1586                     clis[i] = new ClientListenerInfo(ids[i],
       
  1587                             names[i],
       
  1588                             listeners[i],
       
  1589                             filters[i],
       
  1590                             handbacks[i],
       
  1591                             subjects[i]);
       
  1592                 }
       
  1593 
       
  1594                 rmiNotifClient.postReconnection(clis);
       
  1595 
       
  1596                 return;
       
  1597             } catch (InstanceNotFoundException infe) {
       
  1598                 // OK, we will do one by one
       
  1599             }
       
  1600 
       
  1601             int j = 0;
       
  1602             for (i=0;i<len;i++) {
       
  1603                 try {
       
  1604                     Integer id = addListenerWithSubject(names[i],
       
  1605                             new MarshalledObject<NotificationFilter>(filters[i]),
       
  1606                             subjects[i],
       
  1607                             false);
       
  1608 
       
  1609                     clis[j++] = new ClientListenerInfo(id,
       
  1610                             names[i],
       
  1611                             listeners[i],
       
  1612                             filters[i],
       
  1613                             handbacks[i],
       
  1614                             subjects[i]);
       
  1615                 } catch (InstanceNotFoundException infe) {
       
  1616                     logger.warning("reconnectNotificationListeners",
       
  1617                             "Can't reconnect listener for " +
       
  1618                             names[i]);
       
  1619                 }
       
  1620             }
       
  1621 
       
  1622             if (j != len) {
       
  1623                 ClientListenerInfo[] tmp = clis;
       
  1624                 clis = new ClientListenerInfo[j];
       
  1625                 System.arraycopy(tmp, 0, clis, 0, j);
       
  1626             }
       
  1627 
       
  1628             rmiNotifClient.postReconnection(clis);
       
  1629         }
       
  1630 
       
  1631         protected void checkConnection() throws IOException {
       
  1632             if (logger.debugOn())
       
  1633                 logger.debug("RMIClientCommunicatorAdmin-checkConnection",
       
  1634                         "Calling the method getDefaultDomain.");
       
  1635 
       
  1636             connection.getDefaultDomain(null);
       
  1637         }
       
  1638 
       
  1639         protected void doStart() throws IOException {
       
  1640             // Get RMIServer stub from directory or URL encoding if needed.
       
  1641             RMIServer stub;
       
  1642             try {
       
  1643                 stub = (rmiServer!=null)?rmiServer:
       
  1644                     findRMIServer(jmxServiceURL, env);
       
  1645             } catch (NamingException ne) {
       
  1646                 throw new IOException("Failed to get a RMI stub: "+ne);
       
  1647             }
       
  1648 
       
  1649             // Calling newClient on the RMIServer stub.
       
  1650             Object credentials = env.get(CREDENTIALS);
       
  1651             connection = stub.newClient(credentials);
       
  1652 
       
  1653             // notif issues
       
  1654             final ClientListenerInfo[] old = rmiNotifClient.preReconnection();
       
  1655 
       
  1656             reconnectNotificationListeners(old);
       
  1657 
       
  1658             connectionId = getConnectionId();
       
  1659 
       
  1660             Notification reconnectedNotif =
       
  1661                     new JMXConnectionNotification(JMXConnectionNotification.OPENED,
       
  1662                     this,
       
  1663                     connectionId,
       
  1664                     clientNotifSeqNo++,
       
  1665                     "Reconnected to server",
       
  1666                     null);
       
  1667             sendNotification(reconnectedNotif);
       
  1668 
       
  1669         }
       
  1670 
       
  1671         protected void doStop() {
       
  1672             try {
       
  1673                 close();
       
  1674             } catch (IOException ioe) {
       
  1675                 logger.warning("RMIClientCommunicatorAdmin-doStop",
       
  1676                         "Failed to call the method close():" + ioe);
       
  1677                 logger.debug("RMIClientCommunicatorAdmin-doStop",ioe);
       
  1678             }
       
  1679         }
       
  1680     }
       
  1681 
       
  1682     //--------------------------------------------------------------------
       
  1683     // Private stuff - Serialization
       
  1684     //--------------------------------------------------------------------
       
  1685     /**
       
  1686      * Read RMIConnector fields from an {@link java.io.ObjectInputStream
       
  1687      * ObjectInputStream}.
       
  1688      * Calls {@code s.defaultReadObject()} and then initializes
       
  1689      * all transient variables that need initializing.
       
  1690      * @param s The ObjectInputStream to read from.
       
  1691      * @exception InvalidObjectException if none of <var>rmiServer</var> stub
       
  1692      *    or <var>jmxServiceURL</var> are set.
       
  1693      * @see #RMIConnector(JMXServiceURL,Map)
       
  1694      * @see #RMIConnector(RMIServer,Map)
       
  1695      **/
       
  1696     private void readObject(java.io.ObjectInputStream s)
       
  1697     throws IOException, ClassNotFoundException  {
       
  1698         s.defaultReadObject();
       
  1699 
       
  1700         if (rmiServer == null && jmxServiceURL == null) throw new
       
  1701                 InvalidObjectException("rmiServer and jmxServiceURL both null");
       
  1702 
       
  1703         initTransients();
       
  1704     }
       
  1705 
       
  1706     /**
       
  1707      * Writes the RMIConnector fields to an {@link java.io.ObjectOutputStream
       
  1708      * ObjectOutputStream}.
       
  1709      * <p>Connects the underlying RMIServer stub to an ORB, if needed,
       
  1710      * before serializing it. This is done using the environment
       
  1711      * map that was provided to the constructor, if any, and as documented
       
  1712      * in {@link javax.management.remote.rmi}.</p>
       
  1713      * <p>This method then calls {@code s.defaultWriteObject()}.
       
  1714      * Usually, <var>rmiServer</var> is null if this object
       
  1715      * was constructed with a JMXServiceURL, and <var>jmxServiceURL</var>
       
  1716      * is null if this object is constructed with a RMIServer stub.
       
  1717      * <p>Note that the environment Map is not serialized, since the objects
       
  1718      * it contains are assumed to be contextual and relevant only
       
  1719      * with respect to the local environment (class loader, ORB, etc...).</p>
       
  1720      * <p>After an RMIConnector is deserialized, it is assumed that the
       
  1721      * user will call {@link #connect(Map)}, providing a new Map that
       
  1722      * can contain values which are contextually relevant to the new
       
  1723      * local environment.</p>
       
  1724      * <p>Since connection to the ORB is needed prior to serializing, and
       
  1725      * since the ORB to connect to is one of those contextual parameters,
       
  1726      * it is not recommended to re-serialize a just de-serialized object -
       
  1727      * as the de-serialized object has no map. Thus, when an RMIConnector
       
  1728      * object is needed for serialization or transmission to a remote
       
  1729      * application, it is recommended to obtain a new RMIConnector stub
       
  1730      * by calling {@link RMIConnectorServer#toJMXConnector(Map)}.</p>
       
  1731      * @param s The ObjectOutputStream to write to.
       
  1732      * @exception InvalidObjectException if none of <var>rmiServer</var> stub
       
  1733      *    or <var>jmxServiceURL</var> are set.
       
  1734      * @see #RMIConnector(JMXServiceURL,Map)
       
  1735      * @see #RMIConnector(RMIServer,Map)
       
  1736      **/
       
  1737     private void writeObject(java.io.ObjectOutputStream s)
       
  1738     throws IOException {
       
  1739         if (rmiServer == null && jmxServiceURL == null) throw new
       
  1740                 InvalidObjectException("rmiServer and jmxServiceURL both null.");
       
  1741         s.defaultWriteObject();
       
  1742     }
       
  1743 
       
  1744     // Initialization of transient variables.
       
  1745     private void initTransients() {
       
  1746         rmbscMap = new WeakHashMap<Subject, WeakReference<MBeanServerConnection>>();
       
  1747         connected = false;
       
  1748         terminated = false;
       
  1749 
       
  1750         connectionBroadcaster = new NotificationBroadcasterSupport();
       
  1751     }
       
  1752 
       
  1753     //--------------------------------------------------------------------
       
  1754     // Private stuff - Check if stub can be trusted.
       
  1755     //--------------------------------------------------------------------
       
  1756 
       
  1757     private static void checkStub(Remote stub,
       
  1758             Class<?> stubClass) {
       
  1759 
       
  1760         // Check remote stub is from the expected class.
       
  1761         //
       
  1762         if (stub.getClass() != stubClass) {
       
  1763             if (!Proxy.isProxyClass(stub.getClass())) {
       
  1764                 throw new SecurityException(
       
  1765                         "Expecting a " + stubClass.getName() + " stub!");
       
  1766             } else {
       
  1767                 InvocationHandler handler = Proxy.getInvocationHandler(stub);
       
  1768                 if (handler.getClass() != RemoteObjectInvocationHandler.class)
       
  1769                     throw new SecurityException(
       
  1770                             "Expecting a dynamic proxy instance with a " +
       
  1771                             RemoteObjectInvocationHandler.class.getName() +
       
  1772                             " invocation handler!");
       
  1773                 else
       
  1774                     stub = (Remote) handler;
       
  1775             }
       
  1776         }
       
  1777 
       
  1778         // Check RemoteRef in stub is from the expected class
       
  1779         // "sun.rmi.server.UnicastRef2".
       
  1780         //
       
  1781         RemoteRef ref = ((RemoteObject)stub).getRef();
       
  1782         if (ref.getClass() != UnicastRef2.class)
       
  1783             throw new SecurityException(
       
  1784                     "Expecting a " + UnicastRef2.class.getName() +
       
  1785                     " remote reference in stub!");
       
  1786 
       
  1787         // Check RMIClientSocketFactory in stub is from the expected class
       
  1788         // "javax.rmi.ssl.SslRMIClientSocketFactory".
       
  1789         //
       
  1790         LiveRef liveRef = ((UnicastRef2)ref).getLiveRef();
       
  1791         RMIClientSocketFactory csf = liveRef.getClientSocketFactory();
       
  1792         if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class)
       
  1793             throw new SecurityException(
       
  1794                     "Expecting a " + SslRMIClientSocketFactory.class.getName() +
       
  1795                     " RMI client socket factory in stub!");
       
  1796     }
       
  1797 
       
  1798     //--------------------------------------------------------------------
       
  1799     // Private stuff - RMIServer creation
       
  1800     //--------------------------------------------------------------------
       
  1801 
       
  1802     private RMIServer findRMIServer(JMXServiceURL directoryURL,
       
  1803             Map<String, Object> environment)
       
  1804             throws NamingException, IOException {
       
  1805 
       
  1806         String path = directoryURL.getURLPath();
       
  1807         int end = path.indexOf(';');
       
  1808         if (end < 0) end = path.length();
       
  1809         if (path.startsWith("/jndi/"))
       
  1810             return findRMIServerJNDI(path.substring(6,end), environment);
       
  1811         else if (path.startsWith("/stub/"))
       
  1812             return findRMIServerJRMP(path.substring(6,end), environment);
       
  1813         else {
       
  1814             final String msg = "URL path must begin with /jndi/ or /stub/ " +
       
  1815                     "or /ior/: " + path;
       
  1816             throw new MalformedURLException(msg);
       
  1817         }
       
  1818     }
       
  1819 
       
  1820     /**
       
  1821      * Lookup the RMIServer stub in a directory.
       
  1822      * @param jndiURL A JNDI URL indicating the location of the Stub
       
  1823      *                (see {@link javax.management.remote.rmi}), e.g.:
       
  1824      *   <ul><li>{@code rmi://registry-host:port/rmi-stub-name}</li>
       
  1825      *       <li>or {@code ldap://ldap-host:port/java-container-dn}</li>
       
  1826      *   </ul>
       
  1827      * @param env the environment Map passed to the connector.
       
  1828      * @return The retrieved RMIServer stub.
       
  1829      * @exception NamingException if the stub couldn't be found.
       
  1830      **/
       
  1831     private RMIServer findRMIServerJNDI(String jndiURL, Map<String, ?> env)
       
  1832             throws NamingException {
       
  1833 
       
  1834         InitialContext ctx = new InitialContext(EnvHelp.mapToHashtable(env));
       
  1835 
       
  1836         Object objref = ctx.lookup(jndiURL);
       
  1837         ctx.close();
       
  1838 
       
  1839         return narrowJRMPServer(objref);
       
  1840     }
       
  1841 
       
  1842     private static RMIServer narrowJRMPServer(Object objref) {
       
  1843 
       
  1844         return (RMIServer) objref;
       
  1845     }
       
  1846 
       
  1847     private RMIServer findRMIServerJRMP(String base64, Map<String, ?> env)
       
  1848         throws IOException {
       
  1849         final byte[] serialized;
       
  1850         try {
       
  1851             serialized = base64ToByteArray(base64);
       
  1852         } catch (IllegalArgumentException e) {
       
  1853             throw new MalformedURLException("Bad BASE64 encoding: " +
       
  1854                     e.getMessage());
       
  1855         }
       
  1856         final ByteArrayInputStream bin = new ByteArrayInputStream(serialized);
       
  1857 
       
  1858         final ClassLoader loader = EnvHelp.resolveClientClassLoader(env);
       
  1859         final ObjectInputStream oin =
       
  1860                 (loader == null) ?
       
  1861                     new ObjectInputStream(bin) :
       
  1862                     new ObjectInputStreamWithLoader(bin, loader);
       
  1863         final Object stub;
       
  1864         try {
       
  1865             stub = oin.readObject();
       
  1866         } catch (ClassNotFoundException e) {
       
  1867             throw new MalformedURLException("Class not found: " + e);
       
  1868         }
       
  1869         return (RMIServer)stub;
       
  1870     }
       
  1871 
       
  1872     private static final class ObjectInputStreamWithLoader
       
  1873             extends ObjectInputStream {
       
  1874         ObjectInputStreamWithLoader(InputStream in, ClassLoader cl)
       
  1875         throws IOException, IllegalArgumentException {
       
  1876             super(in);
       
  1877             if (cl == null ) {
       
  1878               throw new IllegalArgumentException("class loader is null");
       
  1879             }
       
  1880             this.loader = cl;
       
  1881         }
       
  1882 
       
  1883         @Override
       
  1884         protected Class<?> resolveClass(ObjectStreamClass classDesc)
       
  1885                 throws IOException, ClassNotFoundException {
       
  1886             String name = classDesc.getName();
       
  1887             ReflectUtil.checkPackageAccess(name);
       
  1888             return Class.forName(name, false, Objects.requireNonNull(loader));
       
  1889         }
       
  1890 
       
  1891         private final ClassLoader loader;
       
  1892     }
       
  1893 
       
  1894     private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) {
       
  1895         MBeanServerConnection conn = null;
       
  1896 
       
  1897         if (delegationSubject == null) {
       
  1898             if (nullSubjectConnRef == null
       
  1899                     || (conn = nullSubjectConnRef.get()) == null) {
       
  1900                 conn = new RemoteMBeanServerConnection(null);
       
  1901                 nullSubjectConnRef = new WeakReference<MBeanServerConnection>(conn);
       
  1902             }
       
  1903         } else {
       
  1904             WeakReference<MBeanServerConnection> wr = rmbscMap.get(delegationSubject);
       
  1905             if (wr == null || (conn = wr.get()) == null) {
       
  1906                 conn = new RemoteMBeanServerConnection(delegationSubject);
       
  1907                 rmbscMap.put(delegationSubject, new WeakReference<MBeanServerConnection>(conn));
       
  1908             }
       
  1909         }
       
  1910         return conn;
       
  1911     }
       
  1912 
       
  1913     /*
       
  1914        The following section of code avoids a class loading problem
       
  1915        with RMI.  The problem is that an RMI stub, when deserializing
       
  1916        a remote method return value or exception, will first of all
       
  1917        consult the first non-bootstrap class loader it finds in the
       
  1918        call stack.  This can lead to behavior that is not portable
       
  1919        between implementations of the JMX Remote API.  Notably, an
       
  1920        implementation on J2SE 1.4 will find the RMI stub's loader on
       
  1921        the stack.  But in J2SE 5, this stub is loaded by the
       
  1922        bootstrap loader, so RMI will find the loader of the user code
       
  1923        that called an MBeanServerConnection method.
       
  1924 
       
  1925        To avoid this problem, we take advantage of what the RMI stub
       
  1926        is doing internally.  Each remote call will end up calling
       
  1927        ref.invoke(...), where ref is the RemoteRef parameter given to
       
  1928        the RMI stub's constructor.  It is within this call that the
       
  1929        deserialization will happen.  So we fabricate our own RemoteRef
       
  1930        that delegates everything to the "real" one but that is loaded
       
  1931        by a class loader that knows no other classes.  The class
       
  1932        loader NoCallStackClassLoader does this: the RemoteRef is an
       
  1933        instance of the class named by proxyRefClassName, which is
       
  1934        fabricated by the class loader using byte code that is defined
       
  1935        by the string below.
       
  1936 
       
  1937        The call stack when the deserialization happens is thus this:
       
  1938        MBeanServerConnection.getAttribute (or whatever)
       
  1939        -> RMIConnectionImpl_Stub.getAttribute
       
  1940           -> ProxyRef.invoke(...getAttribute...)
       
  1941              -> UnicastRef.invoke(...getAttribute...)
       
  1942                 -> internal RMI stuff
       
  1943 
       
  1944        Here UnicastRef is the RemoteRef created when the stub was
       
  1945        deserialized (which is of some RMI internal class).  It and the
       
  1946        "internal RMI stuff" are loaded by the bootstrap loader, so are
       
  1947        transparent to the stack search.  The first non-bootstrap
       
  1948        loader found is our ProxyRefLoader, as required.
       
  1949 
       
  1950        In a future version of this code as integrated into J2SE 5,
       
  1951        this workaround could be replaced by direct access to the
       
  1952        internals of RMI.  For now, we use the same code base for J2SE
       
  1953        and for the standalone Reference Implementation.
       
  1954 
       
  1955        The byte code below encodes the following class, compiled using
       
  1956        J2SE 1.4.2 with the -g:none option.
       
  1957 
       
  1958         package jdk.jmx.remote.internal.rmi;
       
  1959 
       
  1960         import java.lang.reflect.Method;
       
  1961         import java.rmi.Remote;
       
  1962         import java.rmi.server.RemoteRef;
       
  1963         import com.sun.jmx.remote.internal.rmi.ProxyRef;
       
  1964 
       
  1965         public class PRef extends ProxyRef {
       
  1966             public PRef(RemoteRef ref) {
       
  1967                 super(ref);
       
  1968             }
       
  1969 
       
  1970             public Object invoke(Remote obj, Method method,
       
  1971                                  Object[] params, long opnum)
       
  1972                     throws Exception {
       
  1973                 return ref.invoke(obj, method, params, opnum);
       
  1974             }
       
  1975         }
       
  1976      */
       
  1977 
       
  1978     private static final String rmiServerImplStubClassName =
       
  1979         RMIServer.class.getName() + "Impl_Stub";
       
  1980     private static final Class<?> rmiServerImplStubClass;
       
  1981     private static final String rmiConnectionImplStubClassName =
       
  1982             RMIConnection.class.getName() + "Impl_Stub";
       
  1983     private static final Class<?> rmiConnectionImplStubClass;
       
  1984     private static final String pRefClassName =
       
  1985         "jdk.jmx.remote.internal.rmi.PRef";
       
  1986     private static final Constructor<?> proxyRefConstructor;
       
  1987     static {
       
  1988         final String pRefByteCodeString =
       
  1989                 "\312\376\272\276\0\0\0\65\0\27\12\0\5\0\15\11\0\4\0\16\13\0\17"+
       
  1990                 "\0\20\7\0\21\7\0\22\1\0\6<init>\1\0\36(Ljava/rmi/server/Remote"+
       
  1991                 "Ref;)V\1\0\4Code\1\0\6invoke\1\0S(Ljava/rmi/Remote;Ljava/lang/"+
       
  1992                 "reflect/Method;[Ljava/lang/Object;J)Ljava/lang/Object;\1\0\12E"+
       
  1993                 "xceptions\7\0\23\14\0\6\0\7\14\0\24\0\25\7\0\26\14\0\11\0\12\1"+
       
  1994                 "\0 jdk/jmx/remote/internal/rmi/PRef\1\0(com/sun/jmx/remote/int"+
       
  1995                 "ernal/rmi/ProxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Lj"+
       
  1996                 "ava/rmi/server/RemoteRef;\1\0\31java/rmi/server/RemoteRef\0!\0"+
       
  1997                 "\4\0\5\0\0\0\0\0\2\0\1\0\6\0\7\0\1\0\10\0\0\0\22\0\2\0\2\0\0\0"+
       
  1998                 "\6*+\267\0\1\261\0\0\0\0\0\1\0\11\0\12\0\2\0\10\0\0\0\33\0\6\0"+
       
  1999                 "\6\0\0\0\17*\264\0\2+,-\26\4\271\0\3\6\0\260\0\0\0\0\0\13\0\0\0"+
       
  2000                 "\4\0\1\0\14\0\0";
       
  2001         final byte[] pRefByteCode =
       
  2002                 NoCallStackClassLoader.stringToBytes(pRefByteCodeString);
       
  2003         PrivilegedExceptionAction<Constructor<?>> action =
       
  2004                 new PrivilegedExceptionAction<Constructor<?>>() {
       
  2005             public Constructor<?> run() throws Exception {
       
  2006                 Class<RMIConnector> thisClass = RMIConnector.class;
       
  2007                 ClassLoader thisLoader = thisClass.getClassLoader();
       
  2008                 ProtectionDomain thisProtectionDomain =
       
  2009                         thisClass.getProtectionDomain();
       
  2010 
       
  2011                 String proxyRefCName = ProxyRef.class.getName();
       
  2012                 ClassLoader cl =
       
  2013                         new NoCallStackClassLoader(pRefClassName,
       
  2014                         pRefByteCode,
       
  2015                         new String[] { proxyRefCName },
       
  2016                         thisLoader,
       
  2017                         thisProtectionDomain);
       
  2018 
       
  2019                 Module jmxModule = ProxyRef.class.getModule();
       
  2020                 Module rmiModule = RemoteRef.class.getModule();
       
  2021 
       
  2022                 String pkg = packageOf(pRefClassName);
       
  2023                 assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName));
       
  2024                 Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg));
       
  2025 
       
  2026                 // jdk.remoteref needs to read to java.base and jmxModule
       
  2027                 Modules.addReads(m, Object.class.getModule());
       
  2028                 Modules.addReads(m, jmxModule);
       
  2029                 Modules.addReads(m, rmiModule);
       
  2030 
       
  2031                 // jdk.remoteref needs access to ProxyRef class
       
  2032                 Modules.addExports(jmxModule, packageOf(proxyRefCName), m);
       
  2033 
       
  2034                 // java.management needs to instantiate the fabricated RemoteRef class
       
  2035                 Modules.addReads(jmxModule, m);
       
  2036                 Modules.addExports(m, pkg, jmxModule);
       
  2037 
       
  2038                 Class<?> c = cl.loadClass(pRefClassName);
       
  2039                 return c.getConstructor(RemoteRef.class);
       
  2040             }
       
  2041         };
       
  2042 
       
  2043         Class<?> serverStubClass;
       
  2044         try {
       
  2045             serverStubClass = Class.forName(rmiServerImplStubClassName);
       
  2046         } catch (Exception e) {
       
  2047             logger.error("<clinit>",
       
  2048                     "Failed to instantiate " +
       
  2049                     rmiServerImplStubClassName + ": " + e);
       
  2050             logger.debug("<clinit>",e);
       
  2051             serverStubClass = null;
       
  2052         }
       
  2053         rmiServerImplStubClass = serverStubClass;
       
  2054 
       
  2055         Class<?> stubClass;
       
  2056         Constructor<?> constr;
       
  2057         try {
       
  2058             stubClass = Class.forName(rmiConnectionImplStubClassName);
       
  2059             constr = (Constructor<?>) AccessController.doPrivileged(action);
       
  2060         } catch (Exception e) {
       
  2061             logger.error("<clinit>",
       
  2062                     "Failed to initialize proxy reference constructor "+
       
  2063                     "for " + rmiConnectionImplStubClassName + ": " + e);
       
  2064             logger.debug("<clinit>",e);
       
  2065             stubClass = null;
       
  2066             constr = null;
       
  2067         }
       
  2068         rmiConnectionImplStubClass = stubClass;
       
  2069         proxyRefConstructor = constr;
       
  2070     }
       
  2071 
       
  2072     private static String packageOf(String cn) {
       
  2073         int i = cn.lastIndexOf('.');
       
  2074         return i > 0 ? cn.substring(0, i) : "";
       
  2075     }
       
  2076 
       
  2077     private static RMIConnection shadowJrmpStub(RemoteObject stub)
       
  2078     throws InstantiationException, IllegalAccessException,
       
  2079             InvocationTargetException, ClassNotFoundException,
       
  2080             NoSuchMethodException {
       
  2081         RemoteRef ref = stub.getRef();
       
  2082         RemoteRef proxyRef = (RemoteRef)
       
  2083             proxyRefConstructor.newInstance(new Object[] {ref});
       
  2084         final Constructor<?> rmiConnectionImplStubConstructor =
       
  2085             rmiConnectionImplStubClass.getConstructor(RemoteRef.class);
       
  2086         Object[] args = {proxyRef};
       
  2087         RMIConnection proxyStub = (RMIConnection)
       
  2088         rmiConnectionImplStubConstructor.newInstance(args);
       
  2089         return proxyStub;
       
  2090     }
       
  2091 
       
  2092     private static RMIConnection getConnection(RMIServer server,
       
  2093             Object credentials,
       
  2094             boolean checkStub)
       
  2095             throws IOException {
       
  2096         RMIConnection c = server.newClient(credentials);
       
  2097         if (checkStub) checkStub(c, rmiConnectionImplStubClass);
       
  2098         try {
       
  2099             if (c.getClass() == rmiConnectionImplStubClass)
       
  2100                 return shadowJrmpStub((RemoteObject) c);
       
  2101             logger.trace("getConnection",
       
  2102                     "Did not wrap " + c.getClass() + " to foil " +
       
  2103                     "stack search for classes: class loading semantics " +
       
  2104                     "may be incorrect");
       
  2105         } catch (Exception e) {
       
  2106             logger.error("getConnection",
       
  2107                     "Could not wrap " + c.getClass() + " to foil " +
       
  2108                     "stack search for classes: class loading semantics " +
       
  2109                     "may be incorrect: " + e);
       
  2110             logger.debug("getConnection",e);
       
  2111             // so just return the original stub, which will work for all
       
  2112             // but the most exotic class loading situations
       
  2113         }
       
  2114         return c;
       
  2115     }
       
  2116 
       
  2117     private static byte[] base64ToByteArray(String s) {
       
  2118         int sLen = s.length();
       
  2119         int numGroups = sLen/4;
       
  2120         if (4*numGroups != sLen)
       
  2121             throw new IllegalArgumentException(
       
  2122                     "String length must be a multiple of four.");
       
  2123         int missingBytesInLastGroup = 0;
       
  2124         int numFullGroups = numGroups;
       
  2125         if (sLen != 0) {
       
  2126             if (s.charAt(sLen-1) == '=') {
       
  2127                 missingBytesInLastGroup++;
       
  2128                 numFullGroups--;
       
  2129             }
       
  2130             if (s.charAt(sLen-2) == '=')
       
  2131                 missingBytesInLastGroup++;
       
  2132         }
       
  2133         byte[] result = new byte[3*numGroups - missingBytesInLastGroup];
       
  2134 
       
  2135         // Translate all full groups from base64 to byte array elements
       
  2136         int inCursor = 0, outCursor = 0;
       
  2137         for (int i=0; i<numFullGroups; i++) {
       
  2138             int ch0 = base64toInt(s.charAt(inCursor++));
       
  2139             int ch1 = base64toInt(s.charAt(inCursor++));
       
  2140             int ch2 = base64toInt(s.charAt(inCursor++));
       
  2141             int ch3 = base64toInt(s.charAt(inCursor++));
       
  2142             result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
       
  2143             result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
       
  2144             result[outCursor++] = (byte) ((ch2 << 6) | ch3);
       
  2145         }
       
  2146 
       
  2147         // Translate partial group, if present
       
  2148         if (missingBytesInLastGroup != 0) {
       
  2149             int ch0 = base64toInt(s.charAt(inCursor++));
       
  2150             int ch1 = base64toInt(s.charAt(inCursor++));
       
  2151             result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
       
  2152 
       
  2153             if (missingBytesInLastGroup == 1) {
       
  2154                 int ch2 = base64toInt(s.charAt(inCursor++));
       
  2155                 result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
       
  2156             }
       
  2157         }
       
  2158         // assert inCursor == s.length()-missingBytesInLastGroup;
       
  2159         // assert outCursor == result.length;
       
  2160         return result;
       
  2161     }
       
  2162 
       
  2163     /**
       
  2164      * Translates the specified character, which is assumed to be in the
       
  2165      * "Base 64 Alphabet" into its equivalent 6-bit positive integer.
       
  2166      *
       
  2167      * @throws IllegalArgumentException if
       
  2168      *        c is not in the Base64 Alphabet.
       
  2169      */
       
  2170     private static int base64toInt(char c) {
       
  2171         int result;
       
  2172 
       
  2173         if (c >= base64ToInt.length)
       
  2174             result = -1;
       
  2175         else
       
  2176             result = base64ToInt[c];
       
  2177 
       
  2178         if (result < 0)
       
  2179             throw new IllegalArgumentException("Illegal character " + c);
       
  2180         return result;
       
  2181     }
       
  2182 
       
  2183     /**
       
  2184      * This array is a lookup table that translates unicode characters
       
  2185      * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
       
  2186      * into their 6-bit positive integer equivalents.  Characters that
       
  2187      * are not in the Base64 alphabet but fall within the bounds of the
       
  2188      * array are translated to -1.
       
  2189      */
       
  2190     private static final byte base64ToInt[] = {
       
  2191         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
       
  2192         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
       
  2193         -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
       
  2194         55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
       
  2195         5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
       
  2196         24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
       
  2197         35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
       
  2198     };
       
  2199 
       
  2200     //--------------------------------------------------------------------
       
  2201     // Private stuff - Find / Set default class loader
       
  2202     //--------------------------------------------------------------------
       
  2203     private ClassLoader pushDefaultClassLoader() {
       
  2204         final Thread t = Thread.currentThread();
       
  2205         final ClassLoader old =  t.getContextClassLoader();
       
  2206         if (defaultClassLoader != null)
       
  2207             AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
  2208                 public Void run() {
       
  2209                     t.setContextClassLoader(defaultClassLoader);
       
  2210                     return null;
       
  2211                 }
       
  2212             });
       
  2213             return old;
       
  2214     }
       
  2215 
       
  2216     private void popDefaultClassLoader(final ClassLoader old) {
       
  2217         AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
  2218             public Void run() {
       
  2219                 Thread.currentThread().setContextClassLoader(old);
       
  2220                 return null;
       
  2221             }
       
  2222         });
       
  2223     }
       
  2224 
       
  2225     //--------------------------------------------------------------------
       
  2226     // Private variables
       
  2227     //--------------------------------------------------------------------
       
  2228     /**
       
  2229      * @serial The RMIServer stub of the RMI JMX Connector server to
       
  2230      * which this client connector is (or will be) connected. This
       
  2231      * field can be null when <var>jmxServiceURL</var> is not
       
  2232      * null. This includes the case where <var>jmxServiceURL</var>
       
  2233      * contains a serialized RMIServer stub. If both
       
  2234      * <var>rmiServer</var> and <var>jmxServiceURL</var> are null then
       
  2235      * serialization will fail.
       
  2236      *
       
  2237      * @see #RMIConnector(RMIServer,Map)
       
  2238      **/
       
  2239     private final RMIServer rmiServer;
       
  2240 
       
  2241     /**
       
  2242      * @serial The JMXServiceURL of the RMI JMX Connector server to
       
  2243      * which this client connector will be connected. This field can
       
  2244      * be null when <var>rmiServer</var> is not null. If both
       
  2245      * <var>rmiServer</var> and <var>jmxServiceURL</var> are null then
       
  2246      * serialization will fail.
       
  2247      *
       
  2248      * @see #RMIConnector(JMXServiceURL,Map)
       
  2249      **/
       
  2250     private final JMXServiceURL jmxServiceURL;
       
  2251 
       
  2252     // ---------------------------------------------------------
       
  2253     // WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
       
  2254     // ---------------------------------------------------------
       
  2255     // Any transient variable which needs to be initialized should
       
  2256     // be initialized in the method initTransient()
       
  2257     private transient Map<String, Object> env;
       
  2258     private transient ClassLoader defaultClassLoader;
       
  2259     private transient RMIConnection connection;
       
  2260     private transient String connectionId;
       
  2261 
       
  2262     private transient long clientNotifSeqNo = 0;
       
  2263 
       
  2264     private transient WeakHashMap<Subject, WeakReference<MBeanServerConnection>> rmbscMap;
       
  2265     private transient WeakReference<MBeanServerConnection> nullSubjectConnRef = null;
       
  2266 
       
  2267     private transient RMINotifClient rmiNotifClient;
       
  2268     // = new RMINotifClient(new Integer(0));
       
  2269 
       
  2270     private transient long clientNotifCounter = 0;
       
  2271 
       
  2272     private transient boolean connected;
       
  2273     // = false;
       
  2274     private transient boolean terminated;
       
  2275     // = false;
       
  2276 
       
  2277     private transient Exception closeException;
       
  2278 
       
  2279     private transient NotificationBroadcasterSupport connectionBroadcaster;
       
  2280 
       
  2281     private transient ClientCommunicatorAdmin communicatorAdmin;
       
  2282 
       
  2283     /**
       
  2284      * A static WeakReference to an {@link org.omg.CORBA.ORB ORB} to
       
  2285      * connect unconnected stubs.
       
  2286      **/
       
  2287     private static volatile WeakReference<Object> orb = null;
       
  2288 
       
  2289     // TRACES & DEBUG
       
  2290     //---------------
       
  2291     private static String objects(final Object[] objs) {
       
  2292         if (objs == null)
       
  2293             return "null";
       
  2294         else
       
  2295             return Arrays.asList(objs).toString();
       
  2296     }
       
  2297 
       
  2298     private static String strings(final String[] strs) {
       
  2299         return objects(strs);
       
  2300     }
       
  2301 
       
  2302     static String getAttributesNames(AttributeList attributes) {
       
  2303         return attributes != null ?
       
  2304                 attributes.asList().stream()
       
  2305                         .map(Attribute::getName)
       
  2306                         .collect(Collectors.joining(", ", "[", "]"))
       
  2307                 : "[]";
       
  2308     }
       
  2309 }