changeset 43503:bc7f8619ab70

8173607: JMX RMI connector should be in its own module Summary: The JMX RMI connector is moved to a new java.management.rmi module. Reviewed-by: mchung, erikj
author dfuchs
date Thu, 02 Feb 2017 16:50:46 +0000
parents aec39566b45e
children 937634498e8c dbb07ad63c71
files jdk/make/rmic/Rmic-java.management.gmk jdk/make/rmic/Rmic-java.management.rmi.gmk jdk/src/java.base/share/classes/module-info.java jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/ProxyRef.java jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/Unmarshal.java jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/protocol/rmi/ClientProvider.java jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/protocol/rmi/ServerProvider.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/NoCallStackClassLoader.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIIIOPServerImpl.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServer.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html jdk/src/java.management.rmi/share/classes/module-info.java jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ProxyRef.java jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/RMIExporter.java jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/Unmarshal.java jdk/src/java.management/share/classes/com/sun/jmx/remote/protocol/rmi/ClientProvider.java jdk/src/java.management/share/classes/com/sun/jmx/remote/protocol/rmi/ServerProvider.java jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorServerFactory.java jdk/src/java.management/share/classes/javax/management/remote/rmi/NoCallStackClassLoader.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnection.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIIIOPServerImpl.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIServer.java jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIServerImpl.java jdk/src/java.management/share/classes/javax/management/remote/rmi/package.html jdk/src/java.management/share/classes/module-info.java jdk/src/java.rmi/share/classes/module-info.java jdk/src/java.se/share/classes/module-info.java jdk/src/jdk.jconsole/share/classes/module-info.java jdk/src/jdk.management.agent/share/classes/module-info.java jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java jdk/test/javax/management/MBeanServer/ExceptionTest.java jdk/test/javax/management/MBeanServer/OldMBeanServerTest.java jdk/test/javax/management/modelmbean/UnserializableTargetObjectTest.java jdk/test/javax/management/mxbean/GenericArrayTypeTest.java jdk/test/javax/management/mxbean/MXBeanExceptionHandlingTest.java jdk/test/javax/management/mxbean/MXBeanInteropTest1.java jdk/test/javax/management/mxbean/MXBeanInteropTest2.java jdk/test/javax/management/mxbean/MXBeanNotifTest.java jdk/test/javax/management/mxbean/MXBeanTest.java jdk/test/javax/management/mxbean/MXBeanWeirdParamTest.java jdk/test/javax/management/query/SupportedQueryTypesTest.java jdk/test/javax/management/remote/mandatory/connection/AddressableTest.java jdk/test/javax/management/remote/mandatory/connection/BrokenConnectionTest.java jdk/test/javax/management/remote/mandatory/connection/CloseableTest.java jdk/test/javax/management/remote/mandatory/connection/ConnectionListenerNullTest.java jdk/test/javax/management/remote/mandatory/connection/ConnectionTest.java jdk/test/javax/management/remote/mandatory/connection/DaemonRMIExporterTest.java jdk/test/javax/management/remote/mandatory/connection/GetConnectionTest.java jdk/test/javax/management/remote/mandatory/connection/IIOPURLTest.java jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java jdk/test/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java jdk/test/javax/management/remote/mandatory/connection/RMIExitTest.java jdk/test/javax/management/remote/mandatory/connection/RMISerializeTest.java jdk/test/javax/management/remote/mandatory/connectorServer/ConnectorStopDeadlockTest.java jdk/test/javax/management/remote/mandatory/connectorServer/JNDIFailureTest.java jdk/test/javax/management/remote/mandatory/connectorServer/MBSFPreStartPostStartTest.java jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java jdk/test/javax/management/remote/mandatory/loading/DeserializeEncodedURLTest.java jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java jdk/test/javax/management/remote/mandatory/loading/RMIDownloadTest.java jdk/test/javax/management/remote/mandatory/loading/TargetMBeanTest.java jdk/test/javax/management/remote/mandatory/notif/ConcurrentModificationTest.java jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java jdk/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java jdk/test/javax/management/remote/mandatory/notif/NotSerializableNotifTest.java jdk/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java jdk/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java jdk/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java jdk/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java jdk/test/javax/management/remote/mandatory/notif/RMINotifTest.java jdk/test/javax/management/remote/mandatory/notif/ServerNotifs.java jdk/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java jdk/test/javax/management/remote/mandatory/passwordAccessFile/NonJMXPrincipalsTest.java jdk/test/javax/management/remote/mandatory/passwordAccessFile/PasswordAccessFileTest.java jdk/test/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java jdk/test/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java jdk/test/javax/management/remote/mandatory/serverError/JMXServerErrorTest.java jdk/test/javax/management/remote/mandatory/socketFactories/RMISocketFactoriesTest.java jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java jdk/test/javax/management/remote/mandatory/util/MapNullValuesTest.java jdk/test/javax/management/security/AuthorizationTest.java jdk/test/javax/management/security/SecurityTest.java jdk/test/sun/management/jmxremote/bootstrap/TestManager.java jdk/test/tools/launcher/modules/listmods/ListModsTest.java
diffstat 107 files changed, 8523 insertions(+), 8218 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/make/rmic/Rmic-java.management.gmk	Thu Feb 02 12:28:23 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-default: all
-
-include RmicCommon.gmk
-
-##########################################################################################
-#
-# Generate RMI stubs
-#
-
-JMX_RMI_CLASSES := javax.management.remote.rmi.RMIConnectionImpl \
-    javax.management.remote.rmi.RMIServerImpl
-
-# Generate into gensrc dir where sources get picked up for javadoc, then move the classes
-# into the stub classes dir.
-$(eval $(call SetupRMICompilation,RMI_GEN, \
-    CLASSES := $(JMX_RMI_CLASSES), \
-    CLASSES_DIR := $(CLASSES_DIR)/java.management, \
-    STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR)/java.management, \
-    RUN_V12 := true, \
-    KEEP_GENERATED := true, \
-))
-
-# Find all classes generated and move them from the gensrc dir to the stub classes dir
-$(RMIC_GENSRC_DIR)/_classes.moved: $(RMI_GEN)
-	$(eval classfiles := $(shell $(FIND) $(RMIC_GENSRC_DIR) -name "*.class"))
-	$(foreach src, $(classfiles), \
-	    $(eval target := $(patsubst $(RMIC_GENSRC_DIR)/%, \
-	        $(STUB_CLASSES_DIR)/%, $(src))) \
-	    $(MKDIR) -p $(dir $(target)) ; \
-	    $(MV) $(src) $(target) $(NEWLINE))
-	$(TOUCH) $@
-
-##########################################################################################
-
-all: $(RMIC_GENSRC_DIR)/_classes.moved $(RMI_GEN)
-
-.PHONY: all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/rmic/Rmic-java.management.rmi.gmk	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+default: all
+
+include RmicCommon.gmk
+
+##########################################################################################
+#
+# Generate RMI stubs
+#
+
+JMX_RMI_CLASSES := javax.management.remote.rmi.RMIConnectionImpl \
+    javax.management.remote.rmi.RMIServerImpl
+
+# Generate into gensrc dir where sources get picked up for javadoc, then move the classes
+# into the stub classes dir.
+$(eval $(call SetupRMICompilation,RMI_GEN, \
+    CLASSES := $(JMX_RMI_CLASSES), \
+    CLASSES_DIR := $(CLASSES_DIR)/java.management.rmi, \
+    STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR)/java.management.rmi, \
+    RUN_V12 := true, \
+    KEEP_GENERATED := true, \
+))
+
+# Find all classes generated and move them from the gensrc dir to the stub classes dir
+$(RMIC_GENSRC_DIR)/_classes.moved: $(RMI_GEN)
+	$(eval classfiles := $(shell $(FIND) $(RMIC_GENSRC_DIR) -name "*.class"))
+	$(foreach src, $(classfiles), \
+	    $(eval target := $(patsubst $(RMIC_GENSRC_DIR)/%, \
+	        $(STUB_CLASSES_DIR)/%, $(src))) \
+	    $(MKDIR) -p $(dir $(target)) ; \
+	    $(MV) $(src) $(target) $(NEWLINE))
+	$(TOUCH) $@
+
+##########################################################################################
+
+all: $(RMIC_GENSRC_DIR)/_classes.moved $(RMI_GEN)
+
+.PHONY: all
--- a/jdk/src/java.base/share/classes/module-info.java	Thu Feb 02 12:28:23 2017 +0100
+++ b/jdk/src/java.base/share/classes/module-info.java	Thu Feb 02 16:50:46 2017 +0000
@@ -150,7 +150,7 @@
         java.desktop;
     exports jdk.internal.module to
         java.instrument,
-        java.management,
+        java.management.rmi,
         jdk.jartool,
         jdk.jlink;
     exports jdk.internal.misc to
@@ -235,6 +235,7 @@
         java.desktop,
         java.datatransfer,
         java.management,
+        java.management.rmi,
         java.rmi,
         java.sql.rowset,
         java.xml,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/ProxyRef.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jmx.remote.internal.rmi;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.Method;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.RemoteObject;
+import java.rmi.server.RemoteRef;
+
+
+@SuppressWarnings("deprecation")
+public class ProxyRef implements RemoteRef {
+    private static final long serialVersionUID = -6503061366316814723L;
+
+    public ProxyRef(RemoteRef ref) {
+        this.ref = ref;
+    }
+
+    public void readExternal(ObjectInput in)
+            throws IOException, ClassNotFoundException {
+        ref.readExternal(in);
+    }
+
+    public void writeExternal(ObjectOutput out) throws IOException {
+        ref.writeExternal(out);
+    }
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public void invoke(java.rmi.server.RemoteCall call) throws Exception {
+        ref.invoke(call);
+    }
+
+    public Object invoke(Remote obj, Method method, Object[] params,
+                         long opnum) throws Exception {
+        return ref.invoke(obj, method, params, opnum);
+    }
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public void done(java.rmi.server.RemoteCall call) throws RemoteException {
+        ref.done(call);
+    }
+
+    public String getRefClass(ObjectOutput out) {
+        return ref.getRefClass(out);
+    }
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public java.rmi.server.RemoteCall newCall(RemoteObject obj,
+            java.rmi.server.Operation[] op, int opnum,
+                              long hash) throws RemoteException {
+        return ref.newCall(obj, op, opnum, hash);
+    }
+
+    public boolean remoteEquals(RemoteRef obj) {
+        return ref.remoteEquals(obj);
+    }
+
+    public int remoteHashCode() {
+        return ref.remoteHashCode();
+    }
+
+    public String remoteToString() {
+        return ref.remoteToString();
+    }
+
+    protected RemoteRef ref;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jmx.remote.internal.rmi;
+
+import java.rmi.NoSuchObjectException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+ * <p>Unpublished interface controlling how the RMI Connector Server
+ * exports objects.  The RMIServerImpl object and each
+ * RMIConnectionImpl object are exported using the exporter.  The
+ * default exporter calls {@link
+ * UnicastRemoteObject#exportObject(Remote, int,
+ * RMIClientSocketFactory, RMIServerSocketFactory)} to export objects
+ * and {@link UnicastRemoteObject#unexportObject(Remote, boolean)} to
+ * unexport them.  A replacement exporter can be specified via the
+ * {@link #EXPORTER_ATTRIBUTE} property in the environment Map passed
+ * to the RMI connector server.</p>
+ */
+public interface RMIExporter {
+    public static final String EXPORTER_ATTRIBUTE =
+        "com.sun.jmx.remote.rmi.exporter";
+
+    public Remote exportObject(Remote obj,
+                               int port,
+                               RMIClientSocketFactory csf,
+                               RMIServerSocketFactory ssf)
+            throws RemoteException;
+
+    public boolean unexportObject(Remote obj, boolean force)
+            throws NoSuchObjectException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/Unmarshal.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jmx.remote.internal.rmi;
+
+import java.io.IOException;
+import java.rmi.MarshalledObject;
+
+public interface Unmarshal {
+    public Object get(MarshalledObject<?> mo)
+            throws IOException, ClassNotFoundException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/protocol/rmi/ClientProvider.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jmx.remote.protocol.rmi;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+import javax.management.remote.JMXConnectorProvider;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnector;
+
+public class ClientProvider implements JMXConnectorProvider {
+
+    public JMXConnector newJMXConnector(JMXServiceURL serviceURL,
+                                        Map<String,?> environment)
+            throws IOException {
+        if (!serviceURL.getProtocol().equals("rmi")) {
+            throw new MalformedURLException("Protocol not rmi: " +
+                                            serviceURL.getProtocol());
+        }
+        return new RMIConnector(serviceURL, environment);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/protocol/rmi/ServerProvider.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.jmx.remote.protocol.rmi;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerProvider;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
+
+public class ServerProvider implements JMXConnectorServerProvider {
+
+    public JMXConnectorServer newJMXConnectorServer(JMXServiceURL serviceURL,
+                                                    Map<String,?> environment,
+                                                    MBeanServer mbeanServer)
+            throws IOException {
+        if (!serviceURL.getProtocol().equals("rmi")) {
+            throw new MalformedURLException("Protocol not rmi: " +
+                                            serviceURL.getProtocol());
+        }
+        return new RMIConnectorServer(serviceURL, environment, mbeanServer);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/NoCallStackClassLoader.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import java.security.ProtectionDomain;
+
+/**
+    <p>A class loader that only knows how to define a limited number
+    of classes, and load a limited number of other classes through
+    delegation to another loader.  It is used to get around a problem
+    with Serialization, in particular as used by RMI. The JMX Remote API
+    defines exactly what class loader must be used to deserialize arguments on
+    the server, and return values on the client.  We communicate this class
+    loader to RMI by setting it as the context class loader.  RMI uses the
+    context class loader to load classes as it deserializes, which is what we
+    want.  However, before consulting the context class loader, it
+    looks up the call stack for a class with a non-null class loader,
+    and uses that if it finds one.  So, in the standalone version of
+    javax.management.remote, if the class you're looking for is known
+    to the loader of jmxremote.jar (typically the system class loader)
+    then that loader will load it.  This contradicts the class-loading
+    semantics required.
+
+    <p>We get around the problem by ensuring that the search up the
+    call stack will find a non-null class loader that doesn't load any
+    classes of interest, namely this one.  So even though this loader
+    is indeed consulted during deserialization, it never finds the
+    class being deserialized.  RMI then proceeds to use the context
+    class loader, as we require.
+
+    <p>This loader is constructed with the name and byte-code of one
+    or more classes that it defines, and a class-loader to which it
+    will delegate certain other classes required by that byte-code.
+    We construct the byte-code somewhat painstakingly, by compiling
+    the Java code directly, converting into a string, copying that
+    string into the class that needs this loader, and using the
+    stringToBytes method to convert it into the byte array.  We
+    compile with -g:none because there's not much point in having
+    line-number information and the like in these directly-encoded
+    classes.
+
+    <p>The referencedClassNames should contain the names of all
+    classes that are referenced by the classes defined by this loader.
+    It is not necessary to include standard J2SE classes, however.
+    Here, a class is referenced if it is the superclass or a
+    superinterface of a defined class, or if it is the type of a
+    field, parameter, or return value.  A class is not referenced if
+    it only appears in the throws clause of a method or constructor.
+    Of course, referencedClassNames should not contain any classes
+    that the user might want to deserialize, because the whole point
+    of this loader is that it does not find such classes.
+*/
+
+class NoCallStackClassLoader extends ClassLoader {
+    /** Simplified constructor when this loader only defines one class.  */
+    public NoCallStackClassLoader(String className,
+                                  byte[] byteCode,
+                                  String[] referencedClassNames,
+                                  ClassLoader referencedClassLoader,
+                                  ProtectionDomain protectionDomain) {
+        this(new String[] {className}, new byte[][] {byteCode},
+             referencedClassNames, referencedClassLoader, protectionDomain);
+    }
+
+    public NoCallStackClassLoader(String[] classNames,
+                                  byte[][] byteCodes,
+                                  String[] referencedClassNames,
+                                  ClassLoader referencedClassLoader,
+                                  ProtectionDomain protectionDomain) {
+        super(null);
+
+        /* Validation. */
+        if (classNames == null || classNames.length == 0
+            || byteCodes == null || classNames.length != byteCodes.length
+            || referencedClassNames == null || protectionDomain == null)
+            throw new IllegalArgumentException();
+        for (int i = 0; i < classNames.length; i++) {
+            if (classNames[i] == null || byteCodes[i] == null)
+                throw new IllegalArgumentException();
+        }
+        for (int i = 0; i < referencedClassNames.length; i++) {
+            if (referencedClassNames[i] == null)
+                throw new IllegalArgumentException();
+        }
+
+        this.classNames = classNames;
+        this.byteCodes = byteCodes;
+        this.referencedClassNames = referencedClassNames;
+        this.referencedClassLoader = referencedClassLoader;
+        this.protectionDomain = protectionDomain;
+    }
+
+    /* This method is called at most once per name.  Define the name
+     * if it is one of the classes whose byte code we have, or
+     * delegate the load if it is one of the referenced classes.
+     */
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        // Note: classNames is guaranteed by the constructor to be non-null.
+        for (int i = 0; i < classNames.length; i++) {
+            if (name.equals(classNames[i])) {
+                return defineClass(classNames[i], byteCodes[i], 0,
+                                   byteCodes[i].length, protectionDomain);
+            }
+        }
+
+        /* If the referencedClassLoader is null, it is the bootstrap
+         * class loader, and there's no point in delegating to it
+         * because it's already our parent class loader.
+         */
+        if (referencedClassLoader != null) {
+            for (int i = 0; i < referencedClassNames.length; i++) {
+                if (name.equals(referencedClassNames[i]))
+                    return referencedClassLoader.loadClass(name);
+            }
+        }
+
+        throw new ClassNotFoundException(name);
+    }
+
+    private final String[] classNames;
+    private final byte[][] byteCodes;
+    private final String[] referencedClassNames;
+    private final ClassLoader referencedClassLoader;
+    private final ProtectionDomain protectionDomain;
+
+    /**
+     * <p>Construct a <code>byte[]</code> using the characters of the
+     * given <code>String</code>.  Only the low-order byte of each
+     * character is used.  This method is useful to reduce the
+     * footprint of classes that include big byte arrays (e.g. the
+     * byte code of other classes), because a string takes up much
+     * less space in a class file than the byte code to initialize a
+     * <code>byte[]</code> with the same number of bytes.</p>
+     *
+     * <p>We use just one byte per character even though characters
+     * contain two bytes.  The resultant output length is much the
+     * same: using one byte per character is shorter because it has
+     * more characters in the optimal 1-127 range but longer because
+     * it has more zero bytes (which are frequent, and are encoded as
+     * two bytes in classfile UTF-8).  But one byte per character has
+     * two key advantages: (1) you can see the string constants, which
+     * is reassuring, (2) you don't need to know whether the class
+     * file length is odd.</p>
+     *
+     * <p>This method differs from {@link String#getBytes()} in that
+     * it does not use any encoding.  So it is guaranteed that each
+     * byte of the result is numerically identical (mod 256) to the
+     * corresponding character of the input.
+     */
+    public static byte[] stringToBytes(String s) {
+        final int slen = s.length();
+        byte[] bytes = new byte[slen];
+        for (int i = 0; i < slen; i++)
+            bytes[i] = (byte) s.charAt(i);
+        return bytes;
+    }
+}
+
+/*
+
+You can use the following Emacs function to convert class files into
+strings to be used by the stringToBytes method above.  Select the
+whole (defun...) with the mouse and type M-x eval-region, or save it
+to a file and do M-x load-file.  Then visit the *.class file and do
+M-x class-string.
+
+;; class-string.el
+;; visit the *.class file with emacs, then invoke this function
+
+(defun class-string ()
+  "Construct a Java string whose bytes are the same as the current
+buffer.  The resultant string is put in a buffer called *string*,
+possibly with a numeric suffix like <2>.  From there it can be
+insert-buffer'd into a Java program."
+  (interactive)
+  (let* ((s (buffer-string))
+         (slen (length s))
+         (i 0)
+         (buf (generate-new-buffer "*string*")))
+    (set-buffer buf)
+    (insert "\"")
+    (while (< i slen)
+      (if (> (current-column) 61)
+          (insert "\"+\n\""))
+      (let ((c (aref s i)))
+        (insert (cond
+                 ((> c 126) (format "\\%o" c))
+                 ((= c ?\") "\\\"")
+                 ((= c ?\\) "\\\\")
+                 ((< c 33)
+                  (let ((nextc (if (< (1+ i) slen)
+                                   (aref s (1+ i))
+                                 ?\0)))
+                    (cond
+                     ((and (<= nextc ?7) (>= nextc ?0))
+                      (format "\\%03o" c))
+                     (t
+                      (format "\\%o" c)))))
+                 (t c))))
+      (setq i (1+ i)))
+    (insert "\"")
+    (switch-to-buffer buf)))
+
+Alternatively, the following class reads a class file and outputs a string
+that can be used by the stringToBytes method above.
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+public class BytesToString {
+
+    public static void main(String[] args) throws IOException {
+        File f = new File(args[0]);
+        int len = (int)f.length();
+        byte[] classBytes = new byte[len];
+
+        FileInputStream in = new FileInputStream(args[0]);
+        try {
+            int pos = 0;
+            for (;;) {
+                int n = in.read(classBytes, pos, (len-pos));
+                if (n < 0)
+                    throw new RuntimeException("class file changed??");
+                pos += n;
+                if (pos >= n)
+                    break;
+            }
+        } finally {
+            in.close();
+        }
+
+        int pos = 0;
+        boolean lastWasOctal = false;
+        for (int i=0; i<len; i++) {
+            int value = classBytes[i];
+            if (value < 0)
+                value += 256;
+            String s = null;
+            if (value == '\\')
+                s = "\\\\";
+            else if (value == '\"')
+                s = "\\\"";
+            else {
+                if ((value >= 32 && value < 127) && ((!lastWasOctal ||
+                    (value < '0' || value > '7')))) {
+                    s = Character.toString((char)value);
+                }
+            }
+            if (s == null) {
+                s = "\\" + Integer.toString(value, 8);
+                lastWasOctal = true;
+            } else {
+                lastWasOctal = false;
+            }
+            if (pos > 61) {
+                System.out.print("\"");
+                if (i<len)
+                    System.out.print("+");
+                System.out.println();
+                pos = 0;
+            }
+            if (pos == 0)
+                System.out.print("                \"");
+            System.out.print(s);
+            pos += s.length();
+        }
+        System.out.println("\"");
+    }
+}
+
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.rmi.MarshalledObject;
+import java.rmi.Remote;
+import java.util.Set;
+
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServerConnection;
+import javax.management.NotCompliantMBeanException;
+
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import javax.management.RuntimeOperationsException;
+import javax.management.remote.NotificationResult;
+import javax.security.auth.Subject;
+
+/**
+ * <p>RMI object used to forward an MBeanServer request from a client
+ * to its MBeanServer implementation on the server side.  There is one
+ * Remote object implementing this interface for each remote client
+ * connected to an RMI connector.</p>
+ *
+ * <p>User code does not usually refer to this interface.  It is
+ * specified as part of the public API so that different
+ * implementations of that API will interoperate.</p>
+ *
+ * <p>To ensure that client parameters will be deserialized at the
+ * server side with the correct classloader, client parameters such as
+ * parameters used to invoke a method are wrapped in a {@link
+ * MarshalledObject}.  An implementation of this interface must first
+ * get the appropriate class loader for the operation and its target,
+ * then deserialize the marshalled parameters with this classloader.
+ * Except as noted, a parameter that is a
+ * <code>MarshalledObject</code> or <code>MarshalledObject[]</code>
+ * must not be null; the behavior is unspecified if it is.</p>
+ *
+ * <p>Class loading aspects are detailed in the
+ * <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
+ * JMX Specification, version 1.4</a> PDF document.</p>
+ *
+ * <p>Most methods in this interface parallel methods in the {@link
+ * MBeanServerConnection} interface.  Where an aspect of the behavior
+ * of a method is not specified here, it is the same as in the
+ * corresponding <code>MBeanServerConnection</code> method.
+ *
+ * @since 1.5
+ */
+/*
+ * Notice that we omit the type parameter from MarshalledObject everywhere,
+ * even though it would add useful information to the documentation.  The
+ * reason is that it was only added in Mustang (Java SE 6), whereas versions
+ * 1.4 and 2.0 of the JMX API must be implementable on Tiger per our
+ * commitments for JSR 255.  This is also why we suppress rawtypes warnings.
+ */
+@SuppressWarnings("rawtypes")
+public interface RMIConnection extends Closeable, Remote {
+    /**
+     * <p>Returns the connection ID.  This string is different for
+     * every open connection to a given RMI connector server.</p>
+     *
+     * @return the connection ID
+     *
+     * @see RMIConnector#connect RMIConnector.connect
+     *
+     * @throws IOException if a general communication exception occurred.
+     */
+    public String getConnectionId() throws IOException;
+
+    /**
+     * <p>Closes this connection.  On return from this method, the RMI
+     * object implementing this interface is unexported, so further
+     * remote calls to it will fail.</p>
+     *
+     * @throws IOException if the connection could not be closed,
+     * or the Remote object could not be unexported, or there was a
+     * communication failure when transmitting the remote close
+     * request.
+     */
+    public void close() throws IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#createMBean(String,
+     * ObjectName)}.
+     *
+     * @param className The class name of the MBean to be instantiated.
+     * @param name The object name of the MBean. May be null.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return An <code>ObjectInstance</code>, containing the
+     * <code>ObjectName</code> and the Java class name of the newly
+     * instantiated MBean.  If the contained <code>ObjectName</code>
+     * is <code>n</code>, the contained Java class name is
+     * <code>{@link #getMBeanInfo getMBeanInfo(n)}.getClassName()</code>.
+     *
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.ClassNotFoundException</code> or a
+     * <code>java.lang.Exception</code> that occurred
+     * when trying to invoke the MBean's constructor.
+     * @throws InstanceAlreadyExistsException The MBean is already
+     * under the control of the MBean server.
+     * @throws MBeanRegistrationException The
+     * <code>preRegister</code> (<code>MBeanRegistration</code>
+     * interface) method of the MBean has thrown an exception. The
+     * MBean will not be registered.
+     * @throws MBeanException The constructor of the MBean has
+     * thrown an exception.
+     * @throws NotCompliantMBeanException This class is not a JMX
+     * compliant MBean.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The className
+     * passed in parameter is null, the <code>ObjectName</code> passed
+     * in parameter contains a pattern or no <code>ObjectName</code>
+     * is specified for the MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#createMBean(String,
+     * ObjectName, ObjectName)}.
+     *
+     * @param className The class name of the MBean to be instantiated.
+     * @param name The object name of the MBean. May be null.
+     * @param loaderName The object name of the class loader to be used.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return An <code>ObjectInstance</code>, containing the
+     * <code>ObjectName</code> and the Java class name of the newly
+     * instantiated MBean.  If the contained <code>ObjectName</code>
+     * is <code>n</code>, the contained Java class name is
+     * <code>{@link #getMBeanInfo getMBeanInfo(n)}.getClassName()</code>.
+     *
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.ClassNotFoundException</code> or a
+     * <code>java.lang.Exception</code> that occurred when trying to
+     * invoke the MBean's constructor.
+     * @throws InstanceAlreadyExistsException The MBean is already
+     * under the control of the MBean server.
+     * @throws MBeanRegistrationException The
+     * <code>preRegister</code> (<code>MBeanRegistration</code>
+     * interface) method of the MBean has thrown an exception. The
+     * MBean will not be registered.
+     * @throws MBeanException The constructor of the MBean has
+     * thrown an exception.
+     * @throws NotCompliantMBeanException This class is not a JMX
+     * compliant MBean.
+     * @throws InstanceNotFoundException The specified class loader
+     * is not registered in the MBean server.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The className
+     * passed in parameter is null, the <code>ObjectName</code> passed
+     * in parameter contains a pattern or no <code>ObjectName</code>
+     * is specified for the MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      ObjectName loaderName,
+                                      Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        InstanceNotFoundException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#createMBean(String,
+     * ObjectName, Object[], String[])}.  The <code>Object[]</code>
+     * parameter is wrapped in a <code>MarshalledObject</code>.
+     *
+     * @param className The class name of the MBean to be instantiated.
+     * @param name The object name of the MBean. May be null.
+     * @param params An array containing the parameters of the
+     * constructor to be invoked, encapsulated into a
+     * <code>MarshalledObject</code>.  The encapsulated array can be
+     * null, equivalent to an empty array.
+     * @param signature An array containing the signature of the
+     * constructor to be invoked.  Can be null, equivalent to an empty
+     * array.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return An <code>ObjectInstance</code>, containing the
+     * <code>ObjectName</code> and the Java class name of the newly
+     * instantiated MBean.  If the contained <code>ObjectName</code>
+     * is <code>n</code>, the contained Java class name is
+     * <code>{@link #getMBeanInfo getMBeanInfo(n)}.getClassName()</code>.
+     *
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.ClassNotFoundException</code> or a
+     * <code>java.lang.Exception</code> that occurred when trying to
+     * invoke the MBean's constructor.
+     * @throws InstanceAlreadyExistsException The MBean is already
+     * under the control of the MBean server.
+     * @throws MBeanRegistrationException The
+     * <code>preRegister</code> (<code>MBeanRegistration</code>
+     * interface) method of the MBean has thrown an exception. The
+     * MBean will not be registered.
+     * @throws MBeanException The constructor of the MBean has
+     * thrown an exception.
+     * @throws NotCompliantMBeanException This class is not a JMX
+     * compliant MBean.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The className
+     * passed in parameter is null, the <code>ObjectName</code> passed
+     * in parameter contains a pattern, or no <code>ObjectName</code>
+     * is specified for the MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public ObjectInstance createMBean(String className,
+                                ObjectName name,
+                                MarshalledObject params,
+                                String signature[],
+                                Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#createMBean(String,
+     * ObjectName, ObjectName, Object[], String[])}.  The
+     * <code>Object[]</code> parameter is wrapped in a
+     * <code>MarshalledObject</code>.
+     *
+     * @param className The class name of the MBean to be instantiated.
+     * @param name The object name of the MBean. May be null.
+     * @param loaderName The object name of the class loader to be used.
+     * @param params An array containing the parameters of the
+     * constructor to be invoked, encapsulated into a
+     * <code>MarshalledObject</code>.  The encapsulated array can be
+     * null, equivalent to an empty array.
+     * @param signature An array containing the signature of the
+     * constructor to be invoked.  Can be null, equivalent to an empty
+     * array.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return An <code>ObjectInstance</code>, containing the
+     * <code>ObjectName</code> and the Java class name of the newly
+     * instantiated MBean.  If the contained <code>ObjectName</code>
+     * is <code>n</code>, the contained Java class name is
+     * <code>{@link #getMBeanInfo getMBeanInfo(n)}.getClassName()</code>.
+     *
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.ClassNotFoundException</code> or a
+     * <code>java.lang.Exception</code> that occurred when trying to
+     * invoke the MBean's constructor.
+     * @throws InstanceAlreadyExistsException The MBean is already
+     * under the control of the MBean server.
+     * @throws MBeanRegistrationException The
+     * <code>preRegister</code> (<code>MBeanRegistration</code>
+     * interface) method of the MBean has thrown an exception. The
+     * MBean will not be registered.
+     * @throws MBeanException The constructor of the MBean has
+     * thrown an exception.
+     * @throws NotCompliantMBeanException This class is not a JMX
+     * compliant MBean.
+     * @throws InstanceNotFoundException The specified class loader
+     * is not registered in the MBean server.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The className
+     * passed in parameter is null, the <code>ObjectName</code> passed
+     * in parameter contains a pattern, or no <code>ObjectName</code>
+     * is specified for the MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public ObjectInstance createMBean(String className,
+                                ObjectName name,
+                                ObjectName loaderName,
+                                MarshalledObject params,
+                                String signature[],
+                                Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        InstanceNotFoundException,
+        IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#unregisterMBean(ObjectName)}.
+     *
+     * @param name The object name of the MBean to be unregistered.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws MBeanRegistrationException The preDeregister
+     * ((<code>MBeanRegistration</code> interface) method of the MBean
+     * has thrown an exception.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null or the MBean you are when trying to
+     * unregister is the {@link javax.management.MBeanServerDelegate
+     * MBeanServerDelegate} MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public void unregisterMBean(ObjectName name, Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        MBeanRegistrationException,
+        IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#getObjectInstance(ObjectName)}.
+     *
+     * @param name The object name of the MBean.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return The <code>ObjectInstance</code> associated with the MBean
+     * specified by <var>name</var>.  The contained <code>ObjectName</code>
+     * is <code>name</code> and the contained class name is
+     * <code>{@link #getMBeanInfo getMBeanInfo(name)}.getClassName()</code>.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public ObjectInstance getObjectInstance(ObjectName name,
+                                            Subject delegationSubject)
+        throws InstanceNotFoundException, IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#queryMBeans(ObjectName,
+     * QueryExp)}.  The <code>QueryExp</code> is wrapped in a
+     * <code>MarshalledObject</code>.
+     *
+     * @param name The object name pattern identifying the MBeans to
+     * be retrieved. If null or no domain and key properties are
+     * specified, all the MBeans registered will be retrieved.
+     * @param query The query expression to be applied for selecting
+     * MBeans, encapsulated into a <code>MarshalledObject</code>. If
+     * the <code>MarshalledObject</code> encapsulates a null value no
+     * query expression will be applied for selecting MBeans.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return A set containing the <code>ObjectInstance</code>
+     * objects for the selected MBeans.  If no MBean satisfies the
+     * query an empty list is returned.
+     *
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public Set<ObjectInstance>
+        queryMBeans(ObjectName name,
+                    MarshalledObject query,
+                    Subject delegationSubject)
+        throws IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#queryNames(ObjectName,
+     * QueryExp)}.  The <code>QueryExp</code> is wrapped in a
+     * <code>MarshalledObject</code>.
+     *
+     * @param name The object name pattern identifying the MBean names
+     * to be retrieved. If null or no domain and key properties are
+     * specified, the name of all registered MBeans will be retrieved.
+     * @param query The query expression to be applied for selecting
+     * MBeans, encapsulated into a <code>MarshalledObject</code>. If
+     * the <code>MarshalledObject</code> encapsulates a null value no
+     * query expression will be applied for selecting MBeans.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return A set containing the ObjectNames for the MBeans
+     * selected.  If no MBean satisfies the query, an empty list is
+     * returned.
+     *
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public Set<ObjectName>
+        queryNames(ObjectName name,
+                   MarshalledObject query,
+                   Subject delegationSubject)
+        throws IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#isRegistered(ObjectName)}.
+     *
+     * @param name The object name of the MBean to be checked.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return True if the MBean is already registered in the MBean
+     * server, false otherwise.
+     *
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public boolean isRegistered(ObjectName name, Subject delegationSubject)
+        throws IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#getMBeanCount()}.
+     *
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return the number of MBeans registered.
+     *
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public Integer getMBeanCount(Subject delegationSubject)
+        throws IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#getAttribute(ObjectName,
+     * String)}.
+     *
+     * @param name The object name of the MBean from which the
+     * attribute is to be retrieved.
+     * @param attribute A String specifying the name of the attribute
+     * to be retrieved.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return  The value of the retrieved attribute.
+     *
+     * @throws AttributeNotFoundException The attribute specified
+     * is not accessible in the MBean.
+     * @throws MBeanException Wraps an exception thrown by the
+     * MBean's getter.
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.Exception</code> thrown when trying to invoke
+     * the getter.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null or the attribute in parameter is
+     * null.
+     * @throws RuntimeMBeanException Wraps a runtime exception thrown
+     * by the MBean's getter.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     *
+     * @see #setAttribute
+     */
+    public Object getAttribute(ObjectName name,
+                               String attribute,
+                               Subject delegationSubject)
+        throws
+        MBeanException,
+        AttributeNotFoundException,
+        InstanceNotFoundException,
+        ReflectionException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#getAttributes(ObjectName,
+     * String[])}.
+     *
+     * @param name The object name of the MBean from which the
+     * attributes are retrieved.
+     * @param attributes A list of the attributes to be retrieved.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return The list of the retrieved attributes.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws ReflectionException An exception occurred when
+     * trying to invoke the getAttributes method of a Dynamic MBean.
+     * @throws RuntimeOperationsException Wrap a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null or attributes in parameter is null.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     *
+     * @see #setAttributes
+     */
+    public AttributeList getAttributes(ObjectName name,
+                                       String[] attributes,
+                                       Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ReflectionException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#setAttribute(ObjectName,
+     * Attribute)}.  The <code>Attribute</code> parameter is wrapped
+     * in a <code>MarshalledObject</code>.
+     *
+     * @param name The name of the MBean within which the attribute is
+     * to be set.
+     * @param attribute The identification of the attribute to be set
+     * and the value it is to be set to, encapsulated into a
+     * <code>MarshalledObject</code>.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws AttributeNotFoundException The attribute specified
+     * is not accessible in the MBean.
+     * @throws InvalidAttributeValueException The value specified
+     * for the attribute is not valid.
+     * @throws MBeanException Wraps an exception thrown by the
+     * MBean's setter.
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.Exception</code> thrown when trying to invoke
+     * the setter.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null or the attribute in parameter is
+     * null.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     *
+     * @see #getAttribute
+     */
+    public void setAttribute(ObjectName name,
+                             MarshalledObject attribute,
+                             Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        AttributeNotFoundException,
+        InvalidAttributeValueException,
+        MBeanException,
+        ReflectionException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#setAttributes(ObjectName,
+     * AttributeList)}.  The <code>AttributeList</code> parameter is
+     * wrapped in a <code>MarshalledObject</code>.
+     *
+     * @param name The object name of the MBean within which the
+     * attributes are to be set.
+     * @param attributes A list of attributes: The identification of
+     * the attributes to be set and the values they are to be set to,
+     * encapsulated into a <code>MarshalledObject</code>.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return The list of attributes that were set, with their new
+     * values.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws ReflectionException An exception occurred when
+     * trying to invoke the getAttributes method of a Dynamic MBean.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null or attributes in parameter is null.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     *
+     * @see #getAttributes
+     */
+    public AttributeList setAttributes(ObjectName name,
+                          MarshalledObject attributes,
+                          Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ReflectionException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#invoke(ObjectName,
+     * String, Object[], String[])}.  The <code>Object[]</code>
+     * parameter is wrapped in a <code>MarshalledObject</code>.
+     *
+     * @param name The object name of the MBean on which the method is
+     * to be invoked.
+     * @param operationName The name of the operation to be invoked.
+     * @param params An array containing the parameters to be set when
+     * the operation is invoked, encapsulated into a
+     * <code>MarshalledObject</code>.  The encapsulated array can be
+     * null, equivalent to an empty array.
+     * @param signature An array containing the signature of the
+     * operation. The class objects will be loaded using the same
+     * class loader as the one used for loading the MBean on which the
+     * operation was invoked.  Can be null, equivalent to an empty
+     * array.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return The object returned by the operation, which represents
+     * the result of invoking the operation on the MBean specified.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws MBeanException Wraps an exception thrown by the
+     * MBean's invoked method.
+     * @throws ReflectionException Wraps a
+     * <code>java.lang.Exception</code> thrown while trying to invoke
+     * the method.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     * @throws RuntimeOperationsException Wraps an {@link
+     * IllegalArgumentException} when <code>name</code> or
+     * <code>operationName</code> is null.
+     */
+    public Object invoke(ObjectName name,
+                         String operationName,
+                         MarshalledObject params,
+                         String signature[],
+                         Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        MBeanException,
+        ReflectionException,
+        IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#getDefaultDomain()}.
+     *
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return the default domain.
+     *
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public String getDefaultDomain(Subject delegationSubject)
+        throws IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#getDomains()}.
+     *
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return the list of domains.
+     *
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public String[] getDomains(Subject delegationSubject)
+        throws IOException;
+
+    /**
+     * Handles the method
+     * {@link javax.management.MBeanServerConnection#getMBeanInfo(ObjectName)}.
+     *
+     * @param name The name of the MBean to analyze
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return An instance of <code>MBeanInfo</code> allowing the
+     * retrieval of all attributes and operations of this MBean.
+     *
+     * @throws IntrospectionException An exception occurred during
+     * introspection.
+     * @throws InstanceNotFoundException The MBean specified was
+     * not found.
+     * @throws ReflectionException An exception occurred when
+     * trying to invoke the getMBeanInfo of a Dynamic MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null.
+     */
+    public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        IntrospectionException,
+        ReflectionException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#isInstanceOf(ObjectName,
+     * String)}.
+     *
+     * @param name The <code>ObjectName</code> of the MBean.
+     * @param className The name of the class.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @return true if the MBean specified is an instance of the
+     * specified class according to the rules above, false otherwise.
+     *
+     * @throws InstanceNotFoundException The MBean specified is not
+     * registered in the MBean server.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     * @throws RuntimeOperationsException Wraps a
+     * <code>java.lang.IllegalArgumentException</code>: The object
+     * name in parameter is null.
+     */
+    public boolean isInstanceOf(ObjectName name,
+                                String className,
+                                Subject delegationSubject)
+        throws InstanceNotFoundException, IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#addNotificationListener(ObjectName,
+     * ObjectName, NotificationFilter, Object)}.  The
+     * <code>NotificationFilter</code> parameter is wrapped in a
+     * <code>MarshalledObject</code>.  The <code>Object</code>
+     * (handback) parameter is also wrapped in a
+     * <code>MarshalledObject</code>.
+     *
+     * @param name The name of the MBean on which the listener should
+     * be added.
+     * @param listener The object name of the listener which will
+     * handle the notifications emitted by the registered MBean.
+     * @param filter The filter object, encapsulated into a
+     * <code>MarshalledObject</code>. If filter encapsulated in the
+     * <code>MarshalledObject</code> has a null value, no filtering
+     * will be performed before handling notifications.
+     * @param handback The context to be sent to the listener when a
+     * notification is emitted, encapsulated into a
+     * <code>MarshalledObject</code>.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @throws InstanceNotFoundException The MBean name of the
+     * notification listener or of the notification broadcaster does
+     * not match any of the registered MBeans.
+     * @throws RuntimeOperationsException Wraps an {@link
+     * IllegalArgumentException}.  The MBean named by
+     * <code>listener</code> exists but does not implement the
+     * {@link javax.management.NotificationListener} interface,
+     * or <code>name</code> or <code>listener</code> is null.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     *
+     * @see #removeNotificationListener(ObjectName, ObjectName, Subject)
+     * @see #removeNotificationListener(ObjectName, ObjectName,
+     * MarshalledObject, MarshalledObject, Subject)
+     */
+    public void addNotificationListener(ObjectName name,
+                        ObjectName listener,
+                        MarshalledObject filter,
+                        MarshalledObject handback,
+                        Subject delegationSubject)
+        throws InstanceNotFoundException, IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#removeNotificationListener(ObjectName,
+     * ObjectName)}.
+     *
+     * @param name The name of the MBean on which the listener should
+     * be removed.
+     * @param listener The object name of the listener to be removed.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @throws InstanceNotFoundException The MBean name provided
+     * does not match any of the registered MBeans.
+     * @throws ListenerNotFoundException The listener is not
+     * registered in the MBean.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     * @throws RuntimeOperationsException Wraps an {@link
+     * IllegalArgumentException} when <code>name</code> or
+     * <code>listener</code> is null.
+     *
+     * @see #addNotificationListener
+     */
+    public void removeNotificationListener(ObjectName name,
+                                           ObjectName listener,
+                                           Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ListenerNotFoundException,
+        IOException;
+
+    /**
+     * Handles the method {@link
+     * javax.management.MBeanServerConnection#removeNotificationListener(ObjectName,
+     * ObjectName, NotificationFilter, Object)}.  The
+     * <code>NotificationFilter</code> parameter is wrapped in a
+     * <code>MarshalledObject</code>.  The <code>Object</code>
+     * parameter is also wrapped in a <code>MarshalledObject</code>.
+     *
+     * @param name The name of the MBean on which the listener should
+     * be removed.
+     * @param listener A listener that was previously added to this
+     * MBean.
+     * @param filter The filter that was specified when the listener
+     * was added, encapsulated into a <code>MarshalledObject</code>.
+     * @param handback The handback that was specified when the
+     * listener was added, encapsulated into a <code>MarshalledObject</code>.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @throws InstanceNotFoundException The MBean name provided
+     * does not match any of the registered MBeans.
+     * @throws ListenerNotFoundException The listener is not
+     * registered in the MBean, or it is not registered with the given
+     * filter and handback.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to perform this operation.
+     * @throws IOException if a general communication exception occurred.
+     * @throws RuntimeOperationsException Wraps an {@link
+     * IllegalArgumentException} when <code>name</code> or
+     * <code>listener</code> is null.
+     *
+     * @see #addNotificationListener
+     */
+    public void removeNotificationListener(ObjectName name,
+                      ObjectName listener,
+                      MarshalledObject filter,
+                      MarshalledObject handback,
+                      Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ListenerNotFoundException,
+        IOException;
+
+    // Special Handling of Notifications -------------------------------------
+
+    /**
+     * <p>Handles the method {@link
+     * javax.management.MBeanServerConnection#addNotificationListener(ObjectName,
+     * NotificationListener, NotificationFilter, Object)}.</p>
+     *
+     * <p>Register for notifications from the given MBeans that match
+     * the given filters.  The remote client can subsequently retrieve
+     * the notifications using the {@link #fetchNotifications
+     * fetchNotifications} method.</p>
+     *
+     * <p>For each listener, the original
+     * <code>NotificationListener</code> and <code>handback</code> are
+     * kept on the client side; in order for the client to be able to
+     * identify them, the server generates and returns a unique
+     * <code>listenerID</code>.  This <code>listenerID</code> is
+     * forwarded with the <code>Notifications</code> to the remote
+     * client.</p>
+     *
+     * <p>If any one of the given (name, filter) pairs cannot be
+     * registered, then the operation fails with an exception, and no
+     * names or filters are registered.</p>
+     *
+     * @param names the <code>ObjectNames</code> identifying the
+     * MBeans emitting the Notifications.
+     * @param filters an array of marshalled representations of the
+     * <code>NotificationFilters</code>.  Elements of this array can
+     * be null.
+     * @param delegationSubjects the <code>Subjects</code> on behalf
+     * of which the listeners are being added.  Elements of this array
+     * can be null.  Also, the <code>delegationSubjects</code>
+     * parameter itself can be null, which is equivalent to an array
+     * of null values with the same size as the <code>names</code> and
+     * <code>filters</code> arrays.
+     *
+     * @return an array of <code>listenerIDs</code> identifying the
+     * local listeners.  This array has the same number of elements as
+     * the parameters.
+     *
+     * @throws IllegalArgumentException if <code>names</code> or
+     * <code>filters</code> is null, or if <code>names</code> contains
+     * a null element, or if the three arrays do not all have the same
+     * size.
+     * @throws ClassCastException if one of the elements of
+     * <code>filters</code> unmarshalls as a non-null object that is
+     * not a <code>NotificationFilter</code>.
+     * @throws InstanceNotFoundException if one of the
+     * <code>names</code> does not correspond to any registered MBean.
+     * @throws SecurityException if, for one of the MBeans, the
+     * client, or the delegated Subject if any, does not have
+     * permission to add a listener.
+     * @throws IOException if a general communication exception occurred.
+     */
+    public Integer[] addNotificationListeners(ObjectName[] names,
+                    MarshalledObject[] filters,
+                    Subject[] delegationSubjects)
+        throws InstanceNotFoundException, IOException;
+
+    /**
+     * <p>Handles the
+     * {@link javax.management.MBeanServerConnection#removeNotificationListener(ObjectName,NotificationListener)
+     * removeNotificationListener(ObjectName, NotificationListener)} and
+     * {@link javax.management.MBeanServerConnection#removeNotificationListener(ObjectName,NotificationListener,NotificationFilter,Object)
+     * removeNotificationListener(ObjectName, NotificationListener, NotificationFilter, Object)} methods.</p>
+     *
+     * <p>This method removes one or more
+     * <code>NotificationListener</code>s from a given MBean in the
+     * MBean server.</p>
+     *
+     * <p>The <code>NotificationListeners</code> are identified by the
+     * IDs which were returned by the {@link
+     * #addNotificationListeners(ObjectName[], MarshalledObject[],
+     * Subject[])} method.</p>
+     *
+     * @param name the <code>ObjectName</code> identifying the MBean
+     * emitting the Notifications.
+     * @param listenerIDs the list of the IDs corresponding to the
+     * listeners to remove.
+     * @param delegationSubject The <code>Subject</code> containing the
+     * delegation principals or <code>null</code> if the authentication
+     * principal is used instead.
+     *
+     * @throws InstanceNotFoundException if the given
+     * <code>name</code> does not correspond to any registered MBean.
+     * @throws ListenerNotFoundException if one of the listeners was
+     * not found on the server side.  This exception can happen if the
+     * MBean discarded a listener for some reason other than a call to
+     * <code>MBeanServer.removeNotificationListener</code>.
+     * @throws SecurityException if the client, or the delegated Subject
+     * if any, does not have permission to remove the listeners.
+     * @throws IOException if a general communication exception occurred.
+     * @throws IllegalArgumentException if <code>ObjectName</code> or
+     * <code>listenerIds</code> is null or if <code>listenerIds</code>
+     * contains a null element.
+     */
+    public void removeNotificationListeners(ObjectName name,
+                                            Integer[] listenerIDs,
+                                            Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ListenerNotFoundException,
+        IOException;
+
+    /**
+     * <p>Retrieves notifications from the connector server.  This
+     * method can block until there is at least one notification or
+     * until the specified timeout is reached.  The method can also
+     * return at any time with zero notifications.</p>
+     *
+     * <p>A notification can be included in the result if its sequence
+     * number is no less than <code>clientSequenceNumber</code> and
+     * this client has registered at least one listener for the MBean
+     * generating the notification, with a filter that accepts the
+     * notification.  Each listener that is interested in the
+     * notification is identified by an Integer ID that was returned
+     * by {@link #addNotificationListeners(ObjectName[],
+     * MarshalledObject[], Subject[])}.</p>
+     *
+     * @param clientSequenceNumber the first sequence number that the
+     * client is interested in.  If negative, it is interpreted as
+     * meaning the sequence number that the next notification will
+     * have.
+     *
+     * @param maxNotifications the maximum number of different
+     * notifications to return.  The <code>TargetedNotification</code>
+     * array in the returned <code>NotificationResult</code> can have
+     * more elements than this if the same notification appears more
+     * than once.  The behavior is unspecified if this parameter is
+     * negative.
+     *
+     * @param timeout the maximum time in milliseconds to wait for a
+     * notification to arrive.  This can be 0 to indicate that the
+     * method should not wait if there are no notifications, but
+     * should return at once.  It can be <code>Long.MAX_VALUE</code>
+     * to indicate that there is no timeout.  The behavior is
+     * unspecified if this parameter is negative.
+     *
+     * @return A <code>NotificationResult</code>.
+     *
+     * @throws IOException if a general communication exception occurred.
+     */
+    public NotificationResult fetchNotifications(long clientSequenceNumber,
+                                                 int maxNotifications,
+                                                 long timeout)
+            throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,1834 @@
+/*
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import java.io.IOException;
+import java.rmi.MarshalledObject;
+import java.rmi.UnmarshalException;
+import java.rmi.server.Unreferenced;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.*;
+import javax.management.remote.JMXServerErrorException;
+import javax.management.remote.NotificationResult;
+import javax.security.auth.Subject;
+import sun.reflect.misc.ReflectUtil;
+
+import static javax.management.remote.rmi.RMIConnector.Util.cast;
+import com.sun.jmx.remote.internal.ServerCommunicatorAdmin;
+import com.sun.jmx.remote.internal.ServerNotifForwarder;
+import com.sun.jmx.remote.security.JMXSubjectDomainCombiner;
+import com.sun.jmx.remote.security.SubjectDelegator;
+import com.sun.jmx.remote.util.ClassLoaderWithRepository;
+import com.sun.jmx.remote.util.ClassLogger;
+import com.sun.jmx.remote.util.EnvHelp;
+import com.sun.jmx.remote.util.OrderClassLoaders;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * <p>Implementation of the {@link RMIConnection} interface.  User
+ * code will not usually reference this class.</p>
+ *
+ * @since 1.5
+ */
+/*
+ * Notice that we omit the type parameter from MarshalledObject everywhere,
+ * even though it would add useful information to the documentation.  The
+ * reason is that it was only added in Mustang (Java SE 6), whereas versions
+ * 1.4 and 2.0 of the JMX API must be implementable on Tiger per our
+ * commitments for JSR 255.
+ */
+public class RMIConnectionImpl implements RMIConnection, Unreferenced {
+
+    /**
+     * Constructs a new {@link RMIConnection}. This connection can be
+     * used with the JRMP transport. This object does
+     * not export itself: it is the responsibility of the caller to
+     * export it appropriately (see {@link
+     * RMIJRMPServerImpl#makeClient(String,Subject)}).
+     *
+     * @param rmiServer The RMIServerImpl object for which this
+     * connection is created.  The behavior is unspecified if this
+     * parameter is null.
+     * @param connectionId The ID for this connection.  The behavior
+     * is unspecified if this parameter is null.
+     * @param defaultClassLoader The default ClassLoader to be used
+     * when deserializing marshalled objects.  Can be null, to signify
+     * the bootstrap class loader.
+     * @param subject the authenticated subject to be used for
+     * authorization.  Can be null, to signify that no subject has
+     * been authenticated.
+     * @param env the environment containing attributes for the new
+     * <code>RMIServerImpl</code>.  Can be null, equivalent to an
+     * empty map.
+     */
+    public RMIConnectionImpl(RMIServerImpl rmiServer,
+                             String connectionId,
+                             ClassLoader defaultClassLoader,
+                             Subject subject,
+                             Map<String,?> env) {
+        if (rmiServer == null || connectionId == null)
+            throw new NullPointerException("Illegal null argument");
+        if (env == null)
+            env = Collections.emptyMap();
+        this.rmiServer = rmiServer;
+        this.connectionId = connectionId;
+        this.defaultClassLoader = defaultClassLoader;
+
+        this.subjectDelegator = new SubjectDelegator();
+        this.subject = subject;
+        if (subject == null) {
+            this.acc = null;
+            this.removeCallerContext = false;
+        } else {
+            this.removeCallerContext =
+                SubjectDelegator.checkRemoveCallerContext(subject);
+            if (this.removeCallerContext) {
+                this.acc =
+                    JMXSubjectDomainCombiner.getDomainCombinerContext(subject);
+            } else {
+                this.acc =
+                    JMXSubjectDomainCombiner.getContext(subject);
+            }
+        }
+        this.mbeanServer = rmiServer.getMBeanServer();
+
+        final ClassLoader dcl = defaultClassLoader;
+
+        ClassLoaderRepository repository = AccessController.doPrivileged(
+            new PrivilegedAction<ClassLoaderRepository>() {
+                public ClassLoaderRepository run() {
+                    return mbeanServer.getClassLoaderRepository();
+                }
+            },
+            withPermissions(new MBeanPermission("*", "getClassLoaderRepository"))
+        );
+        this.classLoaderWithRepository = AccessController.doPrivileged(
+            new PrivilegedAction<ClassLoaderWithRepository>() {
+                public ClassLoaderWithRepository run() {
+                    return new ClassLoaderWithRepository(
+                        repository,
+                        dcl);
+                }
+            },
+            withPermissions(new RuntimePermission("createClassLoader"))
+        );
+
+        this.defaultContextClassLoader =
+            AccessController.doPrivileged(
+                new PrivilegedAction<ClassLoader>() {
+            @Override
+                    public ClassLoader run() {
+                        return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
+                                dcl);
+                    }
+                });
+
+        serverCommunicatorAdmin = new
+          RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env));
+
+        this.env = env;
+    }
+
+    private static AccessControlContext withPermissions(Permission ... perms){
+        Permissions col = new Permissions();
+
+        for (Permission thePerm : perms ) {
+            col.add(thePerm);
+        }
+
+        final ProtectionDomain pd = new ProtectionDomain(null, col);
+        return new AccessControlContext( new ProtectionDomain[] { pd });
+    }
+
+    private synchronized ServerNotifForwarder getServerNotifFwd() {
+        // Lazily created when first use. Mainly when
+        // addNotificationListener is first called.
+        if (serverNotifForwarder == null)
+            serverNotifForwarder =
+                new ServerNotifForwarder(mbeanServer,
+                                         env,
+                                         rmiServer.getNotifBuffer(),
+                                         connectionId);
+        return serverNotifForwarder;
+    }
+
+    public String getConnectionId() throws IOException {
+        // We should call reqIncomming() here... shouldn't we?
+        return connectionId;
+    }
+
+    public void close() throws IOException {
+        final boolean debug = logger.debugOn();
+        final String  idstr = (debug?"["+this.toString()+"]":null);
+
+        synchronized (this) {
+            if (terminated) {
+                if (debug) logger.debug("close",idstr + " already terminated.");
+                return;
+            }
+
+            if (debug) logger.debug("close",idstr + " closing.");
+
+            terminated = true;
+
+            if (serverCommunicatorAdmin != null) {
+                serverCommunicatorAdmin.terminate();
+            }
+
+            if (serverNotifForwarder != null) {
+                serverNotifForwarder.terminate();
+            }
+        }
+
+        rmiServer.clientClosed(this);
+
+        if (debug) logger.debug("close",idstr + " closed.");
+    }
+
+    public void unreferenced() {
+        logger.debug("unreferenced", "called");
+        try {
+            close();
+            logger.debug("unreferenced", "done");
+        } catch (IOException e) {
+            logger.fine("unreferenced", e);
+        }
+    }
+
+    //-------------------------------------------------------------------------
+    // MBeanServerConnection Wrapper
+    //-------------------------------------------------------------------------
+
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        IOException {
+        try {
+            final Object params[] =
+                new Object[] { className, name };
+
+            if (logger.debugOn())
+                logger.debug("createMBean(String,ObjectName)",
+                             "connectionId=" + connectionId +", className=" +
+                             className+", name=" + name);
+
+            return (ObjectInstance)
+                doPrivilegedOperation(
+                  CREATE_MBEAN,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof InstanceAlreadyExistsException)
+                throw (InstanceAlreadyExistsException) e;
+            if (e instanceof MBeanRegistrationException)
+                throw (MBeanRegistrationException) e;
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof NotCompliantMBeanException)
+                throw (NotCompliantMBeanException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      ObjectName loaderName,
+                                      Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        InstanceNotFoundException,
+        IOException {
+        try {
+            final Object params[] =
+                new Object[] { className, name, loaderName };
+
+            if (logger.debugOn())
+                logger.debug("createMBean(String,ObjectName,ObjectName)",
+                      "connectionId=" + connectionId
+                      +", className=" + className
+                      +", name=" + name
+                      +", loaderName=" + loaderName);
+
+            return (ObjectInstance)
+                doPrivilegedOperation(
+                  CREATE_MBEAN_LOADER,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof InstanceAlreadyExistsException)
+                throw (InstanceAlreadyExistsException) e;
+            if (e instanceof MBeanRegistrationException)
+                throw (MBeanRegistrationException) e;
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof NotCompliantMBeanException)
+                throw (NotCompliantMBeanException) e;
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public ObjectInstance createMBean(String className,
+                                      ObjectName name,
+                                      MarshalledObject params,
+                                      String signature[],
+                                      Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        IOException {
+
+        final Object[] values;
+        final boolean debug = logger.debugOn();
+
+        if (debug) logger.debug(
+                  "createMBean(String,ObjectName,Object[],String[])",
+                  "connectionId=" + connectionId
+                  +", unwrapping parameters using classLoaderWithRepository.");
+
+        values =
+            nullIsEmpty(unwrap(params, classLoaderWithRepository, Object[].class,delegationSubject));
+
+        try {
+            final Object params2[] =
+                new Object[] { className, name, values,
+                               nullIsEmpty(signature) };
+
+            if (debug)
+               logger.debug("createMBean(String,ObjectName,Object[],String[])",
+                             "connectionId=" + connectionId
+                             +", className=" + className
+                             +", name=" + name
+                             +", signature=" + strings(signature));
+
+            return (ObjectInstance)
+                doPrivilegedOperation(
+                  CREATE_MBEAN_PARAMS,
+                  params2,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof InstanceAlreadyExistsException)
+                throw (InstanceAlreadyExistsException) e;
+            if (e instanceof MBeanRegistrationException)
+                throw (MBeanRegistrationException) e;
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof NotCompliantMBeanException)
+                throw (NotCompliantMBeanException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public ObjectInstance createMBean(String className,
+                                 ObjectName name,
+                                 ObjectName loaderName,
+                                 MarshalledObject params,
+                                 String signature[],
+                                 Subject delegationSubject)
+        throws
+        ReflectionException,
+        InstanceAlreadyExistsException,
+        MBeanRegistrationException,
+        MBeanException,
+        NotCompliantMBeanException,
+        InstanceNotFoundException,
+        IOException {
+
+        final Object[] values;
+        final boolean debug = logger.debugOn();
+
+        if (debug) logger.debug(
+                 "createMBean(String,ObjectName,ObjectName,Object[],String[])",
+                 "connectionId=" + connectionId
+                 +", unwrapping params with MBean extended ClassLoader.");
+
+        values = nullIsEmpty(unwrap(params,
+                                    getClassLoader(loaderName),
+                                    defaultClassLoader,
+                                    Object[].class,delegationSubject));
+
+        try {
+            final Object params2[] =
+               new Object[] { className, name, loaderName, values,
+                              nullIsEmpty(signature) };
+
+           if (debug) logger.debug(
+                 "createMBean(String,ObjectName,ObjectName,Object[],String[])",
+                 "connectionId=" + connectionId
+                 +", className=" + className
+                 +", name=" + name
+                 +", loaderName=" + loaderName
+                 +", signature=" + strings(signature));
+
+            return (ObjectInstance)
+                doPrivilegedOperation(
+                  CREATE_MBEAN_LOADER_PARAMS,
+                  params2,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof InstanceAlreadyExistsException)
+                throw (InstanceAlreadyExistsException) e;
+            if (e instanceof MBeanRegistrationException)
+                throw (MBeanRegistrationException) e;
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof NotCompliantMBeanException)
+                throw (NotCompliantMBeanException) e;
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public void unregisterMBean(ObjectName name, Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        MBeanRegistrationException,
+        IOException {
+        try {
+            final Object params[] = new Object[] { name };
+
+            if (logger.debugOn()) logger.debug("unregisterMBean",
+                 "connectionId=" + connectionId
+                 +", name="+name);
+
+            doPrivilegedOperation(
+              UNREGISTER_MBEAN,
+              params,
+              delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof MBeanRegistrationException)
+                throw (MBeanRegistrationException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public ObjectInstance getObjectInstance(ObjectName name,
+                                            Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        IOException {
+
+        checkNonNull("ObjectName", name);
+
+        try {
+            final Object params[] = new Object[] { name };
+
+            if (logger.debugOn()) logger.debug("getObjectInstance",
+                 "connectionId=" + connectionId
+                 +", name="+name);
+
+            return (ObjectInstance)
+                doPrivilegedOperation(
+                  GET_OBJECT_INSTANCE,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public Set<ObjectInstance>
+        queryMBeans(ObjectName name,
+                    MarshalledObject query,
+                    Subject delegationSubject)
+        throws IOException {
+        final QueryExp queryValue;
+        final boolean debug=logger.debugOn();
+
+        if (debug) logger.debug("queryMBeans",
+                 "connectionId=" + connectionId
+                 +" unwrapping query with defaultClassLoader.");
+
+        queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject);
+
+        try {
+            final Object params[] = new Object[] { name, queryValue };
+
+            if (debug) logger.debug("queryMBeans",
+                 "connectionId=" + connectionId
+                 +", name="+name +", query="+query);
+
+            return cast(
+                doPrivilegedOperation(
+                  QUERY_MBEANS,
+                  params,
+                  delegationSubject));
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public Set<ObjectName>
+        queryNames(ObjectName name,
+                   MarshalledObject query,
+                   Subject delegationSubject)
+        throws IOException {
+        final QueryExp queryValue;
+        final boolean debug=logger.debugOn();
+
+        if (debug) logger.debug("queryNames",
+                 "connectionId=" + connectionId
+                 +" unwrapping query with defaultClassLoader.");
+
+        queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject);
+
+        try {
+            final Object params[] = new Object[] { name, queryValue };
+
+            if (debug) logger.debug("queryNames",
+                 "connectionId=" + connectionId
+                 +", name="+name +", query="+query);
+
+            return cast(
+                doPrivilegedOperation(
+                  QUERY_NAMES,
+                  params,
+                  delegationSubject));
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public boolean isRegistered(ObjectName name,
+                                Subject delegationSubject) throws IOException {
+        try {
+            final Object params[] = new Object[] { name };
+            return ((Boolean)
+                doPrivilegedOperation(
+                  IS_REGISTERED,
+                  params,
+                  delegationSubject)).booleanValue();
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public Integer getMBeanCount(Subject delegationSubject)
+        throws IOException {
+        try {
+            final Object params[] = new Object[] { };
+
+            if (logger.debugOn()) logger.debug("getMBeanCount",
+                 "connectionId=" + connectionId);
+
+            return (Integer)
+                doPrivilegedOperation(
+                  GET_MBEAN_COUNT,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public Object getAttribute(ObjectName name,
+                               String attribute,
+                               Subject delegationSubject)
+        throws
+        MBeanException,
+        AttributeNotFoundException,
+        InstanceNotFoundException,
+        ReflectionException,
+        IOException {
+        try {
+            final Object params[] = new Object[] { name, attribute };
+            if (logger.debugOn()) logger.debug("getAttribute",
+                                   "connectionId=" + connectionId
+                                   +", name=" + name
+                                   +", attribute="+ attribute);
+
+            return
+                doPrivilegedOperation(
+                  GET_ATTRIBUTE,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof AttributeNotFoundException)
+                throw (AttributeNotFoundException) e;
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public AttributeList getAttributes(ObjectName name,
+                                       String[] attributes,
+                                       Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ReflectionException,
+        IOException {
+        try {
+            final Object params[] = new Object[] { name, attributes };
+
+            if (logger.debugOn()) logger.debug("getAttributes",
+                                   "connectionId=" + connectionId
+                                   +", name=" + name
+                                   +", attributes="+ strings(attributes));
+
+            return (AttributeList)
+                doPrivilegedOperation(
+                  GET_ATTRIBUTES,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public void setAttribute(ObjectName name,
+                             MarshalledObject attribute,
+                             Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        AttributeNotFoundException,
+        InvalidAttributeValueException,
+        MBeanException,
+        ReflectionException,
+        IOException {
+        final Attribute attr;
+        final boolean debug=logger.debugOn();
+
+        if (debug) logger.debug("setAttribute",
+                 "connectionId=" + connectionId
+                 +" unwrapping attribute with MBean extended ClassLoader.");
+
+        attr = unwrap(attribute,
+                      getClassLoaderFor(name),
+                      defaultClassLoader,
+                      Attribute.class, delegationSubject);
+
+        try {
+            final Object params[] = new Object[] { name, attr };
+
+            if (debug) logger.debug("setAttribute",
+                             "connectionId=" + connectionId
+                             +", name="+name
+                             +", attribute name="+attr.getName());
+
+            doPrivilegedOperation(
+              SET_ATTRIBUTE,
+              params,
+              delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof AttributeNotFoundException)
+                throw (AttributeNotFoundException) e;
+            if (e instanceof InvalidAttributeValueException)
+                throw (InvalidAttributeValueException) e;
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public AttributeList setAttributes(ObjectName name,
+                         MarshalledObject attributes,
+                         Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ReflectionException,
+        IOException {
+        final AttributeList attrlist;
+        final boolean debug=logger.debugOn();
+
+        if (debug) logger.debug("setAttributes",
+                 "connectionId=" + connectionId
+                 +" unwrapping attributes with MBean extended ClassLoader.");
+
+        attrlist =
+            unwrap(attributes,
+                   getClassLoaderFor(name),
+                   defaultClassLoader,
+                   AttributeList.class, delegationSubject);
+
+        try {
+            final Object params[] = new Object[] { name, attrlist };
+
+            if (debug) logger.debug("setAttributes",
+                             "connectionId=" + connectionId
+                             +", name="+name
+                             +", attribute names="+RMIConnector.getAttributesNames(attrlist));
+
+            return (AttributeList)
+                doPrivilegedOperation(
+                  SET_ATTRIBUTES,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public Object invoke(ObjectName name,
+                         String operationName,
+                         MarshalledObject params,
+                         String signature[],
+                         Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        MBeanException,
+        ReflectionException,
+        IOException {
+
+        checkNonNull("ObjectName", name);
+        checkNonNull("Operation name", operationName);
+
+        final Object[] values;
+        final boolean debug=logger.debugOn();
+
+        if (debug) logger.debug("invoke",
+                 "connectionId=" + connectionId
+                 +" unwrapping params with MBean extended ClassLoader.");
+
+        values = nullIsEmpty(unwrap(params,
+                                    getClassLoaderFor(name),
+                                    defaultClassLoader,
+                                    Object[].class, delegationSubject));
+
+        try {
+            final Object params2[] =
+                new Object[] { name, operationName, values,
+                               nullIsEmpty(signature) };
+
+            if (debug) logger.debug("invoke",
+                             "connectionId=" + connectionId
+                             +", name="+name
+                             +", operationName="+operationName
+                             +", signature="+strings(signature));
+
+            return
+                doPrivilegedOperation(
+                  INVOKE,
+                  params2,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof MBeanException)
+                throw (MBeanException) e;
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public String getDefaultDomain(Subject delegationSubject)
+        throws IOException {
+        try {
+            final Object params[] = new Object[] { };
+
+            if (logger.debugOn())  logger.debug("getDefaultDomain",
+                                    "connectionId=" + connectionId);
+
+            return (String)
+                doPrivilegedOperation(
+                  GET_DEFAULT_DOMAIN,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public String[] getDomains(Subject delegationSubject) throws IOException {
+        try {
+            final Object params[] = new Object[] { };
+
+            if (logger.debugOn())  logger.debug("getDomains",
+                                    "connectionId=" + connectionId);
+
+            return (String[])
+                doPrivilegedOperation(
+                  GET_DOMAINS,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        IntrospectionException,
+        ReflectionException,
+        IOException {
+
+        checkNonNull("ObjectName", name);
+
+        try {
+            final Object params[] = new Object[] { name };
+
+            if (logger.debugOn())  logger.debug("getMBeanInfo",
+                                    "connectionId=" + connectionId
+                                    +", name="+name);
+
+            return (MBeanInfo)
+                doPrivilegedOperation(
+                  GET_MBEAN_INFO,
+                  params,
+                  delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof IntrospectionException)
+                throw (IntrospectionException) e;
+            if (e instanceof ReflectionException)
+                throw (ReflectionException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public boolean isInstanceOf(ObjectName name,
+                                String className,
+                                Subject delegationSubject)
+        throws InstanceNotFoundException, IOException {
+
+        checkNonNull("ObjectName", name);
+
+        try {
+            final Object params[] = new Object[] { name, className };
+
+            if (logger.debugOn())  logger.debug("isInstanceOf",
+                                    "connectionId=" + connectionId
+                                    +", name="+name
+                                    +", className="+className);
+
+            return ((Boolean)
+                doPrivilegedOperation(
+                  IS_INSTANCE_OF,
+                  params,
+                  delegationSubject)).booleanValue();
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public Integer[] addNotificationListeners(ObjectName[] names,
+                      MarshalledObject[] filters,
+                      Subject[] delegationSubjects)
+            throws InstanceNotFoundException, IOException {
+
+        if (names == null || filters == null) {
+            throw new IllegalArgumentException("Got null arguments.");
+        }
+
+        Subject[] sbjs = (delegationSubjects != null) ? delegationSubjects :
+        new Subject[names.length];
+        if (names.length != filters.length || filters.length != sbjs.length) {
+            final String msg =
+                "The value lengths of 3 parameters are not same.";
+            throw new IllegalArgumentException(msg);
+        }
+
+        for (int i=0; i<names.length; i++) {
+            if (names[i] == null) {
+                throw new IllegalArgumentException("Null Object name.");
+            }
+        }
+
+        int i=0;
+        ClassLoader targetCl;
+        NotificationFilter[] filterValues =
+            new NotificationFilter[names.length];
+        Integer[] ids = new Integer[names.length];
+        final boolean debug=logger.debugOn();
+
+        try {
+            for (; i<names.length; i++) {
+                targetCl = getClassLoaderFor(names[i]);
+
+                if (debug) logger.debug("addNotificationListener"+
+                                        "(ObjectName,NotificationFilter)",
+                                        "connectionId=" + connectionId +
+                      " unwrapping filter with target extended ClassLoader.");
+
+                filterValues[i] =
+                    unwrap(filters[i], targetCl, defaultClassLoader,
+                           NotificationFilter.class, sbjs[i]);
+
+                if (debug) logger.debug("addNotificationListener"+
+                                        "(ObjectName,NotificationFilter)",
+                                        "connectionId=" + connectionId
+                                        +", name=" + names[i]
+                                        +", filter=" + filterValues[i]);
+
+                ids[i] = (Integer)
+                    doPrivilegedOperation(ADD_NOTIFICATION_LISTENERS,
+                                          new Object[] { names[i],
+                                                         filterValues[i] },
+                                          sbjs[i]);
+            }
+
+            return ids;
+        } catch (Exception e) {
+            // remove all registered listeners
+            for (int j=0; j<i; j++) {
+                try {
+                    getServerNotifFwd().removeNotificationListener(names[j],
+                                                                   ids[j]);
+                } catch (Exception eee) {
+                    // strange
+                }
+            }
+
+            if (e instanceof PrivilegedActionException) {
+                e = extractException(e);
+            }
+
+            if (e instanceof ClassCastException) {
+                throw (ClassCastException) e;
+            } else if (e instanceof IOException) {
+                throw (IOException)e;
+            } else if (e instanceof InstanceNotFoundException) {
+                throw (InstanceNotFoundException) e;
+            } else if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            } else {
+                throw newIOException("Got unexpected server exception: "+e,e);
+            }
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public void addNotificationListener(ObjectName name,
+                       ObjectName listener,
+                       MarshalledObject filter,
+                       MarshalledObject handback,
+                       Subject delegationSubject)
+        throws InstanceNotFoundException, IOException {
+
+        checkNonNull("Target MBean name", name);
+        checkNonNull("Listener MBean name", listener);
+
+        final NotificationFilter filterValue;
+        final Object handbackValue;
+        final boolean debug=logger.debugOn();
+
+        final ClassLoader targetCl = getClassLoaderFor(name);
+
+        if (debug) logger.debug("addNotificationListener"+
+                 "(ObjectName,ObjectName,NotificationFilter,Object)",
+                 "connectionId=" + connectionId
+                 +" unwrapping filter with target extended ClassLoader.");
+
+        filterValue =
+            unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject);
+
+        if (debug) logger.debug("addNotificationListener"+
+                 "(ObjectName,ObjectName,NotificationFilter,Object)",
+                 "connectionId=" + connectionId
+                 +" unwrapping handback with target extended ClassLoader.");
+
+        handbackValue =
+            unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject);
+
+        try {
+            final Object params[] =
+                new Object[] { name, listener, filterValue, handbackValue };
+
+            if (debug) logger.debug("addNotificationListener"+
+                 "(ObjectName,ObjectName,NotificationFilter,Object)",
+                             "connectionId=" + connectionId
+                             +", name=" + name
+                             +", listenerName=" + listener
+                             +", filter=" + filterValue
+                             +", handback=" + handbackValue);
+
+            doPrivilegedOperation(
+              ADD_NOTIFICATION_LISTENER_OBJECTNAME,
+              params,
+              delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public void removeNotificationListeners(ObjectName name,
+                                            Integer[] listenerIDs,
+                                            Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ListenerNotFoundException,
+        IOException {
+
+        if (name == null || listenerIDs == null)
+            throw new IllegalArgumentException("Illegal null parameter");
+
+        for (int i = 0; i < listenerIDs.length; i++) {
+            if (listenerIDs[i] == null)
+                throw new IllegalArgumentException("Null listener ID");
+        }
+
+        try {
+            final Object params[] = new Object[] { name, listenerIDs };
+
+            if (logger.debugOn()) logger.debug("removeNotificationListener"+
+                                   "(ObjectName,Integer[])",
+                                   "connectionId=" + connectionId
+                                   +", name=" + name
+                                   +", listenerIDs=" + objects(listenerIDs));
+
+            doPrivilegedOperation(
+              REMOVE_NOTIFICATION_LISTENER,
+              params,
+              delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof ListenerNotFoundException)
+                throw (ListenerNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public void removeNotificationListener(ObjectName name,
+                                           ObjectName listener,
+                                           Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ListenerNotFoundException,
+        IOException {
+
+        checkNonNull("Target MBean name", name);
+        checkNonNull("Listener MBean name", listener);
+
+        try {
+            final Object params[] = new Object[] { name, listener };
+
+            if (logger.debugOn()) logger.debug("removeNotificationListener"+
+                                   "(ObjectName,ObjectName)",
+                                   "connectionId=" + connectionId
+                                   +", name=" + name
+                                   +", listenerName=" + listener);
+
+            doPrivilegedOperation(
+              REMOVE_NOTIFICATION_LISTENER_OBJECTNAME,
+              params,
+              delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof ListenerNotFoundException)
+                throw (ListenerNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")  // MarshalledObject
+    public void removeNotificationListener(ObjectName name,
+                        ObjectName listener,
+                        MarshalledObject filter,
+                        MarshalledObject handback,
+                        Subject delegationSubject)
+        throws
+        InstanceNotFoundException,
+        ListenerNotFoundException,
+        IOException {
+
+        checkNonNull("Target MBean name", name);
+        checkNonNull("Listener MBean name", listener);
+
+        final NotificationFilter filterValue;
+        final Object handbackValue;
+        final boolean debug=logger.debugOn();
+
+        final ClassLoader targetCl = getClassLoaderFor(name);
+
+        if (debug) logger.debug("removeNotificationListener"+
+                 "(ObjectName,ObjectName,NotificationFilter,Object)",
+                 "connectionId=" + connectionId
+                 +" unwrapping filter with target extended ClassLoader.");
+
+        filterValue =
+            unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject);
+
+        if (debug) logger.debug("removeNotificationListener"+
+                 "(ObjectName,ObjectName,NotificationFilter,Object)",
+                 "connectionId=" + connectionId
+                 +" unwrapping handback with target extended ClassLoader.");
+
+        handbackValue =
+            unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject);
+
+        try {
+            final Object params[] =
+                new Object[] { name, listener, filterValue, handbackValue };
+
+            if (debug) logger.debug("removeNotificationListener"+
+                 "(ObjectName,ObjectName,NotificationFilter,Object)",
+                             "connectionId=" + connectionId
+                             +", name=" + name
+                             +", listenerName=" + listener
+                             +", filter=" + filterValue
+                             +", handback=" + handbackValue);
+
+            doPrivilegedOperation(
+              REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK,
+              params,
+              delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof InstanceNotFoundException)
+                throw (InstanceNotFoundException) e;
+            if (e instanceof ListenerNotFoundException)
+                throw (ListenerNotFoundException) e;
+            if (e instanceof IOException)
+                throw (IOException) e;
+            throw newIOException("Got unexpected server exception: " + e, e);
+        }
+    }
+
+    public NotificationResult fetchNotifications(long clientSequenceNumber,
+                                                 int maxNotifications,
+                                                 long timeout)
+        throws IOException {
+
+        if (logger.debugOn()) logger.debug("fetchNotifications",
+                               "connectionId=" + connectionId
+                               +", timeout=" + timeout);
+
+        if (maxNotifications < 0 || timeout < 0)
+            throw new IllegalArgumentException("Illegal negative argument");
+
+        final boolean serverTerminated =
+            serverCommunicatorAdmin.reqIncoming();
+        try {
+            if (serverTerminated) {
+                // we must not call fetchNotifs() if the server is
+                // terminated (timeout elapsed).
+                // returns null to force the client to stop fetching
+                if (logger.debugOn()) logger.debug("fetchNotifications",
+                               "The notification server has been closed, "
+                                       + "returns null to force the client to stop fetching");
+                return null;
+            }
+            final long csn = clientSequenceNumber;
+            final int mn = maxNotifications;
+            final long t = timeout;
+            PrivilegedAction<NotificationResult> action =
+                new PrivilegedAction<NotificationResult>() {
+                    public NotificationResult run() {
+                        return getServerNotifFwd().fetchNotifs(csn, t, mn);
+                    }
+            };
+            if (acc == null)
+                return action.run();
+            else
+                return AccessController.doPrivileged(action, acc);
+        } finally {
+            serverCommunicatorAdmin.rspOutgoing();
+        }
+    }
+
+    /**
+     * <p>Returns a string representation of this object.  In general,
+     * the <code>toString</code> method returns a string that
+     * "textually represents" this object. The result should be a
+     * concise but informative representation that is easy for a
+     * person to read.</p>
+     *
+     * @return a String representation of this object.
+     **/
+    @Override
+    public String toString() {
+        return super.toString() + ": connectionId=" + connectionId;
+    }
+
+    //------------------------------------------------------------------------
+    // private classes
+    //------------------------------------------------------------------------
+
+    private class PrivilegedOperation
+            implements PrivilegedExceptionAction<Object> {
+
+        public PrivilegedOperation(int operation, Object[] params) {
+            this.operation = operation;
+            this.params = params;
+        }
+
+        public Object run() throws Exception {
+            return doOperation(operation, params);
+        }
+
+        private int operation;
+        private Object[] params;
+    }
+
+    //------------------------------------------------------------------------
+    // private classes
+    //------------------------------------------------------------------------
+    private class RMIServerCommunicatorAdmin extends ServerCommunicatorAdmin {
+        public RMIServerCommunicatorAdmin(long timeout) {
+            super(timeout);
+        }
+
+        protected void doStop() {
+            try {
+                close();
+            } catch (IOException ie) {
+                logger.warning("RMIServerCommunicatorAdmin-doStop",
+                               "Failed to close: " + ie);
+                logger.debug("RMIServerCommunicatorAdmin-doStop",ie);
+            }
+        }
+
+    }
+
+
+    //------------------------------------------------------------------------
+    // private methods
+    //------------------------------------------------------------------------
+
+    private ClassLoader getClassLoader(final ObjectName name)
+        throws InstanceNotFoundException {
+        try {
+            return
+                AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<ClassLoader>() {
+                        public ClassLoader run() throws InstanceNotFoundException {
+                            return mbeanServer.getClassLoader(name);
+                        }
+                    },
+                    withPermissions(new MBeanPermission("*", "getClassLoader"))
+            );
+        } catch (PrivilegedActionException pe) {
+            throw (InstanceNotFoundException) extractException(pe);
+        }
+    }
+
+    private ClassLoader getClassLoaderFor(final ObjectName name)
+        throws InstanceNotFoundException {
+        try {
+            return (ClassLoader)
+                AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Object>() {
+                        public Object run() throws InstanceNotFoundException {
+                            return mbeanServer.getClassLoaderFor(name);
+                        }
+                    },
+                    withPermissions(new MBeanPermission("*", "getClassLoaderFor"))
+            );
+        } catch (PrivilegedActionException pe) {
+            throw (InstanceNotFoundException) extractException(pe);
+        }
+    }
+
+    private Object doPrivilegedOperation(final int operation,
+                                         final Object[] params,
+                                         final Subject delegationSubject)
+        throws PrivilegedActionException, IOException {
+
+        serverCommunicatorAdmin.reqIncoming();
+        try {
+
+            final AccessControlContext reqACC;
+            if (delegationSubject == null)
+                reqACC = acc;
+            else {
+                if (subject == null) {
+                    final String msg =
+                        "Subject delegation cannot be enabled unless " +
+                        "an authenticated subject is put in place";
+                    throw new SecurityException(msg);
+                }
+                reqACC = subjectDelegator.delegatedContext(
+                    acc, delegationSubject, removeCallerContext);
+            }
+
+            PrivilegedOperation op =
+                new PrivilegedOperation(operation, params);
+            if (reqACC == null) {
+                try {
+                    return op.run();
+                } catch (Exception e) {
+                    if (e instanceof RuntimeException)
+                        throw (RuntimeException) e;
+                    throw new PrivilegedActionException(e);
+                }
+            } else {
+                return AccessController.doPrivileged(op, reqACC);
+            }
+        } catch (Error e) {
+            throw new JMXServerErrorException(e.toString(),e);
+        } finally {
+            serverCommunicatorAdmin.rspOutgoing();
+        }
+    }
+
+    private Object doOperation(int operation, Object[] params)
+        throws Exception {
+
+        switch (operation) {
+
+        case CREATE_MBEAN:
+            return mbeanServer.createMBean((String)params[0],
+                                           (ObjectName)params[1]);
+
+        case CREATE_MBEAN_LOADER:
+            return mbeanServer.createMBean((String)params[0],
+                                           (ObjectName)params[1],
+                                           (ObjectName)params[2]);
+
+        case CREATE_MBEAN_PARAMS:
+            return mbeanServer.createMBean((String)params[0],
+                                           (ObjectName)params[1],
+                                           (Object[])params[2],
+                                           (String[])params[3]);
+
+        case CREATE_MBEAN_LOADER_PARAMS:
+            return mbeanServer.createMBean((String)params[0],
+                                           (ObjectName)params[1],
+                                           (ObjectName)params[2],
+                                           (Object[])params[3],
+                                           (String[])params[4]);
+
+        case GET_ATTRIBUTE:
+            return mbeanServer.getAttribute((ObjectName)params[0],
+                                            (String)params[1]);
+
+        case GET_ATTRIBUTES:
+            return mbeanServer.getAttributes((ObjectName)params[0],
+                                             (String[])params[1]);
+
+        case GET_DEFAULT_DOMAIN:
+            return mbeanServer.getDefaultDomain();
+
+        case GET_DOMAINS:
+            return mbeanServer.getDomains();
+
+        case GET_MBEAN_COUNT:
+            return mbeanServer.getMBeanCount();
+
+        case GET_MBEAN_INFO:
+            return mbeanServer.getMBeanInfo((ObjectName)params[0]);
+
+        case GET_OBJECT_INSTANCE:
+            return mbeanServer.getObjectInstance((ObjectName)params[0]);
+
+        case INVOKE:
+            return mbeanServer.invoke((ObjectName)params[0],
+                                      (String)params[1],
+                                      (Object[])params[2],
+                                      (String[])params[3]);
+
+        case IS_INSTANCE_OF:
+            return mbeanServer.isInstanceOf((ObjectName)params[0],
+                                            (String)params[1])
+                ? Boolean.TRUE : Boolean.FALSE;
+
+        case IS_REGISTERED:
+            return mbeanServer.isRegistered((ObjectName)params[0])
+                ? Boolean.TRUE : Boolean.FALSE;
+
+        case QUERY_MBEANS:
+            return mbeanServer.queryMBeans((ObjectName)params[0],
+                                           (QueryExp)params[1]);
+
+        case QUERY_NAMES:
+            return mbeanServer.queryNames((ObjectName)params[0],
+                                          (QueryExp)params[1]);
+
+        case SET_ATTRIBUTE:
+            mbeanServer.setAttribute((ObjectName)params[0],
+                                     (Attribute)params[1]);
+            return null;
+
+        case SET_ATTRIBUTES:
+            return mbeanServer.setAttributes((ObjectName)params[0],
+                                             (AttributeList)params[1]);
+
+        case UNREGISTER_MBEAN:
+            mbeanServer.unregisterMBean((ObjectName)params[0]);
+            return null;
+
+        case ADD_NOTIFICATION_LISTENERS:
+            return getServerNotifFwd().addNotificationListener(
+                                                (ObjectName)params[0],
+                                                (NotificationFilter)params[1]);
+
+        case ADD_NOTIFICATION_LISTENER_OBJECTNAME:
+            mbeanServer.addNotificationListener((ObjectName)params[0],
+                                                (ObjectName)params[1],
+                                                (NotificationFilter)params[2],
+                                                params[3]);
+            return null;
+
+        case REMOVE_NOTIFICATION_LISTENER:
+            getServerNotifFwd().removeNotificationListener(
+                                                   (ObjectName)params[0],
+                                                   (Integer[])params[1]);
+            return null;
+
+        case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME:
+            mbeanServer.removeNotificationListener((ObjectName)params[0],
+                                                   (ObjectName)params[1]);
+            return null;
+
+        case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK:
+            mbeanServer.removeNotificationListener(
+                                          (ObjectName)params[0],
+                                          (ObjectName)params[1],
+                                          (NotificationFilter)params[2],
+                                          params[3]);
+            return null;
+
+        default:
+            throw new IllegalArgumentException("Invalid operation");
+        }
+    }
+
+    private static class SetCcl implements PrivilegedExceptionAction<ClassLoader> {
+        private final ClassLoader classLoader;
+
+        SetCcl(ClassLoader classLoader) {
+            this.classLoader = classLoader;
+        }
+
+        public ClassLoader run() {
+            Thread currentThread = Thread.currentThread();
+            ClassLoader old = currentThread.getContextClassLoader();
+            currentThread.setContextClassLoader(classLoader);
+            return old;
+        }
+    }
+
+    private <T> T unwrap(final MarshalledObject<?> mo,
+                                final ClassLoader cl,
+                                final Class<T> wrappedClass,
+                                Subject delegationSubject)
+            throws IOException {
+        if (mo == null) {
+            return null;
+        }
+        try {
+            final ClassLoader old = AccessController.doPrivileged(new SetCcl(cl));
+            try{
+                final AccessControlContext reqACC;
+                if (delegationSubject == null)
+                    reqACC = acc;
+                else {
+                    if (subject == null) {
+                        final String msg =
+                            "Subject delegation cannot be enabled unless " +
+                            "an authenticated subject is put in place";
+                        throw new SecurityException(msg);
+                    }
+                    reqACC = subjectDelegator.delegatedContext(
+                        acc, delegationSubject, removeCallerContext);
+                }
+                if(reqACC != null){
+                    return AccessController.doPrivileged(
+                            (PrivilegedExceptionAction<T>) () ->
+                                    wrappedClass.cast(mo.get()), reqACC);
+                }else{
+                    return wrappedClass.cast(mo.get());
+                }
+            }finally{
+                AccessController.doPrivileged(new SetCcl(old));
+            }
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException) {
+                throw (IOException) e;
+            }
+            if (e instanceof ClassNotFoundException) {
+                throw new UnmarshalException(e.toString(), e);
+            }
+            logger.warning("unwrap", "Failed to unmarshall object: " + e);
+            logger.debug("unwrap", e);
+        }catch (ClassNotFoundException ex) {
+            logger.warning("unwrap", "Failed to unmarshall object: " + ex);
+            logger.debug("unwrap", ex);
+            throw new UnmarshalException(ex.toString(), ex);
+        }
+        return null;
+    }
+
+    private <T> T unwrap(final MarshalledObject<?> mo,
+                                final ClassLoader cl1,
+                                final ClassLoader cl2,
+                                final Class<T> wrappedClass,
+                                Subject delegationSubject)
+        throws IOException {
+        if (mo == null) {
+            return null;
+        }
+        try {
+            ClassLoader orderCL = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<ClassLoader>() {
+                    public ClassLoader run() throws Exception {
+                        return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
+                                new OrderClassLoaders(cl1, cl2));
+                    }
+                }
+            );
+            return unwrap(mo, orderCL, wrappedClass,delegationSubject);
+        } catch (PrivilegedActionException pe) {
+            Exception e = extractException(pe);
+            if (e instanceof IOException) {
+                throw (IOException) e;
+            }
+            if (e instanceof ClassNotFoundException) {
+                throw new UnmarshalException(e.toString(), e);
+            }
+            logger.warning("unwrap", "Failed to unmarshall object: " + e);
+            logger.debug("unwrap", e);
+        }
+        return null;
+    }
+
+    /**
+     * Construct a new IOException with a nested exception.
+     * The nested exception is set only if JDK {@literal >= 1.4}
+     */
+    private static IOException newIOException(String message,
+                                              Throwable cause) {
+        final IOException x = new IOException(message);
+        return EnvHelp.initCause(x,cause);
+    }
+
+    /**
+     * Iterate until we extract the real exception
+     * from a stack of PrivilegedActionExceptions.
+     */
+    private static Exception extractException(Exception e) {
+        while (e instanceof PrivilegedActionException) {
+            e = ((PrivilegedActionException)e).getException();
+        }
+        return e;
+    }
+
+    private static final Object[] NO_OBJECTS = new Object[0];
+    private static final String[] NO_STRINGS = new String[0];
+
+    /*
+     * The JMX spec doesn't explicitly say that a null Object[] or
+     * String[] in e.g. MBeanServer.invoke is equivalent to an empty
+     * array, but the RI behaves that way.  In the interests of
+     * maximal interoperability, we make it so even when we're
+     * connected to some other JMX implementation that might not do
+     * that.  This should be clarified in the next version of JMX.
+     */
+    private static Object[] nullIsEmpty(Object[] array) {
+        return (array == null) ? NO_OBJECTS : array;
+    }
+
+    private static String[] nullIsEmpty(String[] array) {
+        return (array == null) ? NO_STRINGS : array;
+    }
+
+    /*
+     * Similarly, the JMX spec says for some but not all methods in
+     * MBeanServer that take an ObjectName target, that if it's null
+     * you get this exception.  We specify it for all of them, and
+     * make it so for the ones where it's not specified in JMX even if
+     * the JMX implementation doesn't do so.
+     */
+    private static void checkNonNull(String what, Object x) {
+        if (x == null) {
+            RuntimeException wrapped =
+                new IllegalArgumentException(what + " must not be null");
+            throw new RuntimeOperationsException(wrapped);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    // private variables
+    //------------------------------------------------------------------------
+
+    private final Subject subject;
+
+    private final SubjectDelegator subjectDelegator;
+
+    private final boolean removeCallerContext;
+
+    private final AccessControlContext acc;
+
+    private final RMIServerImpl rmiServer;
+
+    private final MBeanServer mbeanServer;
+
+    private final ClassLoader defaultClassLoader;
+
+    private final ClassLoader defaultContextClassLoader;
+
+    private final ClassLoaderWithRepository classLoaderWithRepository;
+
+    private boolean terminated = false;
+
+    private final String connectionId;
+
+    private final ServerCommunicatorAdmin serverCommunicatorAdmin;
+
+    // Method IDs for doOperation
+    //---------------------------
+
+    private final static int
+        ADD_NOTIFICATION_LISTENERS                              = 1;
+    private final static int
+        ADD_NOTIFICATION_LISTENER_OBJECTNAME                    = 2;
+    private final static int
+        CREATE_MBEAN                                            = 3;
+    private final static int
+        CREATE_MBEAN_PARAMS                                     = 4;
+    private final static int
+        CREATE_MBEAN_LOADER                                     = 5;
+    private final static int
+        CREATE_MBEAN_LOADER_PARAMS                              = 6;
+    private final static int
+        GET_ATTRIBUTE                                           = 7;
+    private final static int
+        GET_ATTRIBUTES                                          = 8;
+    private final static int
+        GET_DEFAULT_DOMAIN                                      = 9;
+    private final static int
+        GET_DOMAINS                                             = 10;
+    private final static int
+        GET_MBEAN_COUNT                                         = 11;
+    private final static int
+        GET_MBEAN_INFO                                          = 12;
+    private final static int
+        GET_OBJECT_INSTANCE                                     = 13;
+    private final static int
+        INVOKE                                                  = 14;
+    private final static int
+        IS_INSTANCE_OF                                          = 15;
+    private final static int
+        IS_REGISTERED                                           = 16;
+    private final static int
+        QUERY_MBEANS                                            = 17;
+    private final static int
+        QUERY_NAMES                                             = 18;
+    private final static int
+        REMOVE_NOTIFICATION_LISTENER                            = 19;
+    private final static int
+        REMOVE_NOTIFICATION_LISTENER_OBJECTNAME                 = 20;
+    private final static int
+        REMOVE_NOTIFICATION_LISTENER_OBJECTNAME_FILTER_HANDBACK = 21;
+    private final static int
+        SET_ATTRIBUTE                                           = 22;
+    private final static int
+        SET_ATTRIBUTES                                          = 23;
+    private final static int
+        UNREGISTER_MBEAN                                        = 24;
+
+    // SERVER NOTIFICATION
+    //--------------------
+
+    private ServerNotifForwarder serverNotifForwarder;
+    private Map<String, ?> env;
+
+    // TRACES & DEBUG
+    //---------------
+
+    private static String objects(final Object[] objs) {
+        if (objs == null)
+            return "null";
+        else
+            return Arrays.asList(objs).toString();
+    }
+
+    private static String strings(final String[] strs) {
+        return objects(strs);
+    }
+
+    private static final ClassLogger logger =
+        new ClassLogger("javax.management.remote.rmi", "RMIConnectionImpl");
+
+    private static final class CombinedClassLoader extends ClassLoader {
+
+        private final static class ClassLoaderWrapper extends ClassLoader {
+            ClassLoaderWrapper(ClassLoader cl) {
+                super(cl);
+            }
+
+            @Override
+            protected Class<?> loadClass(String name, boolean resolve)
+                    throws ClassNotFoundException {
+                return super.loadClass(name, resolve);
+            }
+        };
+
+        final ClassLoaderWrapper defaultCL;
+
+        private CombinedClassLoader(ClassLoader parent, ClassLoader defaultCL) {
+            super(parent);
+            this.defaultCL = new ClassLoaderWrapper(defaultCL);
+        }
+
+        @Override
+        protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException {
+            ReflectUtil.checkPackageAccess(name);
+            try {
+                super.loadClass(name, resolve);
+            } catch(Exception e) {
+                for(Throwable t = e; t != null; t = t.getCause()) {
+                    if(t instanceof SecurityException) {
+                        throw t==e?(SecurityException)t:new SecurityException(t.getMessage(), e);
+                    }
+                }
+            }
+            final Class<?> cl = defaultCL.loadClass(name, resolve);
+            return cl;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,2309 @@
+/*
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import com.sun.jmx.remote.internal.ClientCommunicatorAdmin;
+import com.sun.jmx.remote.internal.ClientListenerInfo;
+import com.sun.jmx.remote.internal.ClientNotifForwarder;
+import com.sun.jmx.remote.internal.rmi.ProxyRef;
+import com.sun.jmx.remote.util.ClassLogger;
+import com.sun.jmx.remote.util.EnvHelp;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Module;
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
+import java.rmi.MarshalledObject;
+import java.rmi.NoSuchObjectException;
+import java.rmi.Remote;
+import java.rmi.ServerException;
+import java.rmi.UnmarshalException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RemoteObject;
+import java.rmi.server.RemoteObjectInvocationHandler;
+import java.rmi.server.RemoteRef;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.stream.Collectors;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
+import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationFilterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.JMXAddressable;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.security.auth.Subject;
+import jdk.internal.module.Modules;
+import sun.reflect.misc.ReflectUtil;
+import sun.rmi.server.UnicastRef2;
+import sun.rmi.transport.LiveRef;
+import java.io.NotSerializableException;
+
+/**
+ * <p>A connection to a remote RMI connector.  Usually, such
+ * connections are made using {@link
+ * javax.management.remote.JMXConnectorFactory JMXConnectorFactory}.
+ * However, specialized applications can use this class directly, for
+ * example with an {@link RMIServer} stub obtained without going
+ * through JNDI.</p>
+ *
+ * @since 1.5
+ */
+public class RMIConnector implements JMXConnector, Serializable, JMXAddressable {
+
+    private static final ClassLogger logger =
+            new ClassLogger("javax.management.remote.rmi", "RMIConnector");
+
+    private static final long serialVersionUID = 817323035842634473L;
+
+    static final class Util {
+        private Util() {}
+
+        /* This method can be used by code that is deliberately violating the
+         * allowed checked casts.  Rather than marking the whole method containing
+         * the code with @SuppressWarnings, you can use a call to this method for
+         * the exact place where you need to escape the constraints.  Typically
+         * you will "import static" this method and then write either
+         *    X x = cast(y);
+         * or, if that doesn't work (e.g. X is a type variable)
+         *    Util.<X>cast(y);
+         */
+        @SuppressWarnings("unchecked")
+        public static <T> T cast(Object x) {
+            return (T) x;
+        }
+    }
+
+    private RMIConnector(RMIServer rmiServer, JMXServiceURL address,
+            Map<String, ?> environment) {
+        if (rmiServer == null && address == null) throw new
+                IllegalArgumentException("rmiServer and jmxServiceURL both null");
+        initTransients();
+
+        this.rmiServer = rmiServer;
+        this.jmxServiceURL = address;
+        if (environment == null) {
+            this.env = Collections.emptyMap();
+        } else {
+            EnvHelp.checkAttributes(environment);
+            this.env = Collections.unmodifiableMap(environment);
+        }
+    }
+
+    /**
+     * <p>Constructs an {@code RMIConnector} that will connect
+     * the RMI connector server with the given address.</p>
+     *
+     * <p>The address can refer directly to the connector server,
+     * using the following syntax:</p>
+     *
+     * <pre>
+     * service:jmx:rmi://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>
+     * </pre>
+     *
+     * <p>(Here, the square brackets {@code []} are not part of the
+     * address but indicate that the host and port are optional.)</p>
+     *
+     * <p>The address can instead indicate where to find an RMI stub
+     * through JNDI, using the following syntax:</p>
+     *
+     * <pre>
+     * service:jmx:rmi://<em>[host[:port]]</em>/jndi/<em>jndi-name</em>
+     * </pre>
+     *
+     * <p>An implementation may also recognize additional address
+     * syntaxes, for example:</p>
+     *
+     * <pre>
+     * service:jmx:iiop://<em>[host[:port]]</em>/stub/<em>encoded-stub</em>
+     * </pre>
+     *
+     * @param url the address of the RMI connector server.
+     *
+     * @param environment additional attributes specifying how to make
+     * the connection.  For JNDI-based addresses, these attributes can
+     * usefully include JNDI attributes recognized by {@link
+     * InitialContext#InitialContext(Hashtable) InitialContext}.  This
+     * parameter can be null, which is equivalent to an empty Map.
+     *
+     * @exception IllegalArgumentException if {@code url}
+     * is null.
+     */
+    public RMIConnector(JMXServiceURL url, Map<String,?> environment) {
+        this(null, url, environment);
+    }
+
+    /**
+     * <p>Constructs an {@code RMIConnector} using the given RMI stub.
+     *
+     * @param rmiServer an RMI stub representing the RMI connector server.
+     * @param environment additional attributes specifying how to make
+     * the connection.  This parameter can be null, which is
+     * equivalent to an empty Map.
+     *
+     * @exception IllegalArgumentException if {@code rmiServer}
+     * is null.
+     */
+    public RMIConnector(RMIServer rmiServer, Map<String,?> environment) {
+        this(rmiServer, null, environment);
+    }
+
+    /**
+     * <p>Returns a string representation of this object.  In general,
+     * the {@code toString} method returns a string that
+     * "textually represents" this object. The result should be a
+     * concise but informative representation that is easy for a
+     * person to read.</p>
+     *
+     * @return a String representation of this object.
+     **/
+    @Override
+    public String toString() {
+        final StringBuilder b = new StringBuilder(this.getClass().getName());
+        b.append(":");
+        if (rmiServer != null) {
+            b.append(" rmiServer=").append(rmiServer.toString());
+        }
+        if (jmxServiceURL != null) {
+            if (rmiServer!=null) b.append(",");
+            b.append(" jmxServiceURL=").append(jmxServiceURL.toString());
+        }
+        return b.toString();
+    }
+
+    /**
+     * <p>The address of this connector.</p>
+     *
+     * @return the address of this connector, or null if it
+     * does not have one.
+     *
+     * @since 1.6
+     */
+    public JMXServiceURL getAddress() {
+        return jmxServiceURL;
+    }
+
+    //--------------------------------------------------------------------
+    // implements JMXConnector interface
+    //--------------------------------------------------------------------
+
+    /**
+     * @throws IOException if the connection could not be made because of a
+     *   communication problem
+     */
+    public void connect() throws IOException {
+        connect(null);
+    }
+
+    /**
+     * @throws IOException if the connection could not be made because of a
+     *   communication problem
+     */
+    public synchronized void connect(Map<String,?> environment)
+    throws IOException {
+        final boolean tracing = logger.traceOn();
+        String        idstr   = (tracing?"["+this.toString()+"]":null);
+
+        if (terminated) {
+            logger.trace("connect",idstr + " already closed.");
+            throw new IOException("Connector closed");
+        }
+        if (connected) {
+            logger.trace("connect",idstr + " already connected.");
+            return;
+        }
+
+        try {
+            if (tracing) logger.trace("connect",idstr + " connecting...");
+
+            final Map<String, Object> usemap =
+                    new HashMap<String, Object>((this.env==null) ?
+                        Collections.<String, Object>emptyMap() : this.env);
+
+
+            if (environment != null) {
+                EnvHelp.checkAttributes(environment);
+                usemap.putAll(environment);
+            }
+
+            // Get RMIServer stub from directory or URL encoding if needed.
+            if (tracing) logger.trace("connect",idstr + " finding stub...");
+            RMIServer stub = (rmiServer!=null)?rmiServer:
+                findRMIServer(jmxServiceURL, usemap);
+
+            // Check for secure RMIServer stub if the corresponding
+            // client-side environment property is set to "true".
+            //
+            String stringBoolean =  (String) usemap.get("jmx.remote.x.check.stub");
+            boolean checkStub = EnvHelp.computeBooleanFromString(stringBoolean);
+
+            if (checkStub) checkStub(stub, rmiServerImplStubClass);
+
+            if (tracing) logger.trace("connect",idstr + " connecting stub...");
+            idstr = (tracing?"["+this.toString()+"]":null);
+
+            // Calling newClient on the RMIServer stub.
+            if (tracing)
+                logger.trace("connect",idstr + " getting connection...");
+            Object credentials = usemap.get(CREDENTIALS);
+
+            try {
+                connection = getConnection(stub, credentials, checkStub);
+            } catch (java.rmi.RemoteException re) {
+                throw re;
+            }
+
+            // Always use one of:
+            //   ClassLoader provided in Map at connect time,
+            //   or contextClassLoader at connect time.
+            if (tracing)
+                logger.trace("connect",idstr + " getting class loader...");
+            defaultClassLoader = EnvHelp.resolveClientClassLoader(usemap);
+
+            usemap.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,
+                    defaultClassLoader);
+
+            rmiNotifClient = new RMINotifClient(defaultClassLoader, usemap);
+
+            env = usemap;
+            final long checkPeriod = EnvHelp.getConnectionCheckPeriod(usemap);
+            communicatorAdmin = new RMIClientCommunicatorAdmin(checkPeriod);
+
+            connected = true;
+
+            // The connectionId variable is used in doStart(), when
+            // reconnecting, to identify the "old" connection.
+            //
+            connectionId = getConnectionId();
+
+            Notification connectedNotif =
+                    new JMXConnectionNotification(JMXConnectionNotification.OPENED,
+                    this,
+                    connectionId,
+                    clientNotifSeqNo++,
+                    "Successful connection",
+                    null);
+            sendNotification(connectedNotif);
+
+            if (tracing) logger.trace("connect",idstr + " done...");
+        } catch (IOException e) {
+            if (tracing)
+                logger.trace("connect",idstr + " failed to connect: " + e);
+            throw e;
+        } catch (RuntimeException e) {
+            if (tracing)
+                logger.trace("connect",idstr + " failed to connect: " + e);
+            throw e;
+        } catch (NamingException e) {
+            final String msg = "Failed to retrieve RMIServer stub: " + e;
+            if (tracing) logger.trace("connect",idstr + " " + msg);
+            throw EnvHelp.initCause(new IOException(msg),e);
+        }
+    }
+
+    public synchronized String getConnectionId() throws IOException {
+        if (terminated || !connected) {
+            if (logger.traceOn())
+                logger.trace("getConnectionId","["+this.toString()+
+                        "] not connected.");
+
+            throw new IOException("Not connected");
+        }
+
+        // we do a remote call to have an IOException if the connection is broken.
+        // see the bug 4939578
+        return connection.getConnectionId();
+    }
+
+    public synchronized MBeanServerConnection getMBeanServerConnection()
+    throws IOException {
+        return getMBeanServerConnection(null);
+    }
+
+    public synchronized MBeanServerConnection
+            getMBeanServerConnection(Subject delegationSubject)
+            throws IOException {
+
+        if (terminated) {
+            if (logger.traceOn())
+                logger.trace("getMBeanServerConnection","[" + this.toString() +
+                        "] already closed.");
+            throw new IOException("Connection closed");
+        } else if (!connected) {
+            if (logger.traceOn())
+                logger.trace("getMBeanServerConnection","[" + this.toString() +
+                        "] is not connected.");
+            throw new IOException("Not connected");
+        }
+
+        return getConnectionWithSubject(delegationSubject);
+    }
+
+    public void
+            addConnectionNotificationListener(NotificationListener listener,
+            NotificationFilter filter,
+            Object handback) {
+        if (listener == null)
+            throw new NullPointerException("listener");
+        connectionBroadcaster.addNotificationListener(listener, filter,
+                handback);
+    }
+
+    public void
+            removeConnectionNotificationListener(NotificationListener listener)
+            throws ListenerNotFoundException {
+        if (listener == null)
+            throw new NullPointerException("listener");
+        connectionBroadcaster.removeNotificationListener(listener);
+    }
+
+    public void
+            removeConnectionNotificationListener(NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws ListenerNotFoundException {
+        if (listener == null)
+            throw new NullPointerException("listener");
+        connectionBroadcaster.removeNotificationListener(listener, filter,
+                handback);
+    }
+
+    private void sendNotification(Notification n) {
+        connectionBroadcaster.sendNotification(n);
+    }
+
+    public synchronized void close() throws IOException {
+        close(false);
+    }
+
+    // allows to do close after setting the flag "terminated" to true.
+    // It is necessary to avoid a deadlock, see 6296324
+    private synchronized void close(boolean intern) throws IOException {
+        final boolean tracing = logger.traceOn();
+        final boolean debug   = logger.debugOn();
+        final String  idstr   = (tracing?"["+this.toString()+"]":null);
+
+        if (!intern) {
+            // Return if already cleanly closed.
+            //
+            if (terminated) {
+                if (closeException == null) {
+                    if (tracing) logger.trace("close",idstr + " already closed.");
+                    return;
+                }
+            } else {
+                terminated = true;
+            }
+        }
+
+        if (closeException != null && tracing) {
+            // Already closed, but not cleanly. Attempt again.
+            //
+            if (tracing) {
+                logger.trace("close",idstr + " had failed: " + closeException);
+                logger.trace("close",idstr + " attempting to close again.");
+            }
+        }
+
+        String savedConnectionId = null;
+        if (connected) {
+            savedConnectionId = connectionId;
+        }
+
+        closeException = null;
+
+        if (tracing) logger.trace("close",idstr + " closing.");
+
+        if (communicatorAdmin != null) {
+            communicatorAdmin.terminate();
+        }
+
+        if (rmiNotifClient != null) {
+            try {
+                rmiNotifClient.terminate();
+                if (tracing) logger.trace("close",idstr +
+                        " RMI Notification client terminated.");
+            } catch (RuntimeException x) {
+                closeException = x;
+                if (tracing) logger.trace("close",idstr +
+                        " Failed to terminate RMI Notification client: " + x);
+                if (debug) logger.debug("close",x);
+            }
+        }
+
+        if (connection != null) {
+            try {
+                connection.close();
+                if (tracing) logger.trace("close",idstr + " closed.");
+            } catch (NoSuchObjectException nse) {
+                // OK, the server maybe closed itself.
+            } catch (IOException e) {
+                closeException = e;
+                if (tracing) logger.trace("close",idstr +
+                        " Failed to close RMIServer: " + e);
+                if (debug) logger.debug("close",e);
+            }
+        }
+
+        // Clean up MBeanServerConnection table
+        //
+        rmbscMap.clear();
+
+        /* Send notification of closure.  We don't do this if the user
+         * never called connect() on the connector, because there's no
+         * connection id in that case.  */
+
+        if (savedConnectionId != null) {
+            Notification closedNotif =
+                    new JMXConnectionNotification(JMXConnectionNotification.CLOSED,
+                    this,
+                    savedConnectionId,
+                    clientNotifSeqNo++,
+                    "Client has been closed",
+                    null);
+            sendNotification(closedNotif);
+        }
+
+        // throw exception if needed
+        //
+        if (closeException != null) {
+            if (tracing) logger.trace("close",idstr + " failed to close: " +
+                    closeException);
+            if (closeException instanceof IOException)
+                throw (IOException) closeException;
+            if (closeException instanceof RuntimeException)
+                throw (RuntimeException) closeException;
+            final IOException x =
+                    new IOException("Failed to close: " + closeException);
+            throw EnvHelp.initCause(x,closeException);
+        }
+    }
+
+    // added for re-connection
+    private Integer addListenerWithSubject(ObjectName name,
+                                           MarshalledObject<NotificationFilter> filter,
+                                           Subject delegationSubject,
+                                           boolean reconnect)
+        throws InstanceNotFoundException, IOException {
+
+        final boolean debug = logger.debugOn();
+        if (debug)
+            logger.debug("addListenerWithSubject",
+                    "(ObjectName,MarshalledObject,Subject)");
+
+        final ObjectName[] names = new ObjectName[] {name};
+        final MarshalledObject<NotificationFilter>[] filters =
+                Util.cast(new MarshalledObject<?>[] {filter});
+        final Subject[] delegationSubjects = new Subject[] {
+            delegationSubject
+        };
+
+        final Integer[] listenerIDs =
+                addListenersWithSubjects(names,filters,delegationSubjects,
+                reconnect);
+
+        if (debug) logger.debug("addListenerWithSubject","listenerID="
+                + listenerIDs[0]);
+        return listenerIDs[0];
+    }
+
+    // added for re-connection
+    private Integer[] addListenersWithSubjects(ObjectName[]       names,
+                             MarshalledObject<NotificationFilter>[] filters,
+                             Subject[]          delegationSubjects,
+                             boolean            reconnect)
+        throws InstanceNotFoundException, IOException {
+
+        final boolean debug = logger.debugOn();
+        if (debug)
+            logger.debug("addListenersWithSubjects",
+                    "(ObjectName[],MarshalledObject[],Subject[])");
+
+        final ClassLoader old = pushDefaultClassLoader();
+        Integer[] listenerIDs = null;
+
+        try {
+            listenerIDs = connection.addNotificationListeners(names,
+                    filters,
+                    delegationSubjects);
+        } catch (NoSuchObjectException noe) {
+            // maybe reconnect
+            if (reconnect) {
+                communicatorAdmin.gotIOException(noe);
+
+                listenerIDs = connection.addNotificationListeners(names,
+                        filters,
+                        delegationSubjects);
+            } else {
+                throw noe;
+            }
+        } catch (IOException ioe) {
+            // send a failed notif if necessary
+            communicatorAdmin.gotIOException(ioe);
+        } finally {
+            popDefaultClassLoader(old);
+        }
+
+        if (debug) logger.debug("addListenersWithSubjects","registered "
+                + ((listenerIDs==null)?0:listenerIDs.length)
+                + " listener(s)");
+        return listenerIDs;
+    }
+
+    //--------------------------------------------------------------------
+    // Implementation of MBeanServerConnection
+    //--------------------------------------------------------------------
+    private class RemoteMBeanServerConnection implements MBeanServerConnection {
+        private Subject delegationSubject;
+
+        public RemoteMBeanServerConnection() {
+            this(null);
+        }
+
+        public RemoteMBeanServerConnection(Subject delegationSubject) {
+            this.delegationSubject = delegationSubject;
+        }
+
+        public ObjectInstance createMBean(String className,
+                ObjectName name)
+                throws ReflectionException,
+                InstanceAlreadyExistsException,
+                MBeanRegistrationException,
+                MBeanException,
+                NotCompliantMBeanException,
+                IOException {
+            if (logger.debugOn())
+                logger.debug("createMBean(String,ObjectName)",
+                        "className=" + className + ", name=" +
+                        name);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.createMBean(className,
+                        name,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.createMBean(className,
+                        name,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public ObjectInstance createMBean(String className,
+                ObjectName name,
+                ObjectName loaderName)
+                throws ReflectionException,
+                InstanceAlreadyExistsException,
+                MBeanRegistrationException,
+                MBeanException,
+                NotCompliantMBeanException,
+                InstanceNotFoundException,
+                IOException {
+
+            if (logger.debugOn())
+                logger.debug("createMBean(String,ObjectName,ObjectName)",
+                        "className=" + className + ", name="
+                        + name + ", loaderName="
+                        + loaderName + ")");
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.createMBean(className,
+                        name,
+                        loaderName,
+                        delegationSubject);
+
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.createMBean(className,
+                        name,
+                        loaderName,
+                        delegationSubject);
+
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public ObjectInstance createMBean(String className,
+                ObjectName name,
+                Object params[],
+                String signature[])
+                throws ReflectionException,
+                InstanceAlreadyExistsException,
+                MBeanRegistrationException,
+                MBeanException,
+                NotCompliantMBeanException,
+                IOException {
+            if (logger.debugOn())
+                logger.debug("createMBean(String,ObjectName,Object[],String[])",
+                        "className=" + className + ", name="
+                        + name + ", signature=" + strings(signature));
+
+            final MarshalledObject<Object[]> sParams =
+                    new MarshalledObject<Object[]>(params);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.createMBean(className,
+                        name,
+                        sParams,
+                        signature,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.createMBean(className,
+                        name,
+                        sParams,
+                        signature,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public ObjectInstance createMBean(String className,
+                ObjectName name,
+                ObjectName loaderName,
+                Object params[],
+                String signature[])
+                throws ReflectionException,
+                InstanceAlreadyExistsException,
+                MBeanRegistrationException,
+                MBeanException,
+                NotCompliantMBeanException,
+                InstanceNotFoundException,
+                IOException {
+            if (logger.debugOn()) logger.debug(
+                    "createMBean(String,ObjectName,ObjectName,Object[],String[])",
+                    "className=" + className + ", name=" + name + ", loaderName="
+                    + loaderName + ", signature=" + strings(signature));
+
+            final MarshalledObject<Object[]> sParams =
+                    new MarshalledObject<Object[]>(params);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.createMBean(className,
+                        name,
+                        loaderName,
+                        sParams,
+                        signature,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.createMBean(className,
+                        name,
+                        loaderName,
+                        sParams,
+                        signature,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public void unregisterMBean(ObjectName name)
+        throws InstanceNotFoundException,
+                MBeanRegistrationException,
+                IOException {
+            if (logger.debugOn())
+                logger.debug("unregisterMBean", "name=" + name);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                connection.unregisterMBean(name, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.unregisterMBean(name, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public ObjectInstance getObjectInstance(ObjectName name)
+        throws InstanceNotFoundException,
+                IOException {
+            if (logger.debugOn())
+                logger.debug("getObjectInstance", "name=" + name);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getObjectInstance(name, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getObjectInstance(name, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public Set<ObjectInstance> queryMBeans(ObjectName name,
+                QueryExp query)
+                throws IOException {
+            if (logger.debugOn()) logger.debug("queryMBeans",
+                    "name=" + name + ", query=" + query);
+
+            final MarshalledObject<QueryExp> sQuery =
+                    new MarshalledObject<QueryExp>(query);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.queryMBeans(name, sQuery, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.queryMBeans(name, sQuery, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public Set<ObjectName> queryNames(ObjectName name,
+                QueryExp query)
+                throws IOException {
+            if (logger.debugOn()) logger.debug("queryNames",
+                    "name=" + name + ", query=" + query);
+
+            final MarshalledObject<QueryExp> sQuery =
+                    new MarshalledObject<QueryExp>(query);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.queryNames(name, sQuery, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.queryNames(name, sQuery, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public boolean isRegistered(ObjectName name)
+        throws IOException {
+            if (logger.debugOn())
+                logger.debug("isRegistered", "name=" + name);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.isRegistered(name, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.isRegistered(name, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public Integer getMBeanCount()
+        throws IOException {
+            if (logger.debugOn()) logger.debug("getMBeanCount", "");
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getMBeanCount(delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getMBeanCount(delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public Object getAttribute(ObjectName name,
+                String attribute)
+                throws MBeanException,
+                AttributeNotFoundException,
+                InstanceNotFoundException,
+                ReflectionException,
+                IOException {
+            if (logger.debugOn()) logger.debug("getAttribute",
+                    "name=" + name + ", attribute="
+                    + attribute);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getAttribute(name,
+                        attribute,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getAttribute(name,
+                        attribute,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public AttributeList getAttributes(ObjectName name,
+                String[] attributes)
+                throws InstanceNotFoundException,
+                ReflectionException,
+                IOException {
+            if (logger.debugOn()) logger.debug("getAttributes",
+                    "name=" + name + ", attributes="
+                    + strings(attributes));
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getAttributes(name,
+                        attributes,
+                        delegationSubject);
+
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getAttributes(name,
+                        attributes,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+
+        public void setAttribute(ObjectName name,
+                Attribute attribute)
+                throws InstanceNotFoundException,
+                AttributeNotFoundException,
+                InvalidAttributeValueException,
+                MBeanException,
+                ReflectionException,
+                IOException {
+
+            if (logger.debugOn()) logger.debug("setAttribute",
+                    "name=" + name + ", attribute name="
+                    + attribute.getName());
+
+            final MarshalledObject<Attribute> sAttribute =
+                    new MarshalledObject<Attribute>(attribute);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                connection.setAttribute(name, sAttribute, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.setAttribute(name, sAttribute, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public AttributeList setAttributes(ObjectName name,
+                AttributeList attributes)
+                throws InstanceNotFoundException,
+                ReflectionException,
+                IOException {
+
+            if (logger.debugOn()) {
+                logger.debug("setAttributes",
+                    "name=" + name + ", attribute names="
+                    + getAttributesNames(attributes));
+            }
+
+            final MarshalledObject<AttributeList> sAttributes =
+                    new MarshalledObject<AttributeList>(attributes);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.setAttributes(name,
+                        sAttributes,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.setAttributes(name,
+                        sAttributes,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+
+        public Object invoke(ObjectName name,
+                String operationName,
+                Object params[],
+                String signature[])
+                throws InstanceNotFoundException,
+                MBeanException,
+                ReflectionException,
+                IOException {
+
+            if (logger.debugOn()) logger.debug("invoke",
+                    "name=" + name
+                    + ", operationName=" + operationName
+                    + ", signature=" + strings(signature));
+
+            final MarshalledObject<Object[]> sParams =
+                    new MarshalledObject<Object[]>(params);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.invoke(name,
+                        operationName,
+                        sParams,
+                        signature,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.invoke(name,
+                        operationName,
+                        sParams,
+                        signature,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+
+        public String getDefaultDomain()
+        throws IOException {
+            if (logger.debugOn()) logger.debug("getDefaultDomain", "");
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getDefaultDomain(delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getDefaultDomain(delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public String[] getDomains() throws IOException {
+            if (logger.debugOn()) logger.debug("getDomains", "");
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getDomains(delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getDomains(delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public MBeanInfo getMBeanInfo(ObjectName name)
+        throws InstanceNotFoundException,
+                IntrospectionException,
+                ReflectionException,
+                IOException {
+
+            if (logger.debugOn()) logger.debug("getMBeanInfo", "name=" + name);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.getMBeanInfo(name, delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.getMBeanInfo(name, delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+
+        public boolean isInstanceOf(ObjectName name,
+                String className)
+                throws InstanceNotFoundException,
+                IOException {
+            if (logger.debugOn())
+                logger.debug("isInstanceOf", "name=" + name +
+                        ", className=" + className);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                return connection.isInstanceOf(name,
+                        className,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                return connection.isInstanceOf(name,
+                        className,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public void addNotificationListener(ObjectName name,
+                ObjectName listener,
+                NotificationFilter filter,
+                Object handback)
+                throws InstanceNotFoundException,
+                IOException {
+
+            if (logger.debugOn())
+                logger.debug("addNotificationListener" +
+                        "(ObjectName,ObjectName,NotificationFilter,Object)",
+                        "name=" + name + ", listener=" + listener
+                        + ", filter=" + filter + ", handback=" + handback);
+
+            final MarshalledObject<NotificationFilter> sFilter =
+                    new MarshalledObject<NotificationFilter>(filter);
+            final MarshalledObject<Object> sHandback =
+                    new MarshalledObject<Object>(handback);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                connection.addNotificationListener(name,
+                        listener,
+                        sFilter,
+                        sHandback,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.addNotificationListener(name,
+                        listener,
+                        sFilter,
+                        sHandback,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public void removeNotificationListener(ObjectName name,
+                ObjectName listener)
+                throws InstanceNotFoundException,
+                ListenerNotFoundException,
+                IOException {
+
+            if (logger.debugOn()) logger.debug("removeNotificationListener" +
+                    "(ObjectName,ObjectName)",
+                    "name=" + name
+                    + ", listener=" + listener);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                connection.removeNotificationListener(name,
+                        listener,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.removeNotificationListener(name,
+                        listener,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        public void removeNotificationListener(ObjectName name,
+                ObjectName listener,
+                NotificationFilter filter,
+                Object handback)
+                throws InstanceNotFoundException,
+                ListenerNotFoundException,
+                IOException {
+            if (logger.debugOn())
+                logger.debug("removeNotificationListener" +
+                        "(ObjectName,ObjectName,NotificationFilter,Object)",
+                        "name=" + name
+                        + ", listener=" + listener
+                        + ", filter=" + filter
+                        + ", handback=" + handback);
+
+            final MarshalledObject<NotificationFilter> sFilter =
+                    new MarshalledObject<NotificationFilter>(filter);
+            final MarshalledObject<Object> sHandback =
+                    new MarshalledObject<Object>(handback);
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                connection.removeNotificationListener(name,
+                        listener,
+                        sFilter,
+                        sHandback,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.removeNotificationListener(name,
+                        listener,
+                        sFilter,
+                        sHandback,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+        }
+
+        // Specific Notification Handle ----------------------------------
+
+        public void addNotificationListener(ObjectName name,
+                NotificationListener listener,
+                NotificationFilter filter,
+                Object handback)
+                throws InstanceNotFoundException,
+                IOException {
+
+            final boolean debug = logger.debugOn();
+
+            if (debug)
+                logger.debug("addNotificationListener" +
+                        "(ObjectName,NotificationListener,"+
+                        "NotificationFilter,Object)",
+                        "name=" + name
+                        + ", listener=" + listener
+                        + ", filter=" + filter
+                        + ", handback=" + handback);
+
+            final Integer listenerID =
+                    addListenerWithSubject(name,
+                    new MarshalledObject<NotificationFilter>(filter),
+                    delegationSubject,true);
+            rmiNotifClient.addNotificationListener(listenerID, name, listener,
+                    filter, handback,
+                    delegationSubject);
+        }
+
+        public void removeNotificationListener(ObjectName name,
+                NotificationListener listener)
+                throws InstanceNotFoundException,
+                ListenerNotFoundException,
+                IOException {
+
+            final boolean debug = logger.debugOn();
+
+            if (debug) logger.debug("removeNotificationListener"+
+                    "(ObjectName,NotificationListener)",
+                    "name=" + name
+                    + ", listener=" + listener);
+
+            final Integer[] ret =
+                    rmiNotifClient.removeNotificationListener(name, listener);
+
+            if (debug) logger.debug("removeNotificationListener",
+                    "listenerIDs=" + objects(ret));
+
+            final ClassLoader old = pushDefaultClassLoader();
+
+            try {
+                connection.removeNotificationListeners(name,
+                        ret,
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.removeNotificationListeners(name,
+                        ret,
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+
+        }
+
+        public void removeNotificationListener(ObjectName name,
+                NotificationListener listener,
+                NotificationFilter filter,
+                Object handback)
+                throws InstanceNotFoundException,
+                ListenerNotFoundException,
+                IOException {
+            final boolean debug = logger.debugOn();
+
+            if (debug)
+                logger.debug("removeNotificationListener"+
+                        "(ObjectName,NotificationListener,"+
+                        "NotificationFilter,Object)",
+                        "name=" + name
+                        + ", listener=" + listener
+                        + ", filter=" + filter
+                        + ", handback=" + handback);
+
+            final Integer ret =
+                    rmiNotifClient.removeNotificationListener(name, listener,
+                    filter, handback);
+
+            if (debug) logger.debug("removeNotificationListener",
+                    "listenerID=" + ret);
+
+            final ClassLoader old = pushDefaultClassLoader();
+            try {
+                connection.removeNotificationListeners(name,
+                        new Integer[] {ret},
+                        delegationSubject);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.removeNotificationListeners(name,
+                        new Integer[] {ret},
+                        delegationSubject);
+            } finally {
+                popDefaultClassLoader(old);
+            }
+
+        }
+    }
+
+    //--------------------------------------------------------------------
+    private class RMINotifClient extends ClientNotifForwarder {
+        public RMINotifClient(ClassLoader cl, Map<String, ?> env) {
+            super(cl, env);
+        }
+
+        protected NotificationResult fetchNotifs(long clientSequenceNumber,
+                int maxNotifications,
+                long timeout)
+                throws IOException, ClassNotFoundException {
+
+            boolean retried = false;
+            while (true) { // used for a successful re-connection
+                           // or a transient network problem
+                try {
+                    return connection.fetchNotifications(clientSequenceNumber,
+                            maxNotifications,
+                            timeout); // return normally
+                } catch (IOException ioe) {
+                    // Examine the chain of exceptions to determine whether this
+                    // is a deserialization issue. If so - we propagate the
+                    // appropriate exception to the caller, who will then
+                    // proceed with fetching notifications one by one
+                    rethrowDeserializationException(ioe);
+
+                    try {
+                        communicatorAdmin.gotIOException(ioe);
+                        // reconnection OK, back to "while" to do again
+                    } catch (IOException ee) {
+                        boolean toClose = false;
+
+                        synchronized (this) {
+                            if (terminated) {
+                                // the connection is closed.
+                                throw ioe;
+                            } else if (retried) {
+                                toClose = true;
+                            }
+                        }
+
+                        if (toClose) {
+                            // JDK-8049303
+                            // We received an IOException - but the communicatorAdmin
+                            // did not close the connection - possibly because
+                            // the original exception was raised by a transient network
+                            // problem?
+                            // We already know that this exception is not due to a deserialization
+                            // issue as we already took care of that before involving the
+                            // communicatorAdmin. Moreover - we already made one retry attempt
+                            // at fetching the same batch of notifications - and the
+                            // problem persisted.
+                            // Since trying again doesn't seem to solve the issue, we will now
+                            // close the connection. Doing otherwise might cause the
+                            // NotifFetcher thread to die silently.
+                            final Notification failedNotif =
+                                    new JMXConnectionNotification(
+                                    JMXConnectionNotification.FAILED,
+                                    this,
+                                    connectionId,
+                                    clientNotifSeqNo++,
+                                    "Failed to communicate with the server: " + ioe.toString(),
+                                    ioe);
+
+                            sendNotification(failedNotif);
+
+                            try {
+                                close(true);
+                            } catch (Exception e) {
+                                // OK.
+                                // We are closing
+                            }
+                            throw ioe; // the connection is closed here.
+                        } else {
+                            // JDK-8049303 possible transient network problem,
+                            // let's try one more time
+                            retried = true;
+                        }
+                    }
+                }
+            }
+        }
+
+        private void rethrowDeserializationException(IOException ioe)
+                throws ClassNotFoundException, IOException {
+            // specially treating for an UnmarshalException
+            if (ioe instanceof UnmarshalException) {
+                NotSerializableException nse = new NotSerializableException();
+                nse.initCause(ioe);
+                throw nse; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs
+                           // fetch one by one with UnmarshalException
+            }
+
+            // Not serialization problem, return.
+        }
+
+        protected Integer addListenerForMBeanRemovedNotif()
+        throws IOException, InstanceNotFoundException {
+            NotificationFilterSupport clientFilter =
+                    new NotificationFilterSupport();
+            clientFilter.enableType(
+                    MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+            MarshalledObject<NotificationFilter> sFilter =
+                new MarshalledObject<NotificationFilter>(clientFilter);
+
+            Integer[] listenerIDs;
+            final ObjectName[] names =
+                new ObjectName[] {MBeanServerDelegate.DELEGATE_NAME};
+            final MarshalledObject<NotificationFilter>[] filters =
+                Util.cast(new MarshalledObject<?>[] {sFilter});
+            final Subject[] subjects = new Subject[] {null};
+            try {
+                listenerIDs =
+                        connection.addNotificationListeners(names,
+                        filters,
+                        subjects);
+
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                listenerIDs =
+                        connection.addNotificationListeners(names,
+                        filters,
+                        subjects);
+            }
+            return listenerIDs[0];
+        }
+
+        protected void removeListenerForMBeanRemovedNotif(Integer id)
+        throws IOException, InstanceNotFoundException,
+                ListenerNotFoundException {
+            try {
+                connection.removeNotificationListeners(
+                        MBeanServerDelegate.DELEGATE_NAME,
+                        new Integer[] {id},
+                        null);
+            } catch (IOException ioe) {
+                communicatorAdmin.gotIOException(ioe);
+
+                connection.removeNotificationListeners(
+                        MBeanServerDelegate.DELEGATE_NAME,
+                        new Integer[] {id},
+                        null);
+            }
+
+        }
+
+        protected void lostNotifs(String message, long number) {
+            final String notifType = JMXConnectionNotification.NOTIFS_LOST;
+
+            final JMXConnectionNotification n =
+                new JMXConnectionNotification(notifType,
+                                              RMIConnector.this,
+                                              connectionId,
+                                              clientNotifCounter++,
+                                              message,
+                                              Long.valueOf(number));
+            sendNotification(n);
+        }
+    }
+
+    private class RMIClientCommunicatorAdmin extends ClientCommunicatorAdmin {
+        public RMIClientCommunicatorAdmin(long period) {
+            super(period);
+        }
+
+        @Override
+        public void gotIOException(IOException ioe) throws IOException {
+            if (ioe instanceof NoSuchObjectException) {
+                // need to restart
+                super.gotIOException(ioe);
+
+                return;
+            }
+
+            // check if the connection is broken
+            try {
+                connection.getDefaultDomain(null);
+            } catch (IOException ioexc) {
+                boolean toClose = false;
+
+                synchronized(this) {
+                    if (!terminated) {
+                        terminated = true;
+
+                        toClose = true;
+                    }
+                }
+
+                if (toClose) {
+                    // we should close the connection,
+                    // but send a failed notif at first
+                    final Notification failedNotif =
+                            new JMXConnectionNotification(
+                            JMXConnectionNotification.FAILED,
+                            this,
+                            connectionId,
+                            clientNotifSeqNo++,
+                            "Failed to communicate with the server: "+ioe.toString(),
+                            ioe);
+
+                    sendNotification(failedNotif);
+
+                    try {
+                        close(true);
+                    } catch (Exception e) {
+                        // OK.
+                        // We are closing
+                    }
+                }
+            }
+
+            // forward the exception
+            if (ioe instanceof ServerException) {
+                /* Need to unwrap the exception.
+                   Some user-thrown exception at server side will be wrapped by
+                   rmi into a ServerException.
+                   For example, a RMIConnnectorServer will wrap a
+                   ClassNotFoundException into a UnmarshalException, and rmi
+                   will throw a ServerException at client side which wraps this
+                   UnmarshalException.
+                   No failed notif here.
+                 */
+                Throwable tt = ((ServerException)ioe).detail;
+
+                if (tt instanceof IOException) {
+                    throw (IOException)tt;
+                } else if (tt instanceof RuntimeException) {
+                    throw (RuntimeException)tt;
+                }
+            }
+
+            throw ioe;
+        }
+
+        public void reconnectNotificationListeners(ClientListenerInfo[] old) throws IOException {
+            final int len  = old.length;
+            int i;
+
+            ClientListenerInfo[] clis = new ClientListenerInfo[len];
+
+            final Subject[] subjects = new Subject[len];
+            final ObjectName[] names = new ObjectName[len];
+            final NotificationListener[] listeners = new NotificationListener[len];
+            final NotificationFilter[] filters = new NotificationFilter[len];
+            final MarshalledObject<NotificationFilter>[] mFilters =
+                    Util.cast(new MarshalledObject<?>[len]);
+            final Object[] handbacks = new Object[len];
+
+            for (i=0;i<len;i++) {
+                subjects[i]  = old[i].getDelegationSubject();
+                names[i]     = old[i].getObjectName();
+                listeners[i] = old[i].getListener();
+                filters[i]   = old[i].getNotificationFilter();
+                mFilters[i]  = new MarshalledObject<NotificationFilter>(filters[i]);
+                handbacks[i] = old[i].getHandback();
+            }
+
+            try {
+                Integer[] ids = addListenersWithSubjects(names,mFilters,subjects,false);
+
+                for (i=0;i<len;i++) {
+                    clis[i] = new ClientListenerInfo(ids[i],
+                            names[i],
+                            listeners[i],
+                            filters[i],
+                            handbacks[i],
+                            subjects[i]);
+                }
+
+                rmiNotifClient.postReconnection(clis);
+
+                return;
+            } catch (InstanceNotFoundException infe) {
+                // OK, we will do one by one
+            }
+
+            int j = 0;
+            for (i=0;i<len;i++) {
+                try {
+                    Integer id = addListenerWithSubject(names[i],
+                            new MarshalledObject<NotificationFilter>(filters[i]),
+                            subjects[i],
+                            false);
+
+                    clis[j++] = new ClientListenerInfo(id,
+                            names[i],
+                            listeners[i],
+                            filters[i],
+                            handbacks[i],
+                            subjects[i]);
+                } catch (InstanceNotFoundException infe) {
+                    logger.warning("reconnectNotificationListeners",
+                            "Can't reconnect listener for " +
+                            names[i]);
+                }
+            }
+
+            if (j != len) {
+                ClientListenerInfo[] tmp = clis;
+                clis = new ClientListenerInfo[j];
+                System.arraycopy(tmp, 0, clis, 0, j);
+            }
+
+            rmiNotifClient.postReconnection(clis);
+        }
+
+        protected void checkConnection() throws IOException {
+            if (logger.debugOn())
+                logger.debug("RMIClientCommunicatorAdmin-checkConnection",
+                        "Calling the method getDefaultDomain.");
+
+            connection.getDefaultDomain(null);
+        }
+
+        protected void doStart() throws IOException {
+            // Get RMIServer stub from directory or URL encoding if needed.
+            RMIServer stub;
+            try {
+                stub = (rmiServer!=null)?rmiServer:
+                    findRMIServer(jmxServiceURL, env);
+            } catch (NamingException ne) {
+                throw new IOException("Failed to get a RMI stub: "+ne);
+            }
+
+            // Calling newClient on the RMIServer stub.
+            Object credentials = env.get(CREDENTIALS);
+            connection = stub.newClient(credentials);
+
+            // notif issues
+            final ClientListenerInfo[] old = rmiNotifClient.preReconnection();
+
+            reconnectNotificationListeners(old);
+
+            connectionId = getConnectionId();
+
+            Notification reconnectedNotif =
+                    new JMXConnectionNotification(JMXConnectionNotification.OPENED,
+                    this,
+                    connectionId,
+                    clientNotifSeqNo++,
+                    "Reconnected to server",
+                    null);
+            sendNotification(reconnectedNotif);
+
+        }
+
+        protected void doStop() {
+            try {
+                close();
+            } catch (IOException ioe) {
+                logger.warning("RMIClientCommunicatorAdmin-doStop",
+                        "Failed to call the method close():" + ioe);
+                logger.debug("RMIClientCommunicatorAdmin-doStop",ioe);
+            }
+        }
+    }
+
+    //--------------------------------------------------------------------
+    // Private stuff - Serialization
+    //--------------------------------------------------------------------
+    /**
+     * Read RMIConnector fields from an {@link java.io.ObjectInputStream
+     * ObjectInputStream}.
+     * Calls {@code s.defaultReadObject()} and then initializes
+     * all transient variables that need initializing.
+     * @param s The ObjectInputStream to read from.
+     * @exception InvalidObjectException if none of <var>rmiServer</var> stub
+     *    or <var>jmxServiceURL</var> are set.
+     * @see #RMIConnector(JMXServiceURL,Map)
+     * @see #RMIConnector(RMIServer,Map)
+     **/
+    private void readObject(java.io.ObjectInputStream s)
+    throws IOException, ClassNotFoundException  {
+        s.defaultReadObject();
+
+        if (rmiServer == null && jmxServiceURL == null) throw new
+                InvalidObjectException("rmiServer and jmxServiceURL both null");
+
+        initTransients();
+    }
+
+    /**
+     * Writes the RMIConnector fields to an {@link java.io.ObjectOutputStream
+     * ObjectOutputStream}.
+     * <p>Connects the underlying RMIServer stub to an ORB, if needed,
+     * before serializing it. This is done using the environment
+     * map that was provided to the constructor, if any, and as documented
+     * in {@link javax.management.remote.rmi}.</p>
+     * <p>This method then calls {@code s.defaultWriteObject()}.
+     * Usually, <var>rmiServer</var> is null if this object
+     * was constructed with a JMXServiceURL, and <var>jmxServiceURL</var>
+     * is null if this object is constructed with a RMIServer stub.
+     * <p>Note that the environment Map is not serialized, since the objects
+     * it contains are assumed to be contextual and relevant only
+     * with respect to the local environment (class loader, ORB, etc...).</p>
+     * <p>After an RMIConnector is deserialized, it is assumed that the
+     * user will call {@link #connect(Map)}, providing a new Map that
+     * can contain values which are contextually relevant to the new
+     * local environment.</p>
+     * <p>Since connection to the ORB is needed prior to serializing, and
+     * since the ORB to connect to is one of those contextual parameters,
+     * it is not recommended to re-serialize a just de-serialized object -
+     * as the de-serialized object has no map. Thus, when an RMIConnector
+     * object is needed for serialization or transmission to a remote
+     * application, it is recommended to obtain a new RMIConnector stub
+     * by calling {@link RMIConnectorServer#toJMXConnector(Map)}.</p>
+     * @param s The ObjectOutputStream to write to.
+     * @exception InvalidObjectException if none of <var>rmiServer</var> stub
+     *    or <var>jmxServiceURL</var> are set.
+     * @see #RMIConnector(JMXServiceURL,Map)
+     * @see #RMIConnector(RMIServer,Map)
+     **/
+    private void writeObject(java.io.ObjectOutputStream s)
+    throws IOException {
+        if (rmiServer == null && jmxServiceURL == null) throw new
+                InvalidObjectException("rmiServer and jmxServiceURL both null.");
+        s.defaultWriteObject();
+    }
+
+    // Initialization of transient variables.
+    private void initTransients() {
+        rmbscMap = new WeakHashMap<Subject, WeakReference<MBeanServerConnection>>();
+        connected = false;
+        terminated = false;
+
+        connectionBroadcaster = new NotificationBroadcasterSupport();
+    }
+
+    //--------------------------------------------------------------------
+    // Private stuff - Check if stub can be trusted.
+    //--------------------------------------------------------------------
+
+    private static void checkStub(Remote stub,
+            Class<?> stubClass) {
+
+        // Check remote stub is from the expected class.
+        //
+        if (stub.getClass() != stubClass) {
+            if (!Proxy.isProxyClass(stub.getClass())) {
+                throw new SecurityException(
+                        "Expecting a " + stubClass.getName() + " stub!");
+            } else {
+                InvocationHandler handler = Proxy.getInvocationHandler(stub);
+                if (handler.getClass() != RemoteObjectInvocationHandler.class)
+                    throw new SecurityException(
+                            "Expecting a dynamic proxy instance with a " +
+                            RemoteObjectInvocationHandler.class.getName() +
+                            " invocation handler!");
+                else
+                    stub = (Remote) handler;
+            }
+        }
+
+        // Check RemoteRef in stub is from the expected class
+        // "sun.rmi.server.UnicastRef2".
+        //
+        RemoteRef ref = ((RemoteObject)stub).getRef();
+        if (ref.getClass() != UnicastRef2.class)
+            throw new SecurityException(
+                    "Expecting a " + UnicastRef2.class.getName() +
+                    " remote reference in stub!");
+
+        // Check RMIClientSocketFactory in stub is from the expected class
+        // "javax.rmi.ssl.SslRMIClientSocketFactory".
+        //
+        LiveRef liveRef = ((UnicastRef2)ref).getLiveRef();
+        RMIClientSocketFactory csf = liveRef.getClientSocketFactory();
+        if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class)
+            throw new SecurityException(
+                    "Expecting a " + SslRMIClientSocketFactory.class.getName() +
+                    " RMI client socket factory in stub!");
+    }
+
+    //--------------------------------------------------------------------
+    // Private stuff - RMIServer creation
+    //--------------------------------------------------------------------
+
+    private RMIServer findRMIServer(JMXServiceURL directoryURL,
+            Map<String, Object> environment)
+            throws NamingException, IOException {
+
+        String path = directoryURL.getURLPath();
+        int end = path.indexOf(';');
+        if (end < 0) end = path.length();
+        if (path.startsWith("/jndi/"))
+            return findRMIServerJNDI(path.substring(6,end), environment);
+        else if (path.startsWith("/stub/"))
+            return findRMIServerJRMP(path.substring(6,end), environment);
+        else {
+            final String msg = "URL path must begin with /jndi/ or /stub/ " +
+                    "or /ior/: " + path;
+            throw new MalformedURLException(msg);
+        }
+    }
+
+    /**
+     * Lookup the RMIServer stub in a directory.
+     * @param jndiURL A JNDI URL indicating the location of the Stub
+     *                (see {@link javax.management.remote.rmi}), e.g.:
+     *   <ul><li>{@code rmi://registry-host:port/rmi-stub-name}</li>
+     *       <li>or {@code ldap://ldap-host:port/java-container-dn}</li>
+     *   </ul>
+     * @param env the environment Map passed to the connector.
+     * @return The retrieved RMIServer stub.
+     * @exception NamingException if the stub couldn't be found.
+     **/
+    private RMIServer findRMIServerJNDI(String jndiURL, Map<String, ?> env)
+            throws NamingException {
+
+        InitialContext ctx = new InitialContext(EnvHelp.mapToHashtable(env));
+
+        Object objref = ctx.lookup(jndiURL);
+        ctx.close();
+
+        return narrowJRMPServer(objref);
+    }
+
+    private static RMIServer narrowJRMPServer(Object objref) {
+
+        return (RMIServer) objref;
+    }
+
+    private RMIServer findRMIServerJRMP(String base64, Map<String, ?> env)
+        throws IOException {
+        final byte[] serialized;
+        try {
+            serialized = base64ToByteArray(base64);
+        } catch (IllegalArgumentException e) {
+            throw new MalformedURLException("Bad BASE64 encoding: " +
+                    e.getMessage());
+        }
+        final ByteArrayInputStream bin = new ByteArrayInputStream(serialized);
+
+        final ClassLoader loader = EnvHelp.resolveClientClassLoader(env);
+        final ObjectInputStream oin =
+                (loader == null) ?
+                    new ObjectInputStream(bin) :
+                    new ObjectInputStreamWithLoader(bin, loader);
+        final Object stub;
+        try {
+            stub = oin.readObject();
+        } catch (ClassNotFoundException e) {
+            throw new MalformedURLException("Class not found: " + e);
+        }
+        return (RMIServer)stub;
+    }
+
+    private static final class ObjectInputStreamWithLoader
+            extends ObjectInputStream {
+        ObjectInputStreamWithLoader(InputStream in, ClassLoader cl)
+        throws IOException, IllegalArgumentException {
+            super(in);
+            if (cl == null ) {
+              throw new IllegalArgumentException("class loader is null");
+            }
+            this.loader = cl;
+        }
+
+        @Override
+        protected Class<?> resolveClass(ObjectStreamClass classDesc)
+                throws IOException, ClassNotFoundException {
+            String name = classDesc.getName();
+            ReflectUtil.checkPackageAccess(name);
+            return Class.forName(name, false, Objects.requireNonNull(loader));
+        }
+
+        private final ClassLoader loader;
+    }
+
+    private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) {
+        MBeanServerConnection conn = null;
+
+        if (delegationSubject == null) {
+            if (nullSubjectConnRef == null
+                    || (conn = nullSubjectConnRef.get()) == null) {
+                conn = new RemoteMBeanServerConnection(null);
+                nullSubjectConnRef = new WeakReference<MBeanServerConnection>(conn);
+            }
+        } else {
+            WeakReference<MBeanServerConnection> wr = rmbscMap.get(delegationSubject);
+            if (wr == null || (conn = wr.get()) == null) {
+                conn = new RemoteMBeanServerConnection(delegationSubject);
+                rmbscMap.put(delegationSubject, new WeakReference<MBeanServerConnection>(conn));
+            }
+        }
+        return conn;
+    }
+
+    /*
+       The following section of code avoids a class loading problem
+       with RMI.  The problem is that an RMI stub, when deserializing
+       a remote method return value or exception, will first of all
+       consult the first non-bootstrap class loader it finds in the
+       call stack.  This can lead to behavior that is not portable
+       between implementations of the JMX Remote API.  Notably, an
+       implementation on J2SE 1.4 will find the RMI stub's loader on
+       the stack.  But in J2SE 5, this stub is loaded by the
+       bootstrap loader, so RMI will find the loader of the user code
+       that called an MBeanServerConnection method.
+
+       To avoid this problem, we take advantage of what the RMI stub
+       is doing internally.  Each remote call will end up calling
+       ref.invoke(...), where ref is the RemoteRef parameter given to
+       the RMI stub's constructor.  It is within this call that the
+       deserialization will happen.  So we fabricate our own RemoteRef
+       that delegates everything to the "real" one but that is loaded
+       by a class loader that knows no other classes.  The class
+       loader NoCallStackClassLoader does this: the RemoteRef is an
+       instance of the class named by proxyRefClassName, which is
+       fabricated by the class loader using byte code that is defined
+       by the string below.
+
+       The call stack when the deserialization happens is thus this:
+       MBeanServerConnection.getAttribute (or whatever)
+       -> RMIConnectionImpl_Stub.getAttribute
+          -> ProxyRef.invoke(...getAttribute...)
+             -> UnicastRef.invoke(...getAttribute...)
+                -> internal RMI stuff
+
+       Here UnicastRef is the RemoteRef created when the stub was
+       deserialized (which is of some RMI internal class).  It and the
+       "internal RMI stuff" are loaded by the bootstrap loader, so are
+       transparent to the stack search.  The first non-bootstrap
+       loader found is our ProxyRefLoader, as required.
+
+       In a future version of this code as integrated into J2SE 5,
+       this workaround could be replaced by direct access to the
+       internals of RMI.  For now, we use the same code base for J2SE
+       and for the standalone Reference Implementation.
+
+       The byte code below encodes the following class, compiled using
+       J2SE 1.4.2 with the -g:none option.
+
+        package jdk.jmx.remote.internal.rmi;
+
+        import java.lang.reflect.Method;
+        import java.rmi.Remote;
+        import java.rmi.server.RemoteRef;
+        import com.sun.jmx.remote.internal.rmi.ProxyRef;
+
+        public class PRef extends ProxyRef {
+            public PRef(RemoteRef ref) {
+                super(ref);
+            }
+
+            public Object invoke(Remote obj, Method method,
+                                 Object[] params, long opnum)
+                    throws Exception {
+                return ref.invoke(obj, method, params, opnum);
+            }
+        }
+     */
+
+    private static final String rmiServerImplStubClassName =
+        RMIServer.class.getName() + "Impl_Stub";
+    private static final Class<?> rmiServerImplStubClass;
+    private static final String rmiConnectionImplStubClassName =
+            RMIConnection.class.getName() + "Impl_Stub";
+    private static final Class<?> rmiConnectionImplStubClass;
+    private static final String pRefClassName =
+        "jdk.jmx.remote.internal.rmi.PRef";
+    private static final Constructor<?> proxyRefConstructor;
+    static {
+        final String pRefByteCodeString =
+                "\312\376\272\276\0\0\0\65\0\27\12\0\5\0\15\11\0\4\0\16\13\0\17"+
+                "\0\20\7\0\21\7\0\22\1\0\6<init>\1\0\36(Ljava/rmi/server/Remote"+
+                "Ref;)V\1\0\4Code\1\0\6invoke\1\0S(Ljava/rmi/Remote;Ljava/lang/"+
+                "reflect/Method;[Ljava/lang/Object;J)Ljava/lang/Object;\1\0\12E"+
+                "xceptions\7\0\23\14\0\6\0\7\14\0\24\0\25\7\0\26\14\0\11\0\12\1"+
+                "\0 jdk/jmx/remote/internal/rmi/PRef\1\0(com/sun/jmx/remote/int"+
+                "ernal/rmi/ProxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Lj"+
+                "ava/rmi/server/RemoteRef;\1\0\31java/rmi/server/RemoteRef\0!\0"+
+                "\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"+
+                "\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"+
+                "\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"+
+                "\4\0\1\0\14\0\0";
+        final byte[] pRefByteCode =
+                NoCallStackClassLoader.stringToBytes(pRefByteCodeString);
+        PrivilegedExceptionAction<Constructor<?>> action =
+                new PrivilegedExceptionAction<Constructor<?>>() {
+            public Constructor<?> run() throws Exception {
+                Class<RMIConnector> thisClass = RMIConnector.class;
+                ClassLoader thisLoader = thisClass.getClassLoader();
+                ProtectionDomain thisProtectionDomain =
+                        thisClass.getProtectionDomain();
+
+                String proxyRefCName = ProxyRef.class.getName();
+                ClassLoader cl =
+                        new NoCallStackClassLoader(pRefClassName,
+                        pRefByteCode,
+                        new String[] { proxyRefCName },
+                        thisLoader,
+                        thisProtectionDomain);
+
+                Module jmxModule = ProxyRef.class.getModule();
+                Module rmiModule = RemoteRef.class.getModule();
+
+                String pkg = packageOf(pRefClassName);
+                assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName));
+                Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg));
+
+                // jdk.remoteref needs to read to java.base and jmxModule
+                Modules.addReads(m, Object.class.getModule());
+                Modules.addReads(m, jmxModule);
+                Modules.addReads(m, rmiModule);
+
+                // jdk.remoteref needs access to ProxyRef class
+                Modules.addExports(jmxModule, packageOf(proxyRefCName), m);
+
+                // java.management needs to instantiate the fabricated RemoteRef class
+                Modules.addReads(jmxModule, m);
+                Modules.addExports(m, pkg, jmxModule);
+
+                Class<?> c = cl.loadClass(pRefClassName);
+                return c.getConstructor(RemoteRef.class);
+            }
+        };
+
+        Class<?> serverStubClass;
+        try {
+            serverStubClass = Class.forName(rmiServerImplStubClassName);
+        } catch (Exception e) {
+            logger.error("<clinit>",
+                    "Failed to instantiate " +
+                    rmiServerImplStubClassName + ": " + e);
+            logger.debug("<clinit>",e);
+            serverStubClass = null;
+        }
+        rmiServerImplStubClass = serverStubClass;
+
+        Class<?> stubClass;
+        Constructor<?> constr;
+        try {
+            stubClass = Class.forName(rmiConnectionImplStubClassName);
+            constr = (Constructor<?>) AccessController.doPrivileged(action);
+        } catch (Exception e) {
+            logger.error("<clinit>",
+                    "Failed to initialize proxy reference constructor "+
+                    "for " + rmiConnectionImplStubClassName + ": " + e);
+            logger.debug("<clinit>",e);
+            stubClass = null;
+            constr = null;
+        }
+        rmiConnectionImplStubClass = stubClass;
+        proxyRefConstructor = constr;
+    }
+
+    private static String packageOf(String cn) {
+        int i = cn.lastIndexOf('.');
+        return i > 0 ? cn.substring(0, i) : "";
+    }
+
+    private static RMIConnection shadowJrmpStub(RemoteObject stub)
+    throws InstantiationException, IllegalAccessException,
+            InvocationTargetException, ClassNotFoundException,
+            NoSuchMethodException {
+        RemoteRef ref = stub.getRef();
+        RemoteRef proxyRef = (RemoteRef)
+            proxyRefConstructor.newInstance(new Object[] {ref});
+        final Constructor<?> rmiConnectionImplStubConstructor =
+            rmiConnectionImplStubClass.getConstructor(RemoteRef.class);
+        Object[] args = {proxyRef};
+        RMIConnection proxyStub = (RMIConnection)
+        rmiConnectionImplStubConstructor.newInstance(args);
+        return proxyStub;
+    }
+
+    private static RMIConnection getConnection(RMIServer server,
+            Object credentials,
+            boolean checkStub)
+            throws IOException {
+        RMIConnection c = server.newClient(credentials);
+        if (checkStub) checkStub(c, rmiConnectionImplStubClass);
+        try {
+            if (c.getClass() == rmiConnectionImplStubClass)
+                return shadowJrmpStub((RemoteObject) c);
+            logger.trace("getConnection",
+                    "Did not wrap " + c.getClass() + " to foil " +
+                    "stack search for classes: class loading semantics " +
+                    "may be incorrect");
+        } catch (Exception e) {
+            logger.error("getConnection",
+                    "Could not wrap " + c.getClass() + " to foil " +
+                    "stack search for classes: class loading semantics " +
+                    "may be incorrect: " + e);
+            logger.debug("getConnection",e);
+            // so just return the original stub, which will work for all
+            // but the most exotic class loading situations
+        }
+        return c;
+    }
+
+    private static byte[] base64ToByteArray(String s) {
+        int sLen = s.length();
+        int numGroups = sLen/4;
+        if (4*numGroups != sLen)
+            throw new IllegalArgumentException(
+                    "String length must be a multiple of four.");
+        int missingBytesInLastGroup = 0;
+        int numFullGroups = numGroups;
+        if (sLen != 0) {
+            if (s.charAt(sLen-1) == '=') {
+                missingBytesInLastGroup++;
+                numFullGroups--;
+            }
+            if (s.charAt(sLen-2) == '=')
+                missingBytesInLastGroup++;
+        }
+        byte[] result = new byte[3*numGroups - missingBytesInLastGroup];
+
+        // Translate all full groups from base64 to byte array elements
+        int inCursor = 0, outCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int ch0 = base64toInt(s.charAt(inCursor++));
+            int ch1 = base64toInt(s.charAt(inCursor++));
+            int ch2 = base64toInt(s.charAt(inCursor++));
+            int ch3 = base64toInt(s.charAt(inCursor++));
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+            result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            result[outCursor++] = (byte) ((ch2 << 6) | ch3);
+        }
+
+        // Translate partial group, if present
+        if (missingBytesInLastGroup != 0) {
+            int ch0 = base64toInt(s.charAt(inCursor++));
+            int ch1 = base64toInt(s.charAt(inCursor++));
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+
+            if (missingBytesInLastGroup == 1) {
+                int ch2 = base64toInt(s.charAt(inCursor++));
+                result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            }
+        }
+        // assert inCursor == s.length()-missingBytesInLastGroup;
+        // assert outCursor == result.length;
+        return result;
+    }
+
+    /**
+     * Translates the specified character, which is assumed to be in the
+     * "Base 64 Alphabet" into its equivalent 6-bit positive integer.
+     *
+     * @throws IllegalArgumentException if
+     *        c is not in the Base64 Alphabet.
+     */
+    private static int base64toInt(char c) {
+        int result;
+
+        if (c >= base64ToInt.length)
+            result = -1;
+        else
+            result = base64ToInt[c];
+
+        if (result < 0)
+            throw new IllegalArgumentException("Illegal character " + c);
+        return result;
+    }
+
+    /**
+     * This array is a lookup table that translates unicode characters
+     * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
+     * into their 6-bit positive integer equivalents.  Characters that
+     * are not in the Base64 alphabet but fall within the bounds of the
+     * array are translated to -1.
+     */
+    private static final byte base64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
+        55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+        24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+    };
+
+    //--------------------------------------------------------------------
+    // Private stuff - Find / Set default class loader
+    //--------------------------------------------------------------------
+    private ClassLoader pushDefaultClassLoader() {
+        final Thread t = Thread.currentThread();
+        final ClassLoader old =  t.getContextClassLoader();
+        if (defaultClassLoader != null)
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    t.setContextClassLoader(defaultClassLoader);
+                    return null;
+                }
+            });
+            return old;
+    }
+
+    private void popDefaultClassLoader(final ClassLoader old) {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                Thread.currentThread().setContextClassLoader(old);
+                return null;
+            }
+        });
+    }
+
+    //--------------------------------------------------------------------
+    // Private variables
+    //--------------------------------------------------------------------
+    /**
+     * @serial The RMIServer stub of the RMI JMX Connector server to
+     * which this client connector is (or will be) connected. This
+     * field can be null when <var>jmxServiceURL</var> is not
+     * null. This includes the case where <var>jmxServiceURL</var>
+     * contains a serialized RMIServer stub. If both
+     * <var>rmiServer</var> and <var>jmxServiceURL</var> are null then
+     * serialization will fail.
+     *
+     * @see #RMIConnector(RMIServer,Map)
+     **/
+    private final RMIServer rmiServer;
+
+    /**
+     * @serial The JMXServiceURL of the RMI JMX Connector server to
+     * which this client connector will be connected. This field can
+     * be null when <var>rmiServer</var> is not null. If both
+     * <var>rmiServer</var> and <var>jmxServiceURL</var> are null then
+     * serialization will fail.
+     *
+     * @see #RMIConnector(JMXServiceURL,Map)
+     **/
+    private final JMXServiceURL jmxServiceURL;
+
+    // ---------------------------------------------------------
+    // WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+    // ---------------------------------------------------------
+    // Any transient variable which needs to be initialized should
+    // be initialized in the method initTransient()
+    private transient Map<String, Object> env;
+    private transient ClassLoader defaultClassLoader;
+    private transient RMIConnection connection;
+    private transient String connectionId;
+
+    private transient long clientNotifSeqNo = 0;
+
+    private transient WeakHashMap<Subject, WeakReference<MBeanServerConnection>> rmbscMap;
+    private transient WeakReference<MBeanServerConnection> nullSubjectConnRef = null;
+
+    private transient RMINotifClient rmiNotifClient;
+    // = new RMINotifClient(new Integer(0));
+
+    private transient long clientNotifCounter = 0;
+
+    private transient boolean connected;
+    // = false;
+    private transient boolean terminated;
+    // = false;
+
+    private transient Exception closeException;
+
+    private transient NotificationBroadcasterSupport connectionBroadcaster;
+
+    private transient ClientCommunicatorAdmin communicatorAdmin;
+
+    /**
+     * A static WeakReference to an {@link org.omg.CORBA.ORB ORB} to
+     * connect unconnected stubs.
+     **/
+    private static volatile WeakReference<Object> orb = null;
+
+    // TRACES & DEBUG
+    //---------------
+    private static String objects(final Object[] objs) {
+        if (objs == null)
+            return "null";
+        else
+            return Arrays.asList(objs).toString();
+    }
+
+    private static String strings(final String[] strs) {
+        return objects(strs);
+    }
+
+    static String getAttributesNames(AttributeList attributes) {
+        return attributes != null ?
+                attributes.asList().stream()
+                        .map(Attribute::getName)
+                        .collect(Collectors.joining(", ", "[", "]"))
+                : "[]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+
+import com.sun.jmx.remote.security.MBeanServerFileAccessController;
+import com.sun.jmx.remote.util.ClassLogger;
+import com.sun.jmx.remote.util.EnvHelp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.net.MalformedURLException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.remote.JMXAuthenticator;
+
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.MBeanServerForwarder;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+/**
+ * <p>A JMX API connector server that creates RMI-based connections
+ * from remote clients.  Usually, such connector servers are made
+ * using {@link javax.management.remote.JMXConnectorServerFactory
+ * JMXConnectorServerFactory}.  However, specialized applications can
+ * use this class directly, for example with an {@link RMIServerImpl}
+ * object.</p>
+ *
+ * @since 1.5
+ */
+public class RMIConnectorServer extends JMXConnectorServer {
+    /**
+     * <p>Name of the attribute that specifies whether the {@link
+     * RMIServer} stub that represents an RMI connector server should
+     * override an existing stub at the same address.  The value
+     * associated with this attribute, if any, should be a string that
+     * is equal, ignoring case, to <code>"true"</code> or
+     * <code>"false"</code>.  The default value is false.</p>
+     */
+    public static final String JNDI_REBIND_ATTRIBUTE =
+        "jmx.remote.jndi.rebind";
+
+    /**
+     * <p>Name of the attribute that specifies the {@link
+     * RMIClientSocketFactory} for the RMI objects created in
+     * conjunction with this connector. The value associated with this
+     * attribute must be of type <code>RMIClientSocketFactory</code> and can
+     * only be specified in the <code>Map</code> argument supplied when
+     * creating a connector server.</p>
+     */
+    public static final String RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE =
+        "jmx.remote.rmi.client.socket.factory";
+
+    /**
+     * <p>Name of the attribute that specifies the {@link
+     * RMIServerSocketFactory} for the RMI objects created in
+     * conjunction with this connector. The value associated with this
+     * attribute must be of type <code>RMIServerSocketFactory</code> and can
+     * only be specified in the <code>Map</code> argument supplied when
+     * creating a connector server.</p>
+     */
+    public static final String RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE =
+        "jmx.remote.rmi.server.socket.factory";
+
+    /**
+    * Name of the attribute that specifies a list of class names acceptable
+    * as parameters to the {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()}
+    * remote method call.
+    * <p>
+    * This list of classes should correspond to the transitive closure of the
+    * credentials class (or classes) used by the installed {@linkplain JMXAuthenticator}
+    * associated with the {@linkplain RMIServer} implementation.
+    * <p>
+    * If the attribute is not set, or is null, then any class is
+    * deemed acceptable.
+    */
+    public static final String CREDENTIAL_TYPES =
+            "jmx.remote.rmi.server.credential.types";
+
+    /**
+     * <p>Makes an <code>RMIConnectorServer</code>.
+     * This is equivalent to calling {@link #RMIConnectorServer(
+     * JMXServiceURL,Map,RMIServerImpl,MBeanServer)
+     * RMIConnectorServer(directoryURL,environment,null,null)}</p>
+     *
+     * @param url the URL defining how to create the connector server.
+     * Cannot be null.
+     *
+     * @param environment attributes governing the creation and
+     * storing of the RMI object.  Can be null, which is equivalent to
+     * an empty Map.
+     *
+     * @exception IllegalArgumentException if <code>url</code> is null.
+     *
+     * @exception MalformedURLException if <code>url</code> does not
+     * conform to the syntax for an RMI connector, or if its protocol
+     * is not recognized by this implementation. Only "rmi" is valid when
+     * this constructor is used.
+     *
+     * @exception IOException if the connector server cannot be created
+     * for some reason or if it is inevitable that its {@link #start()
+     * start} method will fail.
+     */
+    public RMIConnectorServer(JMXServiceURL url, Map<String,?> environment)
+            throws IOException {
+        this(url, environment, (MBeanServer) null);
+    }
+
+    /**
+     * <p>Makes an <code>RMIConnectorServer</code> for the given MBean
+     * server.
+     * This is equivalent to calling {@link #RMIConnectorServer(
+     * JMXServiceURL,Map,RMIServerImpl,MBeanServer)
+     * RMIConnectorServer(directoryURL,environment,null,mbeanServer)}</p>
+     *
+     * @param url the URL defining how to create the connector server.
+     * Cannot be null.
+     *
+     * @param environment attributes governing the creation and
+     * storing of the RMI object.  Can be null, which is equivalent to
+     * an empty Map.
+     *
+     * @param mbeanServer the MBean server to which the new connector
+     * server is attached, or null if it will be attached by being
+     * registered as an MBean in the MBean server.
+     *
+     * @exception IllegalArgumentException if <code>url</code> is null.
+     *
+     * @exception MalformedURLException if <code>url</code> does not
+     * conform to the syntax for an RMI connector, or if its protocol
+     * is not recognized by this implementation. Only "rmi" is valid
+     * when this constructor is used.
+     *
+     * @exception IOException if the connector server cannot be created
+     * for some reason or if it is inevitable that its {@link #start()
+     * start} method will fail.
+     */
+    public RMIConnectorServer(JMXServiceURL url, Map<String,?> environment,
+                              MBeanServer mbeanServer)
+            throws IOException {
+        this(url, environment, (RMIServerImpl) null, mbeanServer);
+    }
+
+    /**
+     * <p>Makes an <code>RMIConnectorServer</code> for the given MBean
+     * server.</p>
+     *
+     * @param url the URL defining how to create the connector server.
+     * Cannot be null.
+     *
+     * @param environment attributes governing the creation and
+     * storing of the RMI object.  Can be null, which is equivalent to
+     * an empty Map.
+     *
+     * @param rmiServerImpl An implementation of the RMIServer interface,
+     *  consistent with the protocol type specified in <var>url</var>.
+     *  If this parameter is non null, the protocol type specified by
+     *  <var>url</var> is not constrained, and is assumed to be valid.
+     *  Otherwise, only "rmi" will be recognized.
+     *
+     * @param mbeanServer the MBean server to which the new connector
+     * server is attached, or null if it will be attached by being
+     * registered as an MBean in the MBean server.
+     *
+     * @exception IllegalArgumentException if <code>url</code> is null.
+     *
+     * @exception MalformedURLException if <code>url</code> does not
+     * conform to the syntax for an RMI connector, or if its protocol
+     * is not recognized by this implementation. Only "rmi" is recognized
+     * when <var>rmiServerImpl</var> is null.
+     *
+     * @exception IOException if the connector server cannot be created
+     * for some reason or if it is inevitable that its {@link #start()
+     * start} method will fail.
+     *
+     * @see #start
+     */
+    public RMIConnectorServer(JMXServiceURL url, Map<String,?> environment,
+                              RMIServerImpl rmiServerImpl,
+                              MBeanServer mbeanServer)
+            throws IOException {
+        super(mbeanServer);
+
+        if (url == null) throw new
+            IllegalArgumentException("Null JMXServiceURL");
+        if (rmiServerImpl == null) {
+            final String prt = url.getProtocol();
+            if (prt == null || !(prt.equals("rmi"))) {
+                final String msg = "Invalid protocol type: " + prt;
+                throw new MalformedURLException(msg);
+            }
+            final String urlPath = url.getURLPath();
+            if (!urlPath.equals("")
+                && !urlPath.equals("/")
+                && !urlPath.startsWith("/jndi/")) {
+                final String msg = "URL path must be empty or start with " +
+                    "/jndi/";
+                throw new MalformedURLException(msg);
+            }
+        }
+
+        if (environment == null)
+            this.attributes = Collections.emptyMap();
+        else {
+            EnvHelp.checkAttributes(environment);
+            this.attributes = Collections.unmodifiableMap(environment);
+        }
+
+        this.address = url;
+        this.rmiServerImpl = rmiServerImpl;
+    }
+
+    /**
+     * <p>Returns a client stub for this connector server.  A client
+     * stub is a serializable object whose {@link
+     * JMXConnector#connect(Map) connect} method can be used to make
+     * one new connection to this connector server.</p>
+     *
+     * @param env client connection parameters of the same sort that
+     * could be provided to {@link JMXConnector#connect(Map)
+     * JMXConnector.connect(Map)}.  Can be null, which is equivalent
+     * to an empty map.
+     *
+     * @return a client stub that can be used to make a new connection
+     * to this connector server.
+     *
+     * @exception UnsupportedOperationException if this connector
+     * server does not support the generation of client stubs.
+     *
+     * @exception IllegalStateException if the JMXConnectorServer is
+     * not started (see {@link #isActive()}).
+     *
+     * @exception IOException if a communications problem means that a
+     * stub cannot be created.
+     **/
+    public JMXConnector toJMXConnector(Map<String,?> env) throws IOException {
+        // The serialized for of rmiServerImpl is automatically
+        // a RMI server stub.
+        if (!isActive()) throw new
+            IllegalStateException("Connector is not active");
+
+        // Merge maps
+        Map<String, Object> usemap = new HashMap<String, Object>(
+                (this.attributes==null)?Collections.<String, Object>emptyMap():
+                    this.attributes);
+
+        if (env != null) {
+            EnvHelp.checkAttributes(env);
+            usemap.putAll(env);
+        }
+
+        usemap = EnvHelp.filterAttributes(usemap);
+
+        final RMIServer stub=(RMIServer)rmiServerImpl.toStub();
+
+        return new RMIConnector(stub, usemap);
+    }
+
+    /**
+     * <p>Activates the connector server, that is starts listening for
+     * client connections.  Calling this method when the connector
+     * server is already active has no effect.  Calling this method
+     * when the connector server has been stopped will generate an
+     * <code>IOException</code>.</p>
+     *
+     * <p>The behavior of this method when called for the first time
+     * depends on the parameters that were supplied at construction,
+     * as described below.</p>
+     *
+     * <p>First, an object of a subclass of {@link RMIServerImpl} is
+     * required, to export the connector server through RMI:</p>
+     *
+     * <ul>
+     *
+     * <li>If an <code>RMIServerImpl</code> was supplied to the
+     * constructor, it is used.
+     *
+     * <li>Otherwise, if the <code>JMXServiceURL</code>
+     * was null, or its protocol part was <code>rmi</code>, an object
+     * of type {@link RMIJRMPServerImpl} is created.
+     *
+     * <li>Otherwise, the implementation can create an
+     * implementation-specific {@link RMIServerImpl} or it can throw
+     * {@link MalformedURLException}.
+     *
+     * </ul>
+     *
+     * <p>If the given address includes a JNDI directory URL as
+     * specified in the package documentation for {@link
+     * javax.management.remote.rmi}, then this
+     * <code>RMIConnectorServer</code> will bootstrap by binding the
+     * <code>RMIServerImpl</code> to the given address.</p>
+     *
+     * <p>If the URL path part of the <code>JMXServiceURL</code> was
+     * empty or a single slash (<code>/</code>), then the RMI object
+     * will not be bound to a directory.  Instead, a reference to it
+     * will be encoded in the URL path of the RMIConnectorServer
+     * address (returned by {@link #getAddress()}).  The encodings for
+     * <code>rmi</code> are described in the package documentation for
+     * {@link javax.management.remote.rmi}.</p>
+     *
+     * <p>The behavior when the URL path is neither empty nor a JNDI
+     * directory URL, or when the protocol is not <code>rmi</code>,
+     * is implementation defined, and may include throwing
+     * {@link MalformedURLException} when the connector server is created
+     * or when it is started.</p>
+     *
+     * @exception IllegalStateException if the connector server has
+     * not been attached to an MBean server.
+     * @exception IOException if the connector server cannot be
+     * started.
+     */
+    public synchronized void start() throws IOException {
+        final boolean tracing = logger.traceOn();
+
+        if (state == STARTED) {
+            if (tracing) logger.trace("start", "already started");
+            return;
+        } else if (state == STOPPED) {
+            if (tracing) logger.trace("start", "already stopped");
+            throw new IOException("The server has been stopped.");
+        }
+
+        if (getMBeanServer() == null)
+            throw new IllegalStateException("This connector server is not " +
+                                            "attached to an MBean server");
+
+        // Check the internal access file property to see
+        // if an MBeanServerForwarder is to be provided
+        //
+        if (attributes != null) {
+            // Check if access file property is specified
+            //
+            String accessFile =
+                (String) attributes.get("jmx.remote.x.access.file");
+            if (accessFile != null) {
+                // Access file property specified, create an instance
+                // of the MBeanServerFileAccessController class
+                //
+                MBeanServerForwarder mbsf;
+                try {
+                    mbsf = new MBeanServerFileAccessController(accessFile);
+                } catch (IOException e) {
+                    throw EnvHelp.initCause(
+                        new IllegalArgumentException(e.getMessage()), e);
+                }
+                // Set the MBeanServerForwarder
+                //
+                setMBeanServerForwarder(mbsf);
+            }
+        }
+
+        try {
+            if (tracing) logger.trace("start", "setting default class loader");
+            defaultClassLoader = EnvHelp.resolveServerClassLoader(
+                    attributes, getMBeanServer());
+        } catch (InstanceNotFoundException infc) {
+            IllegalArgumentException x = new
+                IllegalArgumentException("ClassLoader not found: "+infc);
+            throw EnvHelp.initCause(x,infc);
+        }
+
+        if (tracing) logger.trace("start", "setting RMIServer object");
+        final RMIServerImpl rmiServer;
+
+        if (rmiServerImpl != null)
+            rmiServer = rmiServerImpl;
+        else
+            rmiServer = newServer();
+
+        rmiServer.setMBeanServer(getMBeanServer());
+        rmiServer.setDefaultClassLoader(defaultClassLoader);
+        rmiServer.setRMIConnectorServer(this);
+        rmiServer.export();
+
+        try {
+            if (tracing) logger.trace("start", "getting RMIServer object to export");
+            final RMIServer objref = objectToBind(rmiServer, attributes);
+
+            if (address != null && address.getURLPath().startsWith("/jndi/")) {
+                final String jndiUrl = address.getURLPath().substring(6);
+
+                if (tracing)
+                    logger.trace("start", "Using external directory: " + jndiUrl);
+
+                String stringBoolean = (String) attributes.get(JNDI_REBIND_ATTRIBUTE);
+                final boolean rebind = EnvHelp.computeBooleanFromString( stringBoolean );
+
+                if (tracing)
+                    logger.trace("start", JNDI_REBIND_ATTRIBUTE + "=" + rebind);
+
+                try {
+                    if (tracing) logger.trace("start", "binding to " + jndiUrl);
+
+                    final Hashtable<?, ?> usemap = EnvHelp.mapToHashtable(attributes);
+
+                    bind(jndiUrl, usemap, objref, rebind);
+
+                    boundJndiUrl = jndiUrl;
+                } catch (NamingException e) {
+                    // fit e in the nested exception if we are on 1.4
+                    throw newIOException("Cannot bind to URL ["+jndiUrl+"]: "
+                                         + e, e);
+                }
+            } else {
+                // if jndiURL is null, we must encode the stub into the URL.
+                if (tracing) logger.trace("start", "Encoding URL");
+
+                encodeStubInAddress(objref, attributes);
+
+                if (tracing) logger.trace("start", "Encoded URL: " + this.address);
+            }
+        } catch (Exception e) {
+            try {
+                rmiServer.close();
+            } catch (Exception x) {
+                // OK: we are already throwing another exception
+            }
+            if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else if (e instanceof IOException)
+                throw (IOException) e;
+            else
+                throw newIOException("Got unexpected exception while " +
+                                     "starting the connector server: "
+                                     + e, e);
+        }
+
+        rmiServerImpl = rmiServer;
+
+        synchronized(openedServers) {
+            openedServers.add(this);
+        }
+
+        state = STARTED;
+
+        if (tracing) {
+            logger.trace("start", "Connector Server Address = " + address);
+            logger.trace("start", "started.");
+        }
+    }
+
+    /**
+     * <p>Deactivates the connector server, that is, stops listening for
+     * client connections.  Calling this method will also close all
+     * client connections that were made by this server.  After this
+     * method returns, whether normally or with an exception, the
+     * connector server will not create any new client
+     * connections.</p>
+     *
+     * <p>Once a connector server has been stopped, it cannot be started
+     * again.</p>
+     *
+     * <p>Calling this method when the connector server has already
+     * been stopped has no effect.  Calling this method when the
+     * connector server has not yet been started will disable the
+     * connector server object permanently.</p>
+     *
+     * <p>If closing a client connection produces an exception, that
+     * exception is not thrown from this method.  A {@link
+     * JMXConnectionNotification} is emitted from this MBean with the
+     * connection ID of the connection that could not be closed.</p>
+     *
+     * <p>Closing a connector server is a potentially slow operation.
+     * For example, if a client machine with an open connection has
+     * crashed, the close operation might have to wait for a network
+     * protocol timeout.  Callers that do not want to block in a close
+     * operation should do it in a separate thread.</p>
+     *
+     * <p>This method calls the method {@link RMIServerImpl#close()
+     * close} on the connector server's <code>RMIServerImpl</code>
+     * object.</p>
+     *
+     * <p>If the <code>RMIServerImpl</code> was bound to a JNDI
+     * directory by the {@link #start() start} method, it is unbound
+     * from the directory by this method.</p>
+     *
+     * @exception IOException if the server cannot be closed cleanly,
+     * or if the <code>RMIServerImpl</code> cannot be unbound from the
+     * directory.  When this exception is thrown, the server has
+     * already attempted to close all client connections, if
+     * appropriate; to call {@link RMIServerImpl#close()}; and to
+     * unbind the <code>RMIServerImpl</code> from its directory, if
+     * appropriate.  All client connections are closed except possibly
+     * those that generated exceptions when the server attempted to
+     * close them.
+     */
+    public void stop() throws IOException {
+        final boolean tracing = logger.traceOn();
+
+        synchronized (this) {
+            if (state == STOPPED) {
+                if (tracing) logger.trace("stop","already stopped.");
+                return;
+            } else if (state == CREATED) {
+                if (tracing) logger.trace("stop","not started yet.");
+            }
+
+            if (tracing) logger.trace("stop", "stopping.");
+            state = STOPPED;
+        }
+
+        synchronized(openedServers) {
+            openedServers.remove(this);
+        }
+
+        IOException exception = null;
+
+        // rmiServerImpl can be null if stop() called without start()
+        if (rmiServerImpl != null) {
+            try {
+                if (tracing) logger.trace("stop", "closing RMI server.");
+                rmiServerImpl.close();
+            } catch (IOException e) {
+                if (tracing) logger.trace("stop", "failed to close RMI server: " + e);
+                if (logger.debugOn()) logger.debug("stop",e);
+                exception = e;
+            }
+        }
+
+        if (boundJndiUrl != null) {
+            try {
+                if (tracing)
+                    logger.trace("stop",
+                          "unbind from external directory: " + boundJndiUrl);
+
+                final Hashtable<?, ?> usemap = EnvHelp.mapToHashtable(attributes);
+
+                InitialContext ctx =
+                    new InitialContext(usemap);
+
+                ctx.unbind(boundJndiUrl);
+
+                ctx.close();
+            } catch (NamingException e) {
+                if (tracing) logger.trace("stop", "failed to unbind RMI server: "+e);
+                if (logger.debugOn()) logger.debug("stop",e);
+                // fit e in as the nested exception if we are on 1.4
+                if (exception == null)
+                    exception = newIOException("Cannot bind to URL: " + e, e);
+            }
+        }
+
+        if (exception != null) throw exception;
+
+        if (tracing) logger.trace("stop", "stopped");
+    }
+
+    public synchronized boolean isActive() {
+        return (state == STARTED);
+    }
+
+    public JMXServiceURL getAddress() {
+        if (!isActive())
+            return null;
+        return address;
+    }
+
+    public Map<String,?> getAttributes() {
+        Map<String, ?> map = EnvHelp.filterAttributes(attributes);
+        return Collections.unmodifiableMap(map);
+    }
+
+    @Override
+    public synchronized
+        void setMBeanServerForwarder(MBeanServerForwarder mbsf) {
+        super.setMBeanServerForwarder(mbsf);
+        if (rmiServerImpl != null)
+            rmiServerImpl.setMBeanServer(getMBeanServer());
+    }
+
+    /* We repeat the definitions of connection{Opened,Closed,Failed}
+       here so that they are accessible to other classes in this package
+       even though they have protected access.  */
+
+    @Override
+    protected void connectionOpened(String connectionId, String message,
+                                    Object userData) {
+        super.connectionOpened(connectionId, message, userData);
+    }
+
+    @Override
+    protected void connectionClosed(String connectionId, String message,
+                                    Object userData) {
+        super.connectionClosed(connectionId, message, userData);
+    }
+
+    @Override
+    protected void connectionFailed(String connectionId, String message,
+                                    Object userData) {
+        super.connectionFailed(connectionId, message, userData);
+    }
+
+    /**
+     * Bind a stub to a registry.
+     * @param jndiUrl URL of the stub in the registry, extracted
+     *        from the <code>JMXServiceURL</code>.
+     * @param attributes A Hashtable containing environment parameters,
+     *        built from the Map specified at this object creation.
+     * @param rmiServer The object to bind in the registry
+     * @param rebind true if the object must be rebound.
+     **/
+    void bind(String jndiUrl, Hashtable<?, ?> attributes,
+              RMIServer rmiServer, boolean rebind)
+        throws NamingException, MalformedURLException {
+        // if jndiURL is not null, we nust bind the stub to a
+        // directory.
+        InitialContext ctx =
+            new InitialContext(attributes);
+
+        if (rebind)
+            ctx.rebind(jndiUrl, rmiServer);
+        else
+            ctx.bind(jndiUrl, rmiServer);
+        ctx.close();
+    }
+
+    /**
+     * Creates a new RMIServerImpl.
+     **/
+    RMIServerImpl newServer() throws IOException {
+        final int port;
+        if (address == null)
+            port = 0;
+        else
+            port = address.getPort();
+
+        return newJRMPServer(attributes, port);
+    }
+
+    /**
+     * Encode a stub into the JMXServiceURL.
+     * @param rmiServer The stub object to encode in the URL
+     * @param attributes A Map containing environment parameters,
+     *        built from the Map specified at this object creation.
+     **/
+    private void encodeStubInAddress(
+            RMIServer rmiServer, Map<String, ?> attributes)
+            throws IOException {
+
+        final String protocol, host;
+        final int port;
+
+        if (address == null) {
+            protocol = "rmi";
+            host = null; // will default to local host name
+            port = 0;
+        } else {
+            protocol = address.getProtocol();
+            host = (address.getHost().equals("")) ? null : address.getHost();
+            port = address.getPort();
+        }
+
+        final String urlPath = encodeStub(rmiServer, attributes);
+
+        address = new JMXServiceURL(protocol, host, port, urlPath);
+    }
+
+    /**
+     * Returns the IOR of the given rmiServer.
+     **/
+    static String encodeStub(
+            RMIServer rmiServer, Map<String, ?> env) throws IOException {
+        return "/stub/" + encodeJRMPStub(rmiServer, env);
+    }
+
+    static String encodeJRMPStub(
+            RMIServer rmiServer, Map<String, ?> env)
+            throws IOException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        ObjectOutputStream oout = new ObjectOutputStream(bout);
+        oout.writeObject(rmiServer);
+        oout.close();
+        byte[] bytes = bout.toByteArray();
+        return byteArrayToBase64(bytes);
+    }
+
+    /**
+     * Object that we will bind to the registry.
+     * This object is a stub connected to our RMIServerImpl.
+     **/
+    private static RMIServer objectToBind(
+            RMIServerImpl rmiServer, Map<String, ?> env)
+        throws IOException {
+        return (RMIServer)rmiServer.toStub();
+    }
+
+    private static RMIServerImpl newJRMPServer(Map<String, ?> env, int port)
+            throws IOException {
+        RMIClientSocketFactory csf = (RMIClientSocketFactory)
+            env.get(RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE);
+        RMIServerSocketFactory ssf = (RMIServerSocketFactory)
+            env.get(RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE);
+        return new RMIJRMPServerImpl(port, csf, ssf, env);
+    }
+
+    private static String byteArrayToBase64(byte[] a) {
+        int aLen = a.length;
+        int numFullGroups = aLen/3;
+        int numBytesInPartialGroup = aLen - 3*numFullGroups;
+        int resultLen = 4*((aLen + 2)/3);
+        final StringBuilder result = new StringBuilder(resultLen);
+
+        // Translate all full groups from byte array elements to Base64
+        int inCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int byte0 = a[inCursor++] & 0xff;
+            int byte1 = a[inCursor++] & 0xff;
+            int byte2 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+            result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]);
+            result.append(intToAlpha[byte2 & 0x3f]);
+        }
+
+        // Translate partial group if present
+        if (numBytesInPartialGroup != 0) {
+            int byte0 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            if (numBytesInPartialGroup == 1) {
+                result.append(intToAlpha[(byte0 << 4) & 0x3f]);
+                result.append("==");
+            } else {
+                // assert numBytesInPartialGroup == 2;
+                int byte1 = a[inCursor++] & 0xff;
+                result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+                result.append(intToAlpha[(byte1 << 2)&0x3f]);
+                result.append('=');
+            }
+        }
+        // assert inCursor == a.length;
+        // assert result.length() == resultLen;
+        return result.toString();
+    }
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Base64 Alphabet" equivalents as specified
+     * in Table 1 of RFC 2045.
+     */
+    private static final char intToAlpha[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    /**
+     * Construct a new IOException with a nested exception.
+     * The nested exception is set only if JDK {@literal >= 1.4}
+     */
+    private static IOException newIOException(String message,
+                                              Throwable cause) {
+        final IOException x = new IOException(message);
+        return EnvHelp.initCause(x,cause);
+    }
+
+
+    // Private variables
+    // -----------------
+
+    private static ClassLogger logger =
+        new ClassLogger("javax.management.remote.rmi", "RMIConnectorServer");
+
+    private JMXServiceURL address;
+    private RMIServerImpl rmiServerImpl;
+    private final Map<String, ?> attributes;
+    private ClassLoader defaultClassLoader = null;
+
+    private String boundJndiUrl;
+
+    // state
+    private static final int CREATED = 0;
+    private static final int STARTED = 1;
+    private static final int STOPPED = 2;
+
+    private int state = CREATED;
+    private final static Set<RMIConnectorServer> openedServers =
+            new HashSet<RMIConnectorServer>();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIIIOPServerImpl.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.util.Map;
+import javax.security.auth.Subject;
+
+/**
+ * <p>An {@link RMIServerImpl} that is exported through IIOP and that
+ * creates client connections as RMI objects exported through IIOP.
+ * User code does not usually reference this class directly.</p>
+ *
+ * @see RMIServerImpl
+ *
+ * @since 1.5
+ * @deprecated This transport is no longer supported.
+ */
+@Deprecated
+public class RMIIIOPServerImpl extends RMIServerImpl {
+    /**
+     * Throws {@linkplain UnsupportedOperationException}
+     *
+     * @param env the environment containing attributes for the new
+     * <code>RMIServerImpl</code>.  Can be null, which is equivalent
+     * to an empty Map.
+     *
+     * @throws IOException if the RMI object cannot be created.
+     */
+    public RMIIIOPServerImpl(Map<String,?> env)
+            throws IOException {
+        super(env);
+
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void export() throws IOException {
+        throw new UnsupportedOperationException("Method not supported. JMX RMI-IIOP is deprecated");
+    }
+
+    @Override
+    protected String getProtocol() {
+        return "iiop";
+    }
+
+    @Override
+    public Remote toStub() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected RMIConnection makeClient(String connectionId, Subject subject)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void closeClient(RMIConnection client) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void closeServer() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    RMIConnection doNewClient(final Object credentials) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import java.io.IOException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.server.RemoteObject;
+import java.util.Map;
+import java.util.Collections;
+import javax.security.auth.Subject;
+
+import com.sun.jmx.remote.internal.rmi.RMIExporter;
+import com.sun.jmx.remote.util.EnvHelp;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import sun.reflect.misc.ReflectUtil;
+import sun.rmi.server.DeserializationChecker;
+import sun.rmi.server.UnicastServerRef;
+import sun.rmi.server.UnicastServerRef2;
+
+/**
+ * <p>An {@link RMIServer} object that is exported through JRMP and that
+ * creates client connections as RMI objects exported through JRMP.
+ * User code does not usually reference this class directly.</p>
+ *
+ * @see RMIServerImpl
+ *
+ * @since 1.5
+ */
+public class RMIJRMPServerImpl extends RMIServerImpl {
+
+    private final ExportedWrapper exportedWrapper;
+
+    /**
+     * <p>Creates a new {@link RMIServer} object that will be exported
+     * on the given port using the given socket factories.</p>
+     *
+     * @param port the port on which this object and the {@link
+     * RMIConnectionImpl} objects it creates will be exported.  Can be
+     * zero, to indicate any available port.
+     *
+     * @param csf the client socket factory for the created RMI
+     * objects.  Can be null.
+     *
+     * @param ssf the server socket factory for the created RMI
+     * objects.  Can be null.
+     *
+     * @param env the environment map.  Can be null.
+     *
+     * @exception IOException if the {@link RMIServer} object
+     * cannot be created.
+     *
+     * @exception IllegalArgumentException if <code>port</code> is
+     * negative.
+     */
+    public RMIJRMPServerImpl(int port,
+                             RMIClientSocketFactory csf,
+                             RMIServerSocketFactory ssf,
+                             Map<String,?> env)
+            throws IOException {
+
+        super(env);
+
+        if (port < 0)
+            throw new IllegalArgumentException("Negative port: " + port);
+
+        this.port = port;
+        this.csf = csf;
+        this.ssf = ssf;
+        this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
+
+        String[] credentialsTypes
+                = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES);
+        List<String> types = null;
+        if (credentialsTypes != null) {
+            types = new ArrayList<>();
+            for (String type : credentialsTypes) {
+                if (type == null) {
+                    throw new IllegalArgumentException("A credential type is null.");
+                }
+                ReflectUtil.checkPackageAccess(type);
+                types.add(type);
+            }
+        }
+        exportedWrapper = types != null ?
+                new ExportedWrapper(this, types) :
+                null;
+    }
+
+    protected void export() throws IOException {
+        if (exportedWrapper != null) {
+            export(exportedWrapper);
+        } else {
+            export(this);
+        }
+    }
+
+    private void export(Remote obj) throws RemoteException {
+        final RMIExporter exporter =
+            (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
+        final boolean daemon = EnvHelp.isServerDaemon(env);
+
+        if (daemon && exporter != null) {
+            throw new IllegalArgumentException("If "+EnvHelp.JMX_SERVER_DAEMON+
+                    " is specified as true, "+RMIExporter.EXPORTER_ATTRIBUTE+
+                    " cannot be used to specify an exporter!");
+        }
+
+        if (daemon) {
+            if (csf == null && ssf == null) {
+                new UnicastServerRef(port).exportObject(obj, null, true);
+            } else {
+                new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true);
+            }
+        } else if (exporter != null) {
+            exporter.exportObject(obj, port, csf, ssf);
+        } else {
+            UnicastRemoteObject.exportObject(obj, port, csf, ssf);
+        }
+    }
+
+    private void unexport(Remote obj, boolean force)
+            throws NoSuchObjectException {
+        RMIExporter exporter =
+            (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
+        if (exporter == null)
+            UnicastRemoteObject.unexportObject(obj, force);
+        else
+            exporter.unexportObject(obj, force);
+    }
+
+    protected String getProtocol() {
+        return "rmi";
+    }
+
+    /**
+     * <p>Returns a serializable stub for this {@link RMIServer} object.</p>
+     *
+     * @return a serializable stub.
+     *
+     * @exception IOException if the stub cannot be obtained - e.g the
+     *            RMIJRMPServerImpl has not been exported yet.
+     */
+    public Remote toStub() throws IOException {
+        if (exportedWrapper != null) {
+            return RemoteObject.toStub(exportedWrapper);
+        } else {
+            return RemoteObject.toStub(this);
+        }
+    }
+
+    /**
+     * <p>Creates a new client connection as an RMI object exported
+     * through JRMP. The port and socket factories for the new
+     * {@link RMIConnection} object are the ones supplied
+     * to the <code>RMIJRMPServerImpl</code> constructor.</p>
+     *
+     * @param connectionId the ID of the new connection. Every
+     * connection opened by this connector server will have a
+     * different id.  The behavior is unspecified if this parameter is
+     * null.
+     *
+     * @param subject the authenticated subject.  Can be null.
+     *
+     * @return the newly-created <code>RMIConnection</code>.
+     *
+     * @exception IOException if the new {@link RMIConnection}
+     * object cannot be created or exported.
+     */
+    protected RMIConnection makeClient(String connectionId, Subject subject)
+            throws IOException {
+
+        if (connectionId == null)
+            throw new NullPointerException("Null connectionId");
+
+        RMIConnection client =
+            new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),
+                                  subject, env);
+        export(client);
+        return client;
+    }
+
+    protected void closeClient(RMIConnection client) throws IOException {
+        unexport(client, true);
+    }
+
+    /**
+     * <p>Called by {@link #close()} to close the connector server by
+     * unexporting this object.  After returning from this method, the
+     * connector server must not accept any new connections.</p>
+     *
+     * @exception IOException if the attempt to close the connector
+     * server failed.
+     */
+    protected void closeServer() throws IOException {
+        if (exportedWrapper != null) {
+            unexport(exportedWrapper, true);
+        } else {
+            unexport(this, true);
+        }
+    }
+
+    private final int port;
+    private final RMIClientSocketFactory csf;
+    private final RMIServerSocketFactory ssf;
+    private final Map<String, ?> env;
+
+    private static class ExportedWrapper implements RMIServer, DeserializationChecker {
+        private final RMIServer impl;
+        private final List<String> allowedTypes;
+
+        private ExportedWrapper(RMIServer impl, List<String> credentialsTypes) {
+            this.impl = impl;
+            allowedTypes = credentialsTypes;
+        }
+
+        @Override
+        public String getVersion() throws RemoteException {
+            return impl.getVersion();
+        }
+
+        @Override
+        public RMIConnection newClient(Object credentials) throws IOException {
+            return impl.newClient(credentials);
+        }
+
+        @Override
+        public void check(Method method, ObjectStreamClass descriptor,
+                int paramIndex, int callID) {
+            String type = descriptor.getName();
+            if (!allowedTypes.contains(type)) {
+                throw new ClassCastException("Unsupported type: " + type);
+            }
+        }
+
+        @Override
+        public void checkProxyClass(Method method, String[] ifaces,
+                int paramIndex, int callID) {
+            if (ifaces != null && ifaces.length > 0) {
+                for (String iface : ifaces) {
+                    if (!allowedTypes.contains(iface)) {
+                        throw new ClassCastException("Unsupported type: " + iface);
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServer.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * <p>RMI object used to establish connections to an RMI connector.
+ * There is one Remote object implementing this interface for each RMI
+ * connector.</p>
+ *
+ * <p>User code does not usually refer to this interface.  It is
+ * specified as part of the public API so that different
+ * implementations of that API will interoperate.</p>
+ *
+ * @since 1.5
+ */
+public interface RMIServer extends Remote {
+    /**
+     * <p>The version of the RMI Connector Protocol understood by this
+     * connector server.  This is a string with the following format:</p>
+     *
+     * <pre>
+     * <em>protocol-version</em> <em>implementation-name</em>
+     * </pre>
+     *
+     * <p>The <code><em>protocol-version</em></code> is a series of
+     * two or more non-negative integers separated by periods
+     * (<code>.</code>).  An implementation of the version described
+     * by this documentation must use the string <code>1.0</code>
+     * here.</p>
+     *
+     * <p>After the protocol version there must be a space, followed
+     * by the implementation name.  The format of the implementation
+     * name is unspecified.  It is recommended that it include an
+     * implementation version number.  An implementation can use an
+     * empty string as its implementation name, for example for
+     * security reasons.</p>
+     *
+     * @return a string with the format described here.
+     *
+     * @exception RemoteException if there is a communication
+     * exception during the remote method call.
+     */
+    public String getVersion() throws RemoteException;
+
+    /**
+     * <p>Makes a new connection through this RMI connector.  Each
+     * remote client calls this method to obtain a new RMI object
+     * representing its connection.</p>
+     *
+     * @param credentials this object specifies the user-defined credentials
+     * to be passed in to the server in order to authenticate the user before
+     * creating the <code>RMIConnection</code>.  Can be null.
+     *
+     * @return the newly-created connection object.
+     *
+     * @exception IOException if the new client object cannot be
+     * created or exported, or if there is a communication exception
+     * during the remote method call.
+     *
+     * @exception SecurityException if the given credentials do not
+     * allow the server to authenticate the caller successfully.
+     */
+    public RMIConnection newClient(Object credentials) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.management.remote.rmi;
+
+import com.sun.jmx.remote.internal.ArrayNotificationBuffer;
+import com.sun.jmx.remote.internal.NotificationBuffer;
+import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
+import com.sun.jmx.remote.util.ClassLogger;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.rmi.Remote;
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.remote.JMXAuthenticator;
+import javax.management.remote.JMXConnectorServer;
+import javax.security.auth.Subject;
+
+/**
+ * <p>An RMI object representing a connector server.  Remote clients
+ * can make connections using the {@link #newClient(Object)} method.  This
+ * method returns an RMI object representing the connection.</p>
+ *
+ * <p>User code does not usually reference this class directly.
+ * RMI connection servers are usually created with the class {@link
+ * RMIConnectorServer}.  Remote clients usually create connections
+ * either with {@link javax.management.remote.JMXConnectorFactory}
+ * or by instantiating {@link RMIConnector}.</p>
+ *
+ * <p>This is an abstract class.  Concrete subclasses define the
+ * details of the client connection objects.</p>
+ *
+ * @since 1.5
+ */
+public abstract class RMIServerImpl implements Closeable, RMIServer {
+    /**
+     * <p>Constructs a new <code>RMIServerImpl</code>.</p>
+     *
+     * @param env the environment containing attributes for the new
+     * <code>RMIServerImpl</code>.  Can be null, which is equivalent
+     * to an empty Map.
+     */
+    public RMIServerImpl(Map<String,?> env) {
+        this.env = (env == null) ? Collections.<String,Object>emptyMap() : env;
+    }
+
+    void setRMIConnectorServer(RMIConnectorServer connServer)
+            throws IOException {
+        this.connServer = connServer;
+    }
+
+    /**
+     * <p>Exports this RMI object.</p>
+     *
+     * @exception IOException if this RMI object cannot be exported.
+     */
+    protected abstract void export() throws IOException;
+
+    /**
+     * Returns a remotable stub for this server object.
+     * @return a remotable stub.
+     * @exception IOException if the stub cannot be obtained - e.g the
+     *            RMIServerImpl has not been exported yet.
+     **/
+    public abstract Remote toStub() throws IOException;
+
+    /**
+     * <p>Sets the default <code>ClassLoader</code> for this connector
+     * server. New client connections will use this classloader.
+     * Existing client connections are unaffected.</p>
+     *
+     * @param cl the new <code>ClassLoader</code> to be used by this
+     * connector server.
+     *
+     * @see #getDefaultClassLoader
+     */
+    public synchronized void setDefaultClassLoader(ClassLoader cl) {
+        this.cl = cl;
+    }
+
+    /**
+     * <p>Gets the default <code>ClassLoader</code> used by this connector
+     * server.</p>
+     *
+     * @return the default <code>ClassLoader</code> used by this
+     * connector server.
+     *
+     * @see #setDefaultClassLoader
+     */
+    public synchronized ClassLoader getDefaultClassLoader() {
+        return cl;
+    }
+
+    /**
+     * <p>Sets the <code>MBeanServer</code> to which this connector
+     * server is attached. New client connections will interact
+     * with this <code>MBeanServer</code>. Existing client connections are
+     * unaffected.</p>
+     *
+     * @param mbs the new <code>MBeanServer</code>.  Can be null, but
+     * new client connections will be refused as long as it is.
+     *
+     * @see #getMBeanServer
+     */
+    public synchronized void setMBeanServer(MBeanServer mbs) {
+        this.mbeanServer = mbs;
+    }
+
+    /**
+     * <p>The <code>MBeanServer</code> to which this connector server
+     * is attached.  This is the last value passed to {@link
+     * #setMBeanServer} on this object, or null if that method has
+     * never been called.</p>
+     *
+     * @return the <code>MBeanServer</code> to which this connector
+     * is attached.
+     *
+     * @see #setMBeanServer
+     */
+    public synchronized MBeanServer getMBeanServer() {
+        return mbeanServer;
+    }
+
+    public String getVersion() {
+        // Expected format is: "protocol-version implementation-name"
+        try {
+            return "1.0 java_runtime_" +
+                    System.getProperty("java.runtime.version");
+        } catch (SecurityException e) {
+            return "1.0 ";
+        }
+    }
+
+    /**
+     * <p>Creates a new client connection.  This method calls {@link
+     * #makeClient makeClient} and adds the returned client connection
+     * object to an internal list.  When this
+     * <code>RMIServerImpl</code> is shut down via its {@link
+     * #close()} method, the {@link RMIConnection#close() close()}
+     * method of each object remaining in the list is called.</p>
+     *
+     * <p>The fact that a client connection object is in this internal
+     * list does not prevent it from being garbage collected.</p>
+     *
+     * @param credentials this object specifies the user-defined
+     * credentials to be passed in to the server in order to
+     * authenticate the caller before creating the
+     * <code>RMIConnection</code>.  Can be null.
+     *
+     * @return the newly-created <code>RMIConnection</code>.  This is
+     * usually the object created by <code>makeClient</code>, though
+     * an implementation may choose to wrap that object in another
+     * object implementing <code>RMIConnection</code>.
+     *
+     * @exception IOException if the new client object cannot be
+     * created or exported.
+     *
+     * @exception SecurityException if the given credentials do not allow
+     * the server to authenticate the user successfully.
+     *
+     * @exception IllegalStateException if {@link #getMBeanServer()}
+     * is null.
+     */
+    public RMIConnection newClient(Object credentials) throws IOException {
+        return doNewClient(credentials);
+    }
+
+    /**
+     * This method could be overridden by subclasses defined in this package
+     * to perform additional operations specific to the underlying transport
+     * before creating the new client connection.
+     */
+    RMIConnection doNewClient(Object credentials) throws IOException {
+        final boolean tracing = logger.traceOn();
+
+        if (tracing) logger.trace("newClient","making new client");
+
+        if (getMBeanServer() == null)
+            throw new IllegalStateException("Not attached to an MBean server");
+
+        Subject subject = null;
+        JMXAuthenticator authenticator =
+            (JMXAuthenticator) env.get(JMXConnectorServer.AUTHENTICATOR);
+        if (authenticator == null) {
+            /*
+             * Create the JAAS-based authenticator only if authentication
+             * has been enabled
+             */
+            if (env.get("jmx.remote.x.password.file") != null ||
+                env.get("jmx.remote.x.login.config") != null) {
+                authenticator = new JMXPluggableAuthenticator(env);
+            }
+        }
+        if (authenticator != null) {
+            if (tracing) logger.trace("newClient","got authenticator: " +
+                               authenticator.getClass().getName());
+            try {
+                subject = authenticator.authenticate(credentials);
+            } catch (SecurityException e) {
+                logger.trace("newClient", "Authentication failed: " + e);
+                throw e;
+            }
+        }
+
+        if (tracing) {
+            if (subject != null)
+                logger.trace("newClient","subject is not null");
+            else logger.trace("newClient","no subject");
+        }
+
+        final String connectionId = makeConnectionId(getProtocol(), subject);
+
+        if (tracing)
+            logger.trace("newClient","making new connection: " + connectionId);
+
+        RMIConnection client = makeClient(connectionId, subject);
+
+        dropDeadReferences();
+        WeakReference<RMIConnection> wr = new WeakReference<RMIConnection>(client);
+        synchronized (clientList) {
+            clientList.add(wr);
+        }
+
+        connServer.connectionOpened(connectionId, "Connection opened", null);
+
+        synchronized (clientList) {
+            if (!clientList.contains(wr)) {
+                // can be removed only by a JMXConnectionNotification listener
+                throw new IOException("The connection is refused.");
+            }
+        }
+
+        if (tracing)
+            logger.trace("newClient","new connection done: " + connectionId );
+
+        return client;
+    }
+
+    /**
+     * <p>Creates a new client connection.  This method is called by
+     * the public method {@link #newClient(Object)}.</p>
+     *
+     * @param connectionId the ID of the new connection.  Every
+     * connection opened by this connector server will have a
+     * different ID.  The behavior is unspecified if this parameter is
+     * null.
+     *
+     * @param subject the authenticated subject.  Can be null.
+     *
+     * @return the newly-created <code>RMIConnection</code>.
+     *
+     * @exception IOException if the new client object cannot be
+     * created or exported.
+     */
+    protected abstract RMIConnection makeClient(String connectionId,
+                                                Subject subject)
+            throws IOException;
+
+    /**
+     * <p>Closes a client connection made by {@link #makeClient makeClient}.
+     *
+     * @param client a connection previously returned by
+     * <code>makeClient</code> on which the <code>closeClient</code>
+     * method has not previously been called.  The behavior is
+     * unspecified if these conditions are violated, including the
+     * case where <code>client</code> is null.
+     *
+     * @exception IOException if the client connection cannot be
+     * closed.
+     */
+    protected abstract void closeClient(RMIConnection client)
+            throws IOException;
+
+    /**
+     * <p>Returns the protocol string for this object.  The string is
+     * <code>rmi</code> for RMI/JRMP.
+     *
+     * @return the protocol string for this object.
+     */
+    protected abstract String getProtocol();
+
+    /**
+     * <p>Method called when a client connection created by {@link
+     * #makeClient makeClient} is closed.  A subclass that defines
+     * <code>makeClient</code> must arrange for this method to be
+     * called when the resultant object's {@link RMIConnection#close()
+     * close} method is called.  This enables it to be removed from
+     * the <code>RMIServerImpl</code>'s list of connections.  It is
+     * not an error for <code>client</code> not to be in that
+     * list.</p>
+     *
+     * <p>After removing <code>client</code> from the list of
+     * connections, this method calls {@link #closeClient
+     * closeClient(client)}.</p>
+     *
+     * @param client the client connection that has been closed.
+     *
+     * @exception IOException if {@link #closeClient} throws this
+     * exception.
+     *
+     * @exception NullPointerException if <code>client</code> is null.
+     */
+    protected void clientClosed(RMIConnection client) throws IOException {
+        final boolean debug = logger.debugOn();
+
+        if (debug) logger.trace("clientClosed","client="+client);
+
+        if (client == null)
+            throw new NullPointerException("Null client");
+
+        synchronized (clientList) {
+            dropDeadReferences();
+            for (Iterator<WeakReference<RMIConnection>> it = clientList.iterator();
+                 it.hasNext(); ) {
+                WeakReference<RMIConnection> wr = it.next();
+                if (wr.get() == client) {
+                    it.remove();
+                    break;
+                }
+            }
+            /* It is not a bug for this loop not to find the client.  In
+               our close() method, we remove a client from the list before
+               calling its close() method.  */
+        }
+
+        if (debug) logger.trace("clientClosed", "closing client.");
+        closeClient(client);
+
+        if (debug) logger.trace("clientClosed", "sending notif");
+        connServer.connectionClosed(client.getConnectionId(),
+                                    "Client connection closed", null);
+
+        if (debug) logger.trace("clientClosed","done");
+    }
+
+    /**
+     * <p>Closes this connection server.  This method first calls the
+     * {@link #closeServer()} method so that no new client connections
+     * will be accepted.  Then, for each remaining {@link
+     * RMIConnection} object returned by {@link #makeClient
+     * makeClient}, its {@link RMIConnection#close() close} method is
+     * called.</p>
+     *
+     * <p>The behavior when this method is called more than once is
+     * unspecified.</p>
+     *
+     * <p>If {@link #closeServer()} throws an
+     * <code>IOException</code>, the individual connections are
+     * nevertheless closed, and then the <code>IOException</code> is
+     * thrown from this method.</p>
+     *
+     * <p>If {@link #closeServer()} returns normally but one or more
+     * of the individual connections throws an
+     * <code>IOException</code>, then, after closing all the
+     * connections, one of those <code>IOException</code>s is thrown
+     * from this method.  If more than one connection throws an
+     * <code>IOException</code>, it is unspecified which one is thrown
+     * from this method.</p>
+     *
+     * @exception IOException if {@link #closeServer()} or one of the
+     * {@link RMIConnection#close()} calls threw
+     * <code>IOException</code>.
+     */
+    public synchronized void close() throws IOException {
+        final boolean tracing = logger.traceOn();
+        final boolean debug   = logger.debugOn();
+
+        if (tracing) logger.trace("close","closing");
+
+        IOException ioException = null;
+        try {
+            if (debug)   logger.debug("close","closing Server");
+            closeServer();
+        } catch (IOException e) {
+            if (tracing) logger.trace("close","Failed to close server: " + e);
+            if (debug)   logger.debug("close",e);
+            ioException = e;
+        }
+
+        if (debug)   logger.debug("close","closing Clients");
+        // Loop to close all clients
+        while (true) {
+            synchronized (clientList) {
+                if (debug) logger.debug("close","droping dead references");
+                dropDeadReferences();
+
+                if (debug) logger.debug("close","client count: "+clientList.size());
+                if (clientList.size() == 0)
+                    break;
+                /* Loop until we find a non-null client.  Because we called
+                   dropDeadReferences(), this will usually be the first
+                   element of the list, but a garbage collection could have
+                   happened in between.  */
+                for (Iterator<WeakReference<RMIConnection>> it = clientList.iterator();
+                     it.hasNext(); ) {
+                    WeakReference<RMIConnection> wr = it.next();
+                    RMIConnection client = wr.get();
+                    it.remove();
+                    if (client != null) {
+                        try {
+                            client.close();
+                        } catch (IOException e) {
+                            if (tracing)
+                                logger.trace("close","Failed to close client: " + e);
+                            if (debug) logger.debug("close",e);
+                            if (ioException == null)
+                                ioException = e;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        if(notifBuffer != null)
+            notifBuffer.dispose();
+
+        if (ioException != null) {
+            if (tracing) logger.trace("close","close failed.");
+            throw ioException;
+        }
+
+        if (tracing) logger.trace("close","closed.");
+    }
+
+    /**
+     * <p>Called by {@link #close()} to close the connector server.
+     * After returning from this method, the connector server must
+     * not accept any new connections.</p>
+     *
+     * @exception IOException if the attempt to close the connector
+     * server failed.
+     */
+    protected abstract void closeServer() throws IOException;
+
+    private static synchronized String makeConnectionId(String protocol,
+                                                        Subject subject) {
+        connectionIdNumber++;
+
+        String clientHost = "";
+        try {
+            clientHost = RemoteServer.getClientHost();
+            /*
+             * According to the rules specified in the javax.management.remote
+             * package description, a numeric IPv6 address (detected by the
+             * presence of otherwise forbidden ":" character) forming a part
+             * of the connection id must be enclosed in square brackets.
+             */
+            if (clientHost.contains(":")) {
+                clientHost = "[" + clientHost + "]";
+            }
+        } catch (ServerNotActiveException e) {
+            logger.trace("makeConnectionId", "getClientHost", e);
+        }
+
+        final StringBuilder buf = new StringBuilder();
+        buf.append(protocol).append(":");
+        if (clientHost.length() > 0)
+            buf.append("//").append(clientHost);
+        buf.append(" ");
+        if (subject != null) {
+            Set<Principal> principals = subject.getPrincipals();
+            String sep = "";
+            for (Iterator<Principal> it = principals.iterator(); it.hasNext(); ) {
+                Principal p = it.next();
+                String name = p.getName().replace(' ', '_').replace(';', ':');
+                buf.append(sep).append(name);
+                sep = ";";
+            }
+        }
+        buf.append(" ").append(connectionIdNumber);
+        if (logger.traceOn())
+            logger.trace("newConnectionId","connectionId="+buf);
+        return buf.toString();
+    }
+
+    private void dropDeadReferences() {
+        synchronized (clientList) {
+            for (Iterator<WeakReference<RMIConnection>> it = clientList.iterator();
+                 it.hasNext(); ) {
+                WeakReference<RMIConnection> wr = it.next();
+                if (wr.get() == null)
+                    it.remove();
+            }
+        }
+    }
+
+    synchronized NotificationBuffer getNotifBuffer() {
+        //Notification buffer is lazily created when the first client connects
+        if(notifBuffer == null)
+            notifBuffer =
+                ArrayNotificationBuffer.getNotificationBuffer(mbeanServer,
+                                                              env);
+        return notifBuffer;
+    }
+
+    private static final ClassLogger logger =
+        new ClassLogger("javax.management.remote.rmi", "RMIServerImpl");
+
+    /** List of WeakReference values.  Each one references an
+        RMIConnection created by this object, or null if the
+        RMIConnection has been garbage-collected.  */
+    private final List<WeakReference<RMIConnection>> clientList =
+            new ArrayList<WeakReference<RMIConnection>>();
+
+    private ClassLoader cl;
+
+    private MBeanServer mbeanServer;
+
+    private final Map<String, ?> env;
+
+    private RMIConnectorServer connServer;
+
+    private static int connectionIdNumber;
+
+    private NotificationBuffer notifBuffer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,340 @@
+<html>
+<head>
+    <title>RMI connector</title>
+<!--
+Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 only, as
+published by the Free Software Foundation.  Oracle designates this
+particular file as subject to the "Classpath" exception as provided
+by Oracle in the LICENSE file that accompanied this code.
+
+This code is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+version 2 for more details (a copy is included in the LICENSE file that
+accompanied this code).
+
+You should have received a copy of the GNU General Public License version
+2 along with this work; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+or visit www.oracle.com if you need additional information or have any
+questions.
+-->
+</head>
+<body bgcolor="white">
+    <p>The RMI connector is a connector for the JMX Remote API that
+      uses RMI to transmit client requests to a remote MBean server.
+      This package defines the classes that the user of an RMI
+      connector needs to reference directly, for both the client and
+      server sides.  It also defines certain classes that the user
+      will not usually reference directly, but that must be defined so
+      that different implementations of the RMI connector can
+      interoperate.</p>
+
+    <p>The RMI connector supports the JRMP transport for RMI.</p>
+
+    <p>Like most connectors in the JMX Remote API, an RMI connector
+      usually has an address, which
+      is a {@link javax.management.remote.JMXServiceURL
+      JMXServiceURL}.  The protocol part of this address is
+      <code>rmi</code> for a connector that uses the default RMI
+      transport (JRMP).</p>
+
+    <p>There are two forms for RMI connector addresses:</p>
+
+    <ul>
+      <li>
+	In the <em>JNDI form</em>, the URL indicates <em>where to find
+	an RMI stub for the connector</em>.  This RMI stub is a Java
+	object of type {@link javax.management.remote.rmi.RMIServer
+	RMIServer} that gives remote access to the connector server.
+	With this address form, the RMI stub is obtained from an
+	external directory entry included in the URL.  An external
+	directory is any directory recognized by {@link javax.naming
+	JNDI}, typically the RMI registry, LDAP, or COS Naming.
+
+      <li>
+	In the <em>encoded form</em>, the URL directly includes the
+	information needed to connect to the connector server.  When
+	using RMI/JRMP, the encoded form is the serialized RMI stub
+	for the server object, encoded using BASE64 without embedded
+	newlines.
+    </ul>
+
+    <p>Addresses are covered in more detail below.</p>
+
+
+    <h3>Creating an RMI connector server</h3>
+
+    <p>The usual way to create an RMI connector server is to supply an
+      RMI connector address to the method {@link
+      javax.management.remote.JMXConnectorServerFactory#newJMXConnectorServer
+      JMXConnectorServerFactory.newJMXConnectorServer}.  The MBean
+      server to which the connector server is attached can be
+      specified as a parameter to that method.  Alternatively, the
+      connector server can be registered as an MBean in that MBean
+      server.</p>
+
+    <p>An RMI connector server can also be created by constructing an
+      instance of {@link
+      javax.management.remote.rmi.RMIConnectorServer
+      RMIConnectorServer}, explicitly or through the MBean server's
+      <code>createMBean</code> method.</p>
+
+    <h4>Choosing the RMI transport</h4>
+
+    <p>You can choose the RMI transport by specifying
+      <code>rmi</code> in the <code><em>protocol</em></code> part of the
+      <code>serviceURL</code> when creating the connector server.  You
+      can also create specialized connector servers by instantiating
+      an appropriate subclass of {@link
+      javax.management.remote.rmi.RMIServerImpl RMIServerImpl} and
+      supplying it to the <code>RMIConnectorServer</code>
+      constructor.</p>
+
+
+    <h4><a name="servergen">Connector addresses generated by the
+	server</a></h4>
+
+    <p>If the <code>serviceURL</code> you specify has an empty URL
+      path (after the optional host and port), or if you do not
+      specify a <code>serviceURL</code>, then the connector server
+      will fabricate a new <code>JMXServiceURL</code> that clients can
+      use to connect:</p>
+
+    <ul>
+
+      <li><p>If the <code>serviceURL</code> looks like:</p>
+
+	<pre>
+	<code>service:jmx:rmi://<em>host</em>:<em>port</em></code>
+	</pre>
+
+	<p>then the connector server will generate an {@link
+	javax.management.remote.rmi.RMIJRMPServerImpl
+	RMIJRMPServerImpl} and the returned <code>JMXServiceURL</code>
+	looks like:</p>
+
+	<pre>
+	<code>service:jmx:rmi://<em>host</em>:<em>port</em>/stub/<em>XXXX</em></code>
+	</pre>
+
+	<p>where <code><em>XXXX</em></code> is the serialized form of the
+	stub for the generated object, encoded in BASE64 without
+	newlines.</p>
+
+      <li><p>If there is no <code>serviceURL</code>, there must be a
+	user-provided <code>RMIServerImpl</code>.  The connector server
+        will generate a <code>JMXServiceURL</code> using the <code>rmi</code>
+	form.</p>
+
+    </ul>
+
+    <p>The <code><em>host</em></code> in a user-provided
+      <code>serviceURL</code> is optional.  If present, it is copied
+      into the generated <code>JMXServiceURL</code> but otherwise
+      ignored.  If absent, the generated <code>JXMServiceURL</code>
+      will have the local host name.</p>
+
+    <p>The <code><em>port</em></code> in a user-provided
+      <code>serviceURL</code> is also optional.  If present, it is
+      also copied into the generated <code>JMXServiceURL</code>;
+      otherwise, the generated <code>JMXServiceURL</code> has no port.
+      For an <code>serviceURL</code> using the <code>rmi</code>
+      protocol, the <code><em>port</em></code>, if present, indicates
+      what port the generated remote object should be exported on.  It
+      has no other effect.</p>
+
+    <p>If the user provides an <code>RMIServerImpl</code> rather than a
+      <code>JMXServiceURL</code>, then the generated
+      <code>JMXServiceURL</code> will have the local host name in its
+      <code><em>host</em></code> part and no
+      <code><em>port</em></code>.</p>
+
+
+    <h4><a name="directory">Connector addresses based on directory
+	entries</a></h4>
+
+    <p>As an alternative to the generated addresses just described,
+      the <code>serviceURL</code> address supplied when creating a
+      connector server can specify a <em>directory address</em> in
+      which to store the provided or generated <code>RMIServer</code>
+      stub.  This directory address is then used by both client and
+      server.</p>
+
+    <p>In this case, the <code>serviceURL</code> has the following form:</p>
+
+    <pre>
+    <code>service:jmx:rmi://<em>host</em>:<em>port</em>/jndi/<em>jndi-name</em></code>
+    </pre>
+
+    <p>Here, <code><em>jndi-name</em></code> is a string that can be
+      supplied to {@link javax.naming.InitialContext#bind
+      javax.naming.InitialContext.bind}.</p>
+
+    <p>As usual, the <code><em>host</em></code> and
+      <code>:<em>port</em></code> can be omitted.</p>
+
+    <p>The connector server will generate an
+      <code>RMIServerImpl</code> based on the protocol
+      (<code>rmi</code>) and the <code><em>port</em></code> if any.  When
+      the connector server is started, it will derive a stub from this
+      object using its {@link
+      javax.management.remote.rmi.RMIServerImpl#toStub toStub} method
+      and store the object using the given
+      <code><em>jndi-name</em></code>.  The properties defined by the
+      JNDI API are consulted as usual.</p>
+
+    <p>For example, if the <code>JMXServiceURL</code> is:
+
+      <pre>
+      <code>service:jmx:rmi://ignoredhost/jndi/rmi://myhost/myname</code>
+      </pre>
+
+      then the connector server will generate an
+      <code>RMIJRMPServerImpl</code> and store its stub using the JNDI
+      name
+
+      <pre>
+      <code>rmi://myhost/myname</code>
+      </pre>
+
+      which means entry <code>myname</code> in the RMI registry
+      running on the default port of host <code>myhost</code>.  Note
+      that the RMI registry only allows registration from the local
+      host.  So, in this case, <code>myhost</code> must be the name
+      (or a name) of the host that the connector server is running
+      on.
+
+    <p>In this <code>JMXServiceURL</code>, the first <code>rmi:</code>
+      specifies the RMI
+      connector, while the second <code>rmi:</code> specifies the RMI
+      registry.
+
+    <p>As another example, if the <code>JMXServiceURL</code> is:
+
+      <pre>
+      <code>service:jmx:rmi://ignoredhost/jndi/ldap://dirhost:9999/cn=this,ou=that</code>
+      </pre>
+
+      then the connector server will generate an
+      <code>RMIJRMPServerImpl</code> and store its stub using the JNDI
+      name
+
+      <pre>
+      <code>ldap://dirhost:9999/cn=this,ou=that</code>
+      </pre>
+
+      which means entry <code>cn=this,ou=that</code> in the LDAP
+      directory running on port 9999 of host <code>dirhost</code>.
+
+    <p>If the <code>JMXServiceURL</code> is:
+
+      <pre>
+      <code>service:jmx:rmi://ignoredhost/jndi/cn=this,ou=that</code>
+      </pre>
+
+      then the connector server will generate an
+      <code>RMIJRMPServerImpl</code> and store its stub using the JNDI
+      name
+
+      <pre>
+      <code>cn=this,ou=that</code>
+      </pre>
+
+      For this case to work, the JNDI API must have been configured
+      appropriately to supply the information about what directory to
+      use.
+
+    <p>In these examples, the host name <code>ignoredhost</code> is
+      not used by the connector server or its clients.  It can be
+      omitted, for example:</p>
+
+      <pre>
+      <code>service:jmx:rmi:///jndi/cn=this,ou=that</code>
+      </pre>
+
+    <p>However, it is good practice to use the name of the host
+      where the connector server is running.  This is often different
+      from the name of the directory host.</p>
+
+
+    <h4>Connector server attributes</h4>
+
+    <p>When using the default JRMP transport, RMI socket factories can
+      be specified using the attributes
+      <code>jmx.remote.rmi.client.socket.factory</code> and
+      <code>jmx.remote.rmi.server.socket.factory</code> in the
+      <code>environment</code> given to the
+      <code>RMIConnectorServer</code> constructor.  The values of these
+      attributes must be of type {@link
+      java.rmi.server.RMIClientSocketFactory} and {@link
+      java.rmi.server.RMIServerSocketFactory}, respectively.  These
+      factories are used when creating the RMI objects associated with
+      the connector.</p>
+
+    <h3>Creating an RMI connector client</h3>
+
+    <p>An RMI connector client is usually constructed using {@link
+      javax.management.remote.JMXConnectorFactory}, with a
+      <code>JMXServiceURL</code> that has <code>rmi</code> as its protocol.</p>
+
+    <p>If the <code>JMXServiceURL</code> was generated by the server,
+      as described above under <a href="#servergen">"connector
+      addresses generated by the server"</a>, then the client will
+      need to obtain it directly or indirectly from the server.
+      Typically, the server makes the <code>JMXServiceURL</code>
+      available by storing it in a file or a lookup service.</p>
+
+    <p>If the <code>JMXServiceURL</code> uses the directory syntax, as
+      described above under <a href="#directory">"connector addresses
+      based on directory entries"</a>, then the client may obtain it
+      as just explained, or client and server may both know the
+      appropriate directory entry to use.  For example, if the
+      connector server for the Whatsit agent uses the entry
+      <code>whatsit-agent-connector</code> in the RMI registry on host
+      <code>myhost</code>, then client and server can both know
+      that the appropriate <code>JMXServiceURL</code> is:</p>
+
+    <pre>
+    <code>service:jmx:rmi:///jndi/rmi://myhost/whatsit-agent-connector</code>
+    </pre>
+
+    <p>If you have an RMI stub of type {@link
+      javax.management.remote.rmi.RMIServer RMIServer}, you can
+      construct an RMI connection directly by using the appropriate
+      constructor of {@link javax.management.remote.rmi.RMIConnector
+      RMIConnector}.</p>
+
+    <h3>Dynamic code downloading</h3>
+
+    <p>If an RMI connector client or server receives from its peer an
+      instance of a class that it does not know, and if dynamic code
+      downloading is active for the RMI connection, then the class can
+      be downloaded from a codebase specified by the peer.  The
+      article <a
+    href="{@docRoot}/../technotes/guides/rmi/codebase.html"><em>Dynamic
+    code downloading using Java RMI</em></a> explains this in more
+    detail.</p>
+
+
+    @see <a href="{@docRoot}/../technotes/guides/rmi/index.html">
+	Java&trade; Remote Method
+	Invocation (RMI)</a>
+
+    @see <a href="{@docRoot}/../technotes/guides/jndi/index.html">
+	Java Naming and Directory Interface&trade; (JNDI)</a>
+
+    @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045,
+    section 6.8, "Base64 Content-Transfer-Encoding"</a>
+
+
+    @since 1.5
+
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management.rmi/share/classes/module-info.java	Thu Feb 02 16:50:46 2017 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines the RMI Connector for the Java Management Extensions (JMX) Remote API.
+ * <P>
+ * The {@linkplain javax.management.remote.rmi RMI connector} is a connector
+ * for the JMX Remote API that uses RMI to transmit client requests to a remote
+ * MBean server.
+ *
+ * @provides javax.management.remote.JMXConnectorProvider
+ *           A provider of {@code JMXConnector} for the RMI protocol.<br>
+ *           Instances of {@code JMXConnector} using the RMI protocol
+ *           are usually created by the {@link
+ *           javax.management.remote.JMXConnectorFactory} which will locate
+ *           and load the appropriate {@code JMXConnectorProvider} service
+ *           implementation for the given protocol.
+ *
+ * @provides javax.management.remote.JMXConnectorServerProvider
+ *           A provider of {@code JMXConnectorServer} for the RMI protocol.<br>
+ *           Instances of {@code JMXConnectorServer} using the RMI protocol
+ *           are usually created by the {@link
+ *           javax.management.remote.JMXConnectorServerFactory} which will locate
+ *           and load the appropriate {@code JMXConnectorServerProvider} service
+ *           implementation for the given protocol.
+ *
+ */
+module java.management.rmi {
+
+    requires transitive java.management;
+    requires transitive java.rmi;
+    requires java.naming;
+
+    exports javax.management.remote.rmi;
+
+    // The qualified export below is required to preserve backward
+    // compatibility for the legacy case where an ordered list
+    // of package prefixes can be specified to the factory.
+    exports com.sun.jmx.remote.protocol.rmi to java.management;
+
+    // jdk.management.agent needs to create an RMIExporter instance.
+    exports com.sun.jmx.remote.internal.rmi to jdk.management.agent;
+
+    // The java.management.rmi module provides implementations
+    // of the JMXConnectorProvider and JMXConnectorServerProvider
+    // services supporting the RMI protocol.
+    provides javax.management.remote.JMXConnectorProvider
+        with com.sun.jmx.remote.protocol.rmi.ClientProvider;
+    provides javax.management.remote.JMXConnectorServerProvider
+        with com.sun.jmx.remote.protocol.rmi.ServerProvider;
+
+}
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Thu Feb 02 12:28:23 2017 +0100
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Thu Feb 02 16:50:46 2017 +0000
@@ -52,7 +52,6 @@
 import com.sun.jmx.remote.util.ClassLogger;
 import com.sun.jmx.remote.util.EnvHelp;
 import java.lang.reflect.UndeclaredThrowableException;
-import java.rmi.UnmarshalException;
 import java.util.concurrent.RejectedExecutionException;
 
 
@@ -633,7 +632,7 @@
                 }
 
                 return nr;
-            } catch (ClassNotFoundException | NotSerializableException | UnmarshalException e) {
+            } catch (ClassNotFoundException | NotSerializableException e) {
                 logger.trace("NotifFetcher.fetchNotifs", e);
                 return fetchOneNotif();
             } catch (IOException ioe) {
@@ -705,7 +704,7 @@
                 try {
                     // 1 notif to skip possible missing class
                     result = cnf.fetchNotifs(startSequenceNumber, 1, 0L);
-                } catch (ClassNotFoundException | NotSerializableException | UnmarshalException e) {
+                } catch (ClassNotFoundException | NotSerializableException e) {
                     logger.warning("NotifFetcher.fetchOneNotif",
                                    "Failed to deserialize a notification: "+e.toString());
                     if (logger.traceOn()) {
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ProxyRef.java	Thu Feb 02 12:28:23 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jmx.remote.internal;
-
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.lang.reflect.Method;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.server.RemoteObject;
-import java.rmi.server.RemoteRef;
-
-
-@SuppressWarnings("deprecation")
-public class ProxyRef implements RemoteRef {
-    private static final long serialVersionUID = -6503061366316814723L;
-
-    public ProxyRef(RemoteRef ref) {
-        this.ref = ref;
-    }
-
-    public void readExternal(ObjectInput in)
-            throws IOException, ClassNotFoundException {
-        ref.readExternal(in);
-    }
-
-    public void writeExternal(ObjectOutput out) throws IOException {
-        ref.writeExternal(out);
-    }
-
-    /**
-     * @deprecated
-     */
-    @Deprecated
-    public void invoke(java.rmi.server.RemoteCall call) throws Exception {
-        ref.invoke(call);
-    }
-
-    public Object invoke(Remote obj, Method method, Object[] params,
-                         long opnum) throws Exception {
-        return ref.invoke(obj, method, params, opnum);
-    }
-
-    /**
-     * @deprecated
-     */
-    @Deprecated
-    public void done(java.rmi.server.RemoteCall call) throws RemoteException {
-        ref.done(call);
-    }
-
-    public String getRefClass(ObjectOutput out) {
-        return ref.getRefClass(out);
-    }
-
-    /**
-     * @deprecated
-     */
-    @Deprecated
-    public java.rmi.server.RemoteCall newCall(RemoteObject obj,
-            java.rmi.server.Operation[] op, int opnum,
-                              long hash) throws RemoteException {
-        return ref.newCall(obj, op, opnum, hash);
-    }
-
-    public boolean remoteEquals(RemoteRef obj) {
-        return ref.remoteEquals(obj);
-    }
-
-    public int remoteHashCode() {
-        return ref.remoteHashCode();
-    }
-
-    public String remoteToString() {
-        return ref.remoteToString();
-    }
-
-    protected RemoteRef ref;
-}
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/RMIExporter.java	Thu Feb 02 12:28:23 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jmx.remote.internal;
-
-import java.rmi.NoSuchObjectException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.server.RMIClientSocketFactory;
-import java.rmi.server.RMIServerSocketFactory;
-import java.rmi.server.UnicastRemoteObject;
-
-/**
- * <p>Unpublished interface controlling how the RMI Connector Server
- * exports objects.  The RMIServerImpl object and each
- * RMIConnectionImpl object are exported using the exporter.  The
- * default exporter calls {@link
- * UnicastRemoteObject#exportObject(Remote, int,
- * RMIClientSocketFactory, RMIServerSocketFactory)} to export objects
- * and {@link UnicastRemoteObject#unexportObject(Remote, boolean)} to
- * unexport them.  A replacement exporter can be specified via the
- * {@link #EXPORTER_ATTRIBUTE} property in the environment Map passed
- * to the RMI connector server.</p>
- */
-public interface RMIExporter {
-    public static final String EXPORTER_ATTRIBUTE =
-        "com.sun.jmx.remote.rmi.exporter";
-
-    public Remote exportObject(Remote obj,
-                               int port,
-                               RMIClientSocketFactory csf,
-                               RMIServerSocketFactory ssf)
-            throws RemoteException;
-
-    public boolean unexportObject(Remote obj, boolean force)
-            throws NoSuchObjectException;
-}
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/Unmarshal.java	Thu Feb 02 12:28:23 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jmx.remote.internal;
-
-import java.io.IOException;
-import java.rmi.MarshalledObject;
-
-public interface Unmarshal {
-    public Object get(MarshalledObject<?> mo)
-            throws IOException, ClassNotFoundException;
-}
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/protocol/rmi/ClientProvider.java	Thu Feb 02 12:28:23 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jmx.remote.protocol.rmi;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.util.Map;
-
-import javax.management.remote.JMXConnectorProvider;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXServiceURL;
-import javax.management.remote.rmi.RMIConnector;
-
-public class ClientProvider implements JMXConnectorProvider {
-
-    public JMXConnector newJMXConnector(JMXServiceURL serviceURL,
-                                        Map<String,?> environment)
-            throws IOException {
-        if (!serviceURL.getProtocol().equals("rmi")) {
-            throw new MalformedURLException("Protocol not rmi: " +
-                                            serviceURL.getProtocol());
-        }
-        return new RMIConnector(serviceURL, environment);
-    }
-}
--- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/protocol/rmi/ServerProvider.java	Thu Feb 02 12:28:23 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.jmx.remote.protocol.rmi;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.util.Map;
-
-import javax.management.MBeanServer;
-import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerProvider;
-import javax.management.remote.JMXServiceURL;
-import javax.management.remote.rmi.RMIConnectorServer;
-
-public class ServerProvider implements JMXConnectorServerProvider {
-
-    public JMXConnectorServer newJMXConnectorServer(JMXServiceURL serviceURL,
-                                                    Map<String,?> environment,
-                                                    MBeanServer mbeanServer)
-            throws IOException {
-        if (!serviceURL.getProtocol().equals("rmi")) {
-            throw new MalformedURLException("Protocol not rmi: " +
-                                            serviceURL.getProtocol());
-        }
-        return new RMIConnectorServer(serviceURL, environment, mbeanServer);
-    }
-
-}
--- a/jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java	Thu Feb 02 12:28:23 2017 +0100
+++ b/jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java	Thu Feb 02 16:50:46 2017 +0000
@@ -27,13 +27,17 @@
 
 import com.sun.jmx.mbeanserver.Util;
 import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Module;
 import java.net.MalformedURLException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Iterator;
 import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
 import java.util.StringTokenizer;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
@@ -332,25 +336,32 @@
 
         IOException exception = null;
         if (provider == null) {
+            Predicate<Provider<?>> systemProvider =
+                    JMXConnectorFactory::isSystemProvider;
             // Loader is null when context class loader is set to null
             // and no loader has been provided in map.
             // com.sun.jmx.remote.util.Service class extracted from j2se
             // provider search algorithm doesn't handle well null classloader.
+            JMXConnector connection = null;
             if (loader != null) {
                 try {
-                    JMXConnector connection =
-                        getConnectorAsService(loader, providerURL, envcopy);
-                    if (connection != null)
-                        return connection;
+                    connection = getConnectorAsService(loader,
+                                                       providerURL,
+                                                       envcopy,
+                                                       systemProvider.negate());
+                    if (connection != null) return connection;
                 } catch (JMXProviderException e) {
                     throw e;
                 } catch (IOException e) {
                     exception = e;
                 }
             }
-            provider = getProvider(protocol, PROTOCOL_PROVIDER_DEFAULT_PACKAGE,
-                            JMXConnectorFactory.class.getClassLoader(),
-                            providerClassName, targetInterface);
+            connection = getConnectorAsService(
+                             JMXConnectorFactory.class.getClassLoader(),
+                             providerURL,
+                             Collections.unmodifiableMap(envcopy),
+                             systemProvider);
+            if (connection != null) return connection;
         }
 
         if (provider == null) {
@@ -437,13 +448,6 @@
         return instance;
     }
 
-    static <T> Iterator<T> getProviderIterator(final Class<T> providerClass,
-                                               final ClassLoader loader) {
-       ServiceLoader<T> serviceLoader =
-                ServiceLoader.load(providerClass, loader);
-       return serviceLoader.iterator();
-    }
-
     private static ClassLoader wrap(final ClassLoader parent) {
         return parent != null ? AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
             @Override
@@ -459,44 +463,265 @@
         }) : null;
     }
 
+    /**
+     * Checks whether the given provider is our system provider for
+     * the RMI connector.
+     * If providers for additional protocols are added in the future
+     * then the name of their modules may need to be added here.
+     * System providers will be loaded only if no other provider is found.
+     * @param provider the provider to test.
+     * @return true if this provider is a default system provider.
+     */
+    static boolean isSystemProvider(Provider<?> provider) {
+        Module providerModule = provider.type().getModule();
+        return providerModule.isNamed()
+           && providerModule.getName().equals("java.management.rmi");
+    }
+
+    /**
+     * Creates a JMXConnector from the first JMXConnectorProvider service
+     * supporting the given url that can be loaded from the given loader.
+     * <p>
+     * Parses the list of JMXConnectorProvider services that can be loaded
+     * from the given loader, only retaining those that satisfy the given filter.
+     * Then for each provider, attempts to create a new JMXConnector.
+     * The first JMXConnector successfully created is returned.
+     * <p>
+     * The filter predicate is usually used to either exclude system providers
+     * or only retain system providers (see isSystemProvider(...) above).
+     *
+     * @param loader The ClassLoader to use when looking up an implementation
+     *        of the service. If null, then only installed services will be
+     *        considered.
+     *
+     * @param url The JMXServiceURL of the connector for which a provider is
+     *        requested.
+     *
+     * @param filter A filter used to exclude or return provider
+     *        implementations. Typically the filter will either exclude
+     *        system services (system default implementations) or only
+     *        retain those.
+     *        This can allow to first look for custom implementations (e.g.
+     *        deployed on the CLASSPATH with META-INF/services) and
+     *        then only default to system implementations.
+     *
+     * @throws IOException if no connector could not be instantiated, and
+     *         at least one provider threw an exception that wasn't a
+     *         {@code MalformedURLException} or a {@code JMProviderException}.
+     *
+     * @throws JMXProviderException if a provider for the protocol in
+     *         <code>url</code> was found, but couldn't create the connector
+     *         some reason.
+     *
+     * @return an instance of JMXConnector if a provider was found from
+     *         which one could be instantiated, {@code null} otherwise.
+     */
     private static JMXConnector getConnectorAsService(ClassLoader loader,
                                                       JMXServiceURL url,
-                                                      Map<String, ?> map)
+                                                      Map<String, ?> map,
+                                                      Predicate<Provider<?>> filter)
         throws IOException {
 
-        Iterator<JMXConnectorProvider> providers =
-                getProviderIterator(JMXConnectorProvider.class, loader);
-        JMXConnector connection;
-        IOException exception = null;
-        while (providers.hasNext()) {
-            JMXConnectorProvider provider = providers.next();
-            try {
-                connection = provider.newJMXConnector(url, map);
-                return connection;
-            } catch (JMXProviderException e) {
-                throw e;
-            } catch (Exception e) {
-                if (logger.traceOn())
-                    logger.trace("getConnectorAsService",
-                                 "URL[" + url +
-                                 "] Service provider exception: " + e);
-                if (!(e instanceof MalformedURLException)) {
-                    if (exception == null) {
-                        if (e instanceof IOException) {
-                            exception = (IOException) e;
-                        } else {
-                            exception = EnvHelp.initCause(
-                                new IOException(e.getMessage()), e);
+        final ConnectorFactory<JMXConnectorProvider, JMXConnector> factory =
+                (p) -> p.newJMXConnector(url, map);
+        return getConnectorAsService(JMXConnectorProvider.class, loader, url,
+                                     filter, factory);
+    }
+
+
+    /**
+     * A factory function that can create a connector from a provider.
+     * The pair (P,C) will be either one of:
+     * a. (JMXConnectorProvider, JMXConnector) or
+     * b. (JMXConnectorServerProvider, JMXConnectorServer)
+     */
+    @FunctionalInterface
+    static interface ConnectorFactory<P,C> {
+        public C apply(P provider) throws Exception;
+    }
+
+    /**
+     * An instance of ProviderFinder is used to traverse a
+     * {@code Stream<Provider<P>>} and find the first implementation of P
+     * that supports creating a connector C from the given JMXServiceURL.
+     * <p>
+     * The pair (P,C) will be either one of: <br>
+     * a. (JMXConnectorProvider, JMXConnector) or <br>
+     * b. (JMXConnectorServerProvider, JMXConnectorServer)
+     * <p>
+     * The first connector successfully created while traversing the stream
+     * is stored in the ProviderFinder instance. After that, the
+     * ProviderFinder::test method, if called, will always return false, skipping
+     * the remaining providers.
+     * <p>
+     * An instance of ProviderFinder is always expected to be used in conjunction
+     * with Stream::findFirst, so that the stream traversal is stopped as soon
+     * as a matching provider is found.
+     * <p>
+     * At the end of the stream traversal, the ProviderFinder::get method can be
+     * used to obtain the connector instance (an instance of C) that was created.
+     * If no connector could be created, and an exception was encountered while
+     * traversing the stream and attempting to create the connector, then that
+     * exception will be thrown by ProviderFinder::get, wrapped, if needed,
+     * inside an IOException.
+     * <p>
+     * If any JMXProviderException is encountered while traversing the stream and
+     * attempting to create the connector, that exception will be wrapped in an
+     * UncheckedIOException and thrown immediately within the stream, thus
+     * interrupting the traversal.
+     * <p>
+     * If no matching provider was found (no provider found or attempting
+     * factory.apply always returned null or threw a MalformedURLException,
+     * indicating the provider didn't support the protocol asked for by
+     * the JMXServiceURL), then ProviderFinder::get will simply return null.
+     */
+    private static final class ProviderFinder<P,C> implements Predicate<Provider<P>> {
+
+        final ConnectorFactory<P,C> factory;
+        final JMXServiceURL  url;
+        private IOException  exception = null;
+        private C connection = null;
+
+        ProviderFinder(ConnectorFactory<P,C> factory, JMXServiceURL url) {
+            this.factory = factory;
+            this.url = url;
+        }
+
+        /**
+         * Returns {@code true} for the first provider {@code sp} that can
+         * be used to obtain an instance of {@code C} from the given
+         * {@code factory}.
+         *
+         * @param sp a candidate provider for instantiating {@code C}.
+         *
+         * @throws UncheckedIOException if {@code sp} throws a
+         *         JMXProviderException. The JMXProviderException is set as the
+         *         root cause.
+         *
+         * @return {@code true} for the first provider {@code sp} for which
+         *         {@code C} could be instantiated, {@code false} otherwise.
+         */
+        public boolean test(Provider<P> sp) {
+            if (connection == null) {
+                P provider = sp.get();
+                try {
+                    connection = factory.apply(provider);
+                    return connection != null;
+                } catch (JMXProviderException e) {
+                    throw new UncheckedIOException(e);
+                } catch (Exception e) {
+                    if (logger.traceOn())
+                        logger.trace("getConnectorAsService",
+                             "URL[" + url +
+                             "] Service provider exception: " + e);
+                    if (!(e instanceof MalformedURLException)) {
+                        if (exception == null) {
+                            if (e instanceof IOException) {
+                                exception = (IOException) e;
+                            } else {
+                                exception = EnvHelp.initCause(
+                                    new IOException(e.getMessage()), e);
+                            }
                         }
                     }
                 }
-                continue;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an instance of {@code C} if a provider was found from
+         * which {@code C} could be instantiated.
+         *
+         * @throws IOException if {@code C} could not be instantiated, and
+         *         at least one provider threw an exception that wasn't a
+         *         {@code MalformedURLException} or a {@code JMProviderException}.
+         *
+         * @return an instance of {@code C} if a provider was found from
+         *         which {@code C} could be instantiated, {@code null} otherwise.
+         */
+        C get() throws IOException {
+            if (connection != null) return connection;
+            else if (exception != null) throw exception;
+            else return null;
+        }
+    }
+
+    /**
+     * Creates a connector from a provider loaded from the ServiceLoader.
+     * <p>
+     * The pair (P,C) will be either one of: <br>
+     * a. (JMXConnectorProvider, JMXConnector) or <br>
+     * b. (JMXConnectorServerProvider, JMXConnectorServer)
+     *
+     * @param providerClass The service type for which an implementation
+     *        should be looked up from the {@code ServiceLoader}. This will
+     *        be either {@code JMXConnectorProvider.class} or
+     *        {@code JMXConnectorServerProvider.class}
+     *
+     * @param loader The ClassLoader to use when looking up an implementation
+     *        of the service. If null, then only installed services will be
+     *        considered.
+     *
+     * @param url The JMXServiceURL of the connector for which a provider is
+     *        requested.
+     *
+     * @param filter A filter used to exclude or return provider
+     *        implementations. Typically the filter will either exclude
+     *        system services (system default implementations) or only
+     *        retain those.
+     *        This can allow to first look for custom implementations (e.g.
+     *        deployed on the CLASSPATH with META-INF/services) and
+     *        then only default to system implementations.
+     *
+     * @param factory A functional factory that can attempt to create an
+     *        instance of connector {@code C} from a provider {@code P}.
+     *        Typically, this is a simple wrapper over {@code
+     *        JMXConnectorProvider::newJMXConnector} or {@code
+     *        JMXConnectorProviderServer::newJMXConnectorServer}.
+     *
+     * @throws IOException if {@code C} could not be instantiated, and
+     *         at least one provider {@code P} threw an exception that wasn't a
+     *         {@code MalformedURLException} or a {@code JMProviderException}.
+     *
+     * @throws JMXProviderException if a provider {@code P} for the protocol in
+     *         <code>url</code> was found, but couldn't create the connector
+     *         {@code C} for some reason.
+     *
+     * @return an instance of {@code C} if a provider {@code P} was found from
+     *         which one could be instantiated, {@code null} otherwise.
+     */
+    static <P,C> C getConnectorAsService(Class<P> providerClass,
+                                         ClassLoader loader,
+                                         JMXServiceURL url,
+                                         Predicate<Provider<?>> filter,
+                                         ConnectorFactory<P,C> factory)
+        throws IOException {
+
+        // sanity check
+        if (JMXConnectorProvider.class != providerClass
+            && JMXConnectorServerProvider.class != providerClass) {
+            // should never happen
+            throw new InternalError("Unsupported service interface: "
+                                    + providerClass.getName());
+        }
+
+        ServiceLoader<P> serviceLoader = loader == null
+                ? ServiceLoader.loadInstalled(providerClass)
+                : ServiceLoader.load(providerClass, loader);
+        Stream<Provider<P>> stream = serviceLoader.stream().filter(filter);
+        ProviderFinder<P,C> finder = new ProviderFinder<>(factory, url);
+
+        try {
+            stream.filter(finder).findFirst();
+            return finder.get();
+        } catch (UncheckedIOException e) {
+            if (e.getCause() instanceof JMXProviderException) {
+                throw (JMXProviderException) e.getCause();
+            } else {
+                throw e;
             }
         }
-        if (exception == null)
-            return null;
-        else
-            throw exception;
     }
 
     static <T> T getProvider(String protocol,
--- a/jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Thu Feb 02 12:28:23 2017 +0100
+++ b/jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Thu Feb 02 16:50:46 2017 +0000
@@ -30,13 +30,16 @@
 import com.sun.jmx.remote.util.EnvHelp;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.MalformedURLException;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.ServiceLoader.Provider;
+import java.util.function.Predicate;
 
 import javax.management.MBeanServer;
+import javax.management.remote.JMXConnectorFactory.ConnectorFactory;
 
 /**
  * <p>Factory to create JMX API connector servers.  There
@@ -205,43 +208,15 @@
     }
 
     private static JMXConnectorServer
-        getConnectorServerAsService(ClassLoader loader,
-                                    JMXServiceURL url,
-                                    Map<String, ?> map,
-                                    MBeanServer mbs)
+        getConnectorServerAsService(ClassLoader loader, JMXServiceURL url,
+                                    Map<String, ?> map, MBeanServer mbs,
+                                    Predicate<Provider<?>> filter)
         throws IOException {
-        Iterator<JMXConnectorServerProvider> providers =
-                JMXConnectorFactory.
-                getProviderIterator(JMXConnectorServerProvider.class, loader);
-
-        IOException exception = null;
-        while (providers.hasNext()) {
-            try {
-                return providers.next().newJMXConnectorServer(url, map, mbs);
-            } catch (JMXProviderException e) {
-                throw e;
-            } catch (Exception e) {
-                if (logger.traceOn())