mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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("\"");
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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>();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
77
src/java.management.rmi/share/classes/module-info.java
Normal file
77
src/java.management.rmi/share/classes/module-info.java
Normal 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;
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue