8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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("\"");
}
}
*/

View file

@ -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>();
}

View file

@ -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();
}
}

View file

@ -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);
}
}
}
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -0,0 +1,329 @@
<html>
<head>
<title>RMI connector</title>
<!--
Copyright (c) 2002, 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.
-->
</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 id="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 id="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.
{@extLink rmi_guide Java RMI Guide} explains this in more detail.</p>
@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>

View file

@ -0,0 +1,77 @@
/*
* 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 {@linkplain javax.management.remote.rmi RMI connector}
* for the Java Management Extensions (JMX) Remote API.
*
* <dl>
* <dt class="simpleTagLabel" style="font-family:'DejaVu Sans', Arial, Helvetica, sans serif">Providers:</dt>
* <dd>This module provides the
* {@link javax.management.remote.JMXConnectorProvider} service,
* which creates JMX connector clients using the RMI protocol.
* Instances of {@code JMXConnector} can be obtained via the
* {@link javax.management.remote.JMXConnectorFactory#newJMXConnector
* JMXConnectorFactory.newJMXConnector} factory method.
* It also provides the {@link javax.management.remote.JMXConnectorServerProvider} service,
* which creates JMX connector servers using the RMI protocol.
* Instances of {@code JMXConnectorServer} can be obtained via the
* {@link javax.management.remote.JMXConnectorServerFactory#newJMXConnectorServer
* JMXConnectorServerFactory.newJMXConnectorServer} factory method.
* </dd>
* </dl>
*
* @provides javax.management.remote.JMXConnectorProvider
* @provides javax.management.remote.JMXConnectorServerProvider
*
* @moduleGraph
* @since 9
*/
module java.management.rmi {
requires java.naming;
requires transitive java.management;
requires transitive java.rmi;
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;
}