author | dfuchs |
Thu, 02 Feb 2017 16:50:46 +0000 | |
changeset 43503 | bc7f8619ab70 |
parent 43502 | aec39566b45e |
child 43504 | 937634498e8c |
child 43505 | dbb07ad63c71 |
--- 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™ Remote Method + Invocation (RMI)</a> + + @see <a href="{@docRoot}/../technotes/guides/jndi/index.html"> + Java Naming and Directory Interface™ (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()) - 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; - } - } - if (exception == null) - return null; - else - throw exception; + final ConnectorFactory<JMXConnectorServerProvider,JMXConnectorServer> + factory = (p) -> p.newJMXConnectorServer(url, map, mbs); + return JMXConnectorFactory.getConnectorAsService( + JMXConnectorServerProvider.class, + loader, url, filter, factory); } /** @@ -309,18 +284,22 @@ loader); IOException exception = null; + JMXConnectorServer connection = 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. if (loader != null) { try { - JMXConnectorServer connection = + connection = getConnectorServerAsService(loader, serviceURL, envcopy, - mbeanServer); + mbeanServer, + systemProvider.negate()); if (connection != null) return connection; } catch (JMXProviderException e) { @@ -329,13 +308,13 @@ exception = e; } } - provider = - JMXConnectorFactory.getProvider( - protocol, - PROTOCOL_PROVIDER_DEFAULT_PACKAGE, - JMXConnectorFactory.class.getClassLoader(), - providerClassName, - targetInterface); + connection = getConnectorServerAsService( + JMXConnectorFactory.class.getClassLoader(), + serviceURL, + Collections.unmodifiableMap(envcopy), + mbeanServer, + systemProvider); + if (connection != null) return connection; } if (provider == null) {
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/NoCallStackClassLoader.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,296 +0,0 @@ -/* - * 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("\""); - } -} - -*/
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnection.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1092 +0,0 @@ -/* - * 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; -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1834 +0,0 @@ -/* - * 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 com.sun.jmx.mbeanserver.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; - } - - } -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2289 +0,0 @@ -/* - * 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.mbeanserver.Util; -import com.sun.jmx.remote.internal.ClientCommunicatorAdmin; -import com.sun.jmx.remote.internal.ClientListenerInfo; -import com.sun.jmx.remote.internal.ClientNotifForwarder; -import com.sun.jmx.remote.internal.ProxyRef; -import com.sun.jmx.remote.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; - -/** - * <p>A connection to a remote RMI connector. Usually, such - * connections are made using {@link - * javax.management.remote.JMXConnectorFactory JMXConnectorFactory}. - * However, specialized applications can use this class directly, for - * example with an {@link RMIServer} stub obtained without going - * through JNDI.</p> - * - * @since 1.5 - */ -public class RMIConnector implements JMXConnector, Serializable, JMXAddressable { - - private static final ClassLogger logger = - new ClassLogger("javax.management.remote.rmi", "RMIConnector"); - - private static final long serialVersionUID = 817323035842634473L; - - private RMIConnector(RMIServer rmiServer, JMXServiceURL address, - Map<String, ?> environment) { - if (rmiServer == null && address == null) throw new - IllegalArgumentException("rmiServer and jmxServiceURL both null"); - initTransients(); - - this.rmiServer = rmiServer; - this.jmxServiceURL = address; - if (environment == null) { - this.env = Collections.emptyMap(); - } else { - EnvHelp.checkAttributes(environment); - this.env = Collections.unmodifiableMap(environment); - } - } - - /** - * <p>Constructs an {@code RMIConnector} 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) { - throw ioe; // 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 com.sun.jmx.remote.internal; - - import java.lang.reflect.Method; - import java.rmi.Remote; - import java.rmi.server.RemoteRef; - import com.sun.jmx.remote.internal.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.PRef"; - private static final Constructor<?> proxyRefConstructor; - static { - final String pRefByteCodeString = - "\312\376\272\276\0\0\0\60\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\34jdk/jmx/remote/internal/PRef\1\0$com/sun/jmx/remote/inter"+ - "nal/ProxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Ljava/rm"+ - "i/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(", ", "[", "]")) - : "[]"; - } -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,819 +0,0 @@ -/* - * 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>(); -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIIIOPServerImpl.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * 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(); - } -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* - * 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.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); - } - } - } - } - } -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIServer.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * 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; -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIServerImpl.java Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,550 +0,0 @@ -/* - * 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; -}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/package.html Thu Feb 02 12:28:23 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ -<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™ Remote Method - Invocation (RMI)</a> - - @see <a href="{@docRoot}/../technotes/guides/jndi/index.html"> - Java Naming and Directory Interface™ (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>
--- a/jdk/src/java.management/share/classes/module-info.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/src/java.management/share/classes/module-info.java Thu Feb 02 16:50:46 2017 +0000 @@ -30,8 +30,6 @@ * JVM and other components in the Java runtime. */ module java.management { - requires transitive java.rmi; - requires java.naming; exports java.lang.management; exports javax.management; @@ -41,10 +39,14 @@ exports javax.management.openmbean; exports javax.management.relation; exports javax.management.remote; - exports javax.management.remote.rmi; exports javax.management.timer; - exports com.sun.jmx.remote.internal to jdk.management.agent; - exports com.sun.jmx.remote.security to jdk.management.agent; + exports com.sun.jmx.remote.internal to + java.management.rmi, + jdk.management.agent; + exports com.sun.jmx.remote.security to + java.management.rmi, + jdk.management.agent; + exports com.sun.jmx.remote.util to java.management.rmi; exports sun.management to jdk.jconsole, jdk.management,
--- a/jdk/src/java.rmi/share/classes/module-info.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/src/java.rmi/share/classes/module-info.java Thu Feb 02 16:50:46 2017 +0000 @@ -41,13 +41,12 @@ exports sun.rmi.registry to jdk.management.agent; exports sun.rmi.server to - java.management, + java.management.rmi, jdk.management.agent, jdk.jconsole; exports sun.rmi.transport to - java.management, + java.management.rmi, jdk.management.agent, jdk.jconsole; uses java.rmi.server.RMIClassLoaderSpi; } -
--- a/jdk/src/java.se/share/classes/module-info.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/src/java.se/share/classes/module-info.java Thu Feb 02 16:50:46 2017 +0000 @@ -36,6 +36,7 @@ requires transitive java.instrument; requires transitive java.logging; requires transitive java.management; + requires transitive java.management.rmi; requires transitive java.naming; requires transitive java.prefs; requires transitive java.rmi; @@ -47,4 +48,3 @@ requires transitive java.xml; requires transitive java.xml.crypto; } -
--- a/jdk/src/jdk.jconsole/share/classes/module-info.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/src/jdk.jconsole/share/classes/module-info.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ module jdk.jconsole { requires transitive java.desktop; requires transitive java.management; - requires java.logging; + requires java.management.rmi; requires java.rmi; requires jdk.attach; requires jdk.jvmstat; @@ -35,4 +35,3 @@ exports com.sun.tools.jconsole; uses com.sun.tools.jconsole.JConsolePlugin; } -
--- a/jdk/src/jdk.management.agent/share/classes/module-info.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/src/jdk.management.agent/share/classes/module-info.java Thu Feb 02 16:50:46 2017 +0000 @@ -25,9 +25,9 @@ module jdk.management.agent { requires java.management; + requires java.management.rmi; exports jdk.internal.agent to jdk.jconsole; uses jdk.internal.agent.spi.AgentProvider; } -
--- a/jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Thu Feb 02 16:50:46 2017 +0000 @@ -73,7 +73,7 @@ import javax.rmi.ssl.SslRMIServerSocketFactory; import javax.security.auth.Subject; -import com.sun.jmx.remote.internal.RMIExporter; +import com.sun.jmx.remote.internal.rmi.RMIExporter; import com.sun.jmx.remote.security.JMXPluggableAuthenticator; import jdk.internal.agent.Agent;
--- a/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Test that JMX classes use fully-qualified class names * in MBeanNotificationInfo * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean NotificationInfoTest * @run build NotificationInfoTest * @run main NotificationInfoTest
--- a/jdk/test/javax/management/MBeanServer/ExceptionTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/MBeanServer/ExceptionTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Checks that exceptions are correctly wired (compared to reference). * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @run main/othervm/timeout=300 -DDEBUG_STANDARD ExceptionTest */ @@ -368,5 +368,3 @@ } } - -
--- a/jdk/test/javax/management/MBeanServer/OldMBeanServerTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/MBeanServer/OldMBeanServerTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -97,7 +97,7 @@ * @bug 5072268 * @summary Test that nothing assumes a post-1.2 MBeanServer * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run main/othervm -ea OldMBeanServerTest */
--- a/jdk/test/javax/management/modelmbean/UnserializableTargetObjectTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/modelmbean/UnserializableTargetObjectTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Test that a RequiredModelMBean operation can have a targetObject * that is not serializable * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean UnserializableTargetObjectTest * @run build UnserializableTargetObjectTest * @run main UnserializableTargetObjectTest
--- a/jdk/test/javax/management/mxbean/GenericArrayTypeTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/GenericArrayTypeTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Test support for arrays in parameterized types. * @author Luis-Miguel Alventosa * @key intermittent - * @modules java.management + * @modules java.management.rmi * @run clean GenericArrayTypeTest * @run build GenericArrayTypeTest * @run main GenericArrayTypeTest
--- a/jdk/test/javax/management/mxbean/MXBeanExceptionHandlingTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/MXBeanExceptionHandlingTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Checks correct exception and error events from NotificationListener * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @compile Basic.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanExceptionHandlingTest -timeForNotificationInSeconds 3
--- a/jdk/test/javax/management/mxbean/MXBeanInteropTest1.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/MXBeanInteropTest1.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Test all MXBeans available by default on the platform * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanInteropTest1 */
--- a/jdk/test/javax/management/mxbean/MXBeanInteropTest2.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/MXBeanInteropTest2.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Checks access to test MXBean * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @compile Basic.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanInteropTest2
--- a/jdk/test/javax/management/mxbean/MXBeanNotifTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/MXBeanNotifTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Checks MXBean proper registration both as its implementation class and interface * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @compile Basic.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanNotifTest -numOfNotifications 239 -timeForNotificationInSeconds 4
--- a/jdk/test/javax/management/mxbean/MXBeanTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/MXBeanTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary General MXBean test. * @author Eamonn McManus * @author Jaroslav Bachorik - * @modules java.management + * @modules java.management.rmi * @run clean MXBeanTest MerlinMXBean TigerMXBean * @run build MXBeanTest MerlinMXBean TigerMXBean * @run main MXBeanTest
--- a/jdk/test/javax/management/mxbean/MXBeanWeirdParamTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/mxbean/MXBeanWeirdParamTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Checks that a serialized instance is not transmitted from an MXBean. * All the communication should be done via Open Types * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @compile Basic.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanWeirdParamTest
--- a/jdk/test/javax/management/query/SupportedQueryTypesTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/query/SupportedQueryTypesTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Tests most of the existing query types. * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @compile TestQuery.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD SupportedQueryTypesTest -mbeanClassName TestQuery */
--- a/jdk/test/javax/management/remote/mandatory/connection/AddressableTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/AddressableTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 6238815 * @summary test the new interface Addressable * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean AddressableTest * @run build AddressableTest * @run main AddressableTest
--- a/jdk/test/javax/management/remote/mandatory/connection/BrokenConnectionTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/BrokenConnectionTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests behaviour when connections break * @author Eamonn McManus * @key intermittent - * @modules java.management + * @modules java.management.rmi * @run clean BrokenConnectionTest * @run build BrokenConnectionTest * @run main BrokenConnectionTest
--- a/jdk/test/javax/management/remote/mandatory/connection/CloseableTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/CloseableTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -28,7 +28,7 @@ * the method "void close() throws IOException;" extend * or implement the java.io.Closeable interface. * @author Luis-Miguel Alventosa - * @modules java.management + * @modules java.management.rmi * @run clean CloseableTest * @run build CloseableTest * @run main CloseableTest
--- a/jdk/test/javax/management/remote/mandatory/connection/ConnectionListenerNullTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/ConnectionListenerNullTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4943248 * @summary Tests that NullPointerException is thrown when listener is null. * @author Daniel Fuchs - * @modules java.management + * @modules java.management.rmi * @run clean ConnectionListenerNullTest * @run build ConnectionListenerNullTest * @run main ConnectionListenerNullTest
--- a/jdk/test/javax/management/remote/mandatory/connection/ConnectionTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/ConnectionTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4865397 * @summary Tests remote JMX connections * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean ConnectionTest * @run build ConnectionTest * @run main ConnectionTest
--- a/jdk/test/javax/management/remote/mandatory/connection/DaemonRMIExporterTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/DaemonRMIExporterTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -28,7 +28,7 @@ * @summary test the connector server option that causes it not to prevent the * VM from exiting * @author Shanliang JIANG, Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run main/othervm DaemonRMIExporterTest */ import java.util.Arrays;
--- a/jdk/test/javax/management/remote/mandatory/connection/GetConnectionTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/GetConnectionTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4951414 * @summary Try to get an IOException. * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean GetConnectionTest * @run build GetConnectionTest * @run main GetConnectionTest
--- a/jdk/test/javax/management/remote/mandatory/connection/IIOPURLTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/IIOPURLTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4886799 * @summary Check that IIOP URLs have /ior/ in the path * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean IIOPURLTest * @run build IIOPURLTest * @run main IIOPURLTest
--- a/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,8 @@ * @bug 4886838 4886830 8025204 * @summary Tests that idle timeouts happen at appropriate times * @author Eamonn McManus - * @modules java.management/com.sun.jmx.remote.util + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.util * @run clean IdleTimeoutTest * @run build IdleTimeoutTest * @run main IdleTimeoutTest
--- a/jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -45,7 +45,7 @@ * @bug 6697180 * @summary test on a client notification deadlock. * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean MultiThreadDeadLockTest * @run build MultiThreadDeadLockTest * @run main MultiThreadDeadLockTest
--- a/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -29,7 +29,7 @@ * thrown when constructor is invoked with null class loader as * an argument. * @author Amit Sapre - * @modules java.management/javax.management.remote.rmi:open + * @modules java.management.rmi/javax.management.remote.rmi:open * @run clean ObjectInputStreamWithLoaderNullCheckTest * @run build ObjectInputStreamWithLoaderNullCheckTest * @run main ObjectInputStreamWithLoaderNullCheckTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -42,7 +42,7 @@ * @bug 6566891 * @summary Check no memory leak on RMIConnector's rmbscMap * @author Shanliang JIANG - * @modules java.management/javax.management.remote.rmi:open + * @modules java.management.rmi/javax.management.remote.rmi:open * @run clean RMIConnectorInternalMapTest * @run build RMIConnectorInternalMapTest * @run main RMIConnectorInternalMapTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -38,7 +38,7 @@ * @bug 6566891 * @summary Check no memory leak on RMIConnector's nullSubjectConn * @author Shanliang JIANG - * @modules java.management/javax.management.remote.rmi:open + * @modules java.management.rmi/javax.management.remote.rmi:open * @run clean RMIConnectorNullSubjectConnTest * @run build RMIConnectorNullSubjectConnTest * @run main RMIConnectorNullSubjectConnTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @summary NPE IN RMIConnector.connect * @bug 6984520 * @library /java/rmi/testlibrary - * @modules java.management + * @modules java.management.rmi * java.rmi/sun.rmi.registry * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport @@ -75,4 +75,3 @@ } } -
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIExitTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIExitTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @bug 4917237 * @summary test that process exit immediately after stop() / close() called * @author Jean Francois Denise - * @modules java.management + * @modules java.management.rmi * @run clean RMIExitTest * @run build RMIExitTest * @run main RMIExitTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMISerializeTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMISerializeTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @summary Tests to serialize RMIConnector * @bug 5032052 * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean RMISerializeTest * @run build RMISerializeTest * @run main RMISerializeTest
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/ConnectorStopDeadlockTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connectorServer/ConnectorStopDeadlockTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 6475157 * @summary Tests deadlock in simultaneous connection and connector-server close * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi */ /* This test is somewhat dependent on implementation details. If it suddenly
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/JNDIFailureTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connectorServer/JNDIFailureTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests that JNDI bind failure doesn't leave an orphan RMI * Connector Server object * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean JNDIFailureTest * @run build JNDIFailureTest * @run main JNDIFailureTest
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/MBSFPreStartPostStartTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connectorServer/MBSFPreStartPostStartTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Test that setting an MBeanServerForwarder on an already * started RMI connector server has the expected behavior. * @author Luis-Miguel Alventosa - * @modules java.management + * @modules java.management.rmi * @run clean MBSFPreStartPostStartTest * @run build MBSFPreStartPostStartTest * @run main MBSFPreStartPostStartTest
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 5016705 * @summary Tests the use of the RMIExporter class. * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.internal + * @modules java.management.rmi/com.sun.jmx.remote.internal.rmi * @run clean RMIExporterTest * @run build RMIExporterTest * @run main RMIExporterTest @@ -46,7 +46,7 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; -import com.sun.jmx.remote.internal.RMIExporter; +import com.sun.jmx.remote.internal.rmi.RMIExporter; public class RMIExporterTest {
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,8 @@ * @summary Tests that IllegalArgumentException is thrown when * MBeanServerForwrder is null. * @author Daniel Fuchs - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean SetMBeanServerForwarder * @run build SetMBeanServerForwarder * @run main SetMBeanServerForwarder
--- a/jdk/test/javax/management/remote/mandatory/loading/DeserializeEncodedURLTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/loading/DeserializeEncodedURLTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4924683 * @summary Check RMI/JRMP stubs can be deserialized using user's loader * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean DeserializeEncodedURLTest SingleClassLoader * @run build DeserializeEncodedURLTest SingleClassLoader * @run main DeserializeEncodedURLTest
--- a/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4915825 4921009 4934965 4977469 8019584 * @summary Tests behavior when client or server gets object of unknown class * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean MissingClassTest SingleClassLoader * @run build MissingClassTest SingleClassLoader * @run main MissingClassTest
--- a/jdk/test/javax/management/remote/mandatory/loading/RMIDownloadTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/loading/RMIDownloadTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 5021246 * @summary Check that class downloading is supported by RMI connector * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run main RMIDownloadTest receive without * @run main RMIDownloadTest send without * @run main RMIDownloadTest receive with
--- a/jdk/test/javax/management/remote/mandatory/loading/TargetMBeanTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/loading/TargetMBeanTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4910428 * @summary Tests target MBean class loader used before JSR 160 loader * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * @run clean TargetMBeanTest * @run build TargetMBeanTest * @run main TargetMBeanTest
--- a/jdk/test/javax/management/remote/mandatory/notif/ConcurrentModificationTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/ConcurrentModificationTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 7120365 * @summary test on Concurrent Modification * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run main ConcurrentModificationTest */
--- a/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -25,7 +25,7 @@ * @test * @bug 6957378 * @summary Test that a listener can be removed remotely from an MBean that no longer exists. - * @modules java.management/javax.management.remote.rmi:open + * @modules java.management.rmi/javax.management.remote.rmi:open * java.management/com.sun.jmx.remote.internal:+open * @author Eamonn McManus * @run main/othervm -XX:+UsePerfData DeadListenerTest
--- a/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/EmptyDomainNotificationTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Check that the expected notification is received by the JMX * client even when the domain in the ObjectName is not specified * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean EmptyDomainNotificationTest * @run build EmptyDomainNotificationTest * @run main EmptyDomainNotificationTest
--- a/jdk/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/ListenerScaleTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 6338874 * @summary Check that notification dispatch is not linear in number of MBeans. * @author Eamonn McManus - * @modules java.management + * @modules java.management.rmi * * @library /lib/testlibrary * @run build jdk.testlibrary.* ListenerScaleTest
--- a/jdk/test/javax/management/remote/mandatory/notif/NotSerializableNotifTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/NotSerializableNotifTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @summary Tests to send a not serializable notification. * @bug 5022196 8132003 * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean NotSerializableNotifTest * @run build NotSerializableNotifTest * @run main NotSerializableNotifTest
--- a/jdk/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 6199899 * @summary Tests reconnection done by a fetching notif thread. * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean NotifReconnectDeadlockTest * @run build NotifReconnectDeadlockTest * @run main NotifReconnectDeadlockTest
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,8 @@ * @bug 5106721 * @summary Check the NotificationAccessController methods are properly called. * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean NotificationAccessControllerTest * @run build NotificationAccessControllerTest * @run main NotificationAccessControllerTest
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferCreationTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 4934236 * @summary Tests that NotificationBuffer is created when used. * @author jfd@... - * @modules java.management + * @modules java.management.rmi * @run clean NotificationBufferCreationTest NotificationSender * @run build NotificationBufferCreationTest * @run main NotificationBufferCreationTest
--- a/jdk/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/NotificationEmissionTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -28,7 +28,7 @@ * installed. Test the property "jmx.remote.x.check.notification.emission". * @author Luis-Miguel Alventosa * @key intermittent - * @modules java.management + * @modules java.management.rmi * @run clean NotificationEmissionTest * @run build NotificationEmissionTest * @run main NotificationEmissionTest 1
--- a/jdk/test/javax/management/remote/mandatory/notif/RMINotifTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/RMINotifTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests to receive notifications for opened and closed connections ions * @author sjiang - * @modules java.management + * @modules java.management.rmi * @run clean RMINotifTest * @run build RMINotifTest * @run main RMINotifTest
--- a/jdk/test/javax/management/remote/mandatory/notif/ServerNotifs.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/ServerNotifs.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests the reception of the notifications for opened and closed * connections * @author sjiang - * @modules java.management + * @modules java.management.rmi * @run clean ServerNotifs * @run build ServerNotifs * @run main ServerNotifs
--- a/jdk/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/notif/UnexpectedNotifTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests whether a listener receives notifs emitted before the * listener is registered. * @author Shanliang JIANG - * @modules java.management + * @modules java.management.rmi * @run clean UnexpectedNotifTest * @run build UnexpectedNotifTest * @run main UnexpectedNotifTest
--- a/jdk/test/javax/management/remote/mandatory/passwordAccessFile/NonJMXPrincipalsTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/passwordAccessFile/NonJMXPrincipalsTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests that MBeanServerFileAccessController supports * principals other than JMXPrincipal. * @author Luis-Miguel Alventosa - * @modules java.management + * @modules java.management.rmi * @run clean NonJMXPrincipalsTest SimpleStandard SimpleStandardMBean * @run build NonJMXPrincipalsTest SimpleStandard SimpleStandardMBean * @run main NonJMXPrincipalsTest
--- a/jdk/test/javax/management/remote/mandatory/passwordAccessFile/PasswordAccessFileTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/passwordAccessFile/PasswordAccessFileTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,7 @@ * @summary Tests the use of the "jmx.remote.x.password.file" and * "jmx.remote.x.access.file" environment map properties. * @author Luis-Miguel Alventosa - * @modules java.management + * @modules java.management.rmi * @run clean PasswordAccessFileTest SimpleStandard SimpleStandardMBean * @run build PasswordAccessFileTest SimpleStandard SimpleStandardMBean * @run main PasswordAccessFileTest
--- a/jdk/test/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/passwordAuthenticator/RMIAltAuthTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,8 @@ * @bug 5016508 * @summary Supplies an alternative JAAS configuration for authenticating RMI clients * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean RMIAltAuthTest * @run build RMIAltAuthTest SimpleStandard SimpleStandardMBean * @run main RMIAltAuthTest
--- a/jdk/test/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/passwordAuthenticator/RMIPasswdAuthTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,8 @@ * @bug 5016508 * @summary Tests the default JAAS configuration for authenticating RMI clients * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean RMIPasswdAuthTest * @run build RMIPasswdAuthTest SimpleStandard SimpleStandardMBean * @run main RMIPasswdAuthTest
--- a/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -24,7 +24,7 @@ /* * @test ProviderTest.java * @summary Tests jar services provider are called - * @modules java.management + * @modules java.management.rmi * @run clean ProviderTest provider.JMXConnectorProviderImpl provider.JMXConnectorServerProviderImpl * @run build ProviderTest provider.JMXConnectorProviderImpl provider.JMXConnectorServerProviderImpl * @run main ProviderTest
--- a/jdk/test/javax/management/remote/mandatory/serverError/JMXServerErrorTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/serverError/JMXServerErrorTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,8 @@ * @bug 4871761 * @summary Tests that JMXServiceErrorException is correctly emitted. * @author Daniel Fuchs - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean JMXServerErrorTest * @run build JMXServerErrorTest * @run main JMXServerErrorTest
--- a/jdk/test/javax/management/remote/mandatory/socketFactories/RMISocketFactoriesTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/socketFactories/RMISocketFactoriesTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 7654321 * @summary Tests the use of the custom RMI socket factories. * @author Luis-Miguel Alventosa - * @modules java.management + * @modules java.management.rmi * @run clean RMISocketFactoriesTest * @run build RMISocketFactoriesTest RMIClientFactory RMIServerFactory * @run main RMISocketFactoriesTest test_server_factory
--- a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,8 @@ * @summary Tests the use of the subject delegation feature in the * RMI connector * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean SubjectDelegation1Test SimpleStandard SimpleStandardMBean * @run build SubjectDelegation1Test SimpleStandard SimpleStandardMBean * @run main SubjectDelegation1Test policy11 ok
--- a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java Thu Feb 02 16:50:46 2017 +0000 @@ -27,7 +27,8 @@ * @summary Tests the use of the subject delegation feature on the authenticated * principals within the RMI connector server's creator codebase. * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean SubjectDelegation2Test SimpleStandard SimpleStandardMBean * @run build SubjectDelegation2Test SimpleStandard SimpleStandardMBean * @run main SubjectDelegation2Test policy21 ok
--- a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java Thu Feb 02 16:50:46 2017 +0000 @@ -28,7 +28,8 @@ * principals within the RMI connector server's creator codebase with * subject delegation. * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.security + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security * @run clean SubjectDelegation3Test SimpleStandard SimpleStandardMBean * @run build SubjectDelegation3Test SimpleStandard SimpleStandardMBean * @run main SubjectDelegation3Test policy31 ok
--- a/jdk/test/javax/management/remote/mandatory/util/MapNullValuesTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/remote/mandatory/util/MapNullValuesTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -31,7 +31,8 @@ * Check also that null values for keys are not allowed in * the maps passed to the JMXConnector[Server] factories. * @author Luis-Miguel Alventosa - * @modules java.management/com.sun.jmx.remote.util + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.util * @run clean MapNullValuesTest * @run build MapNullValuesTest * @run main MapNullValuesTest
--- a/jdk/test/javax/management/security/AuthorizationTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/security/AuthorizationTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Checks various authentication behavior from remote jmx client * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @compile Simple.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials
--- a/jdk/test/javax/management/security/SecurityTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/javax/management/security/SecurityTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -26,7 +26,7 @@ * @bug 8058865 * @summary Checks various secure ways of connecting from remote jmx client * @author Olivier Lagneau - * @modules java.management + * @modules java.management.rmi * @library /lib/testlibrary * @compile MBS_Light.java ServerDelegate.java TestSampleLoginModule.java * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=SQE_username -Dpassword=SQE_password SecurityTest -server -mapType x.password.file -client -mapType credentials
--- a/jdk/test/sun/management/jmxremote/bootstrap/TestManager.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/sun/management/jmxremote/bootstrap/TestManager.java Thu Feb 02 16:50:46 2017 +0000 @@ -57,7 +57,7 @@ try { VirtualMachine.attach(pid).startLocalManagementAgent(); } catch (Exception x) { - throw new IOException(x.getMessage()); + throw new IOException(x.getMessage(), x); } }
--- a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java Thu Feb 02 12:28:23 2017 +0100 +++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java Thu Feb 02 16:50:46 2017 +0000 @@ -147,7 +147,7 @@ @Test public void testListWithLimitMods1() throws Exception { OutputAnalyzer output - = executeTestJava("--limit-modules", "java.management", "--list-modules") + = executeTestJava("--limit-modules", "java.management.rmi", "--list-modules") .outputTo(System.out) .errorTo(System.out); output.shouldContain("java.rmi");