JSR 160 compliance requires implementation of a JMXConnector and JMXConnectorServer that
use Java's Remote Method Invocation (RMI) to communicate.
The RMI connector and connector server are meant to work both over JRMP (Java Remote
Method Protocol, RMI's native protocol) and over IIOP (Internet Inter ORB Protocol, CORBA's
native protocol), and MX4J implements both fully.
Java's RMI works so that the RMI client needs to have a
stub object.
A normal java method call on the stub is routed to the network and ends up on the RMI server
making possible to perform remote calls as if they were standard local calls.
The stub takes care the details of invoking the server side such as arguments and return
value marshalling, exception throwing and so on.
The stub class is normally present in the client's
classpath (since the stub is part of the JSR 160 classes), but the stub object is normally
downloaded from a naming server such as the
rmiregistry.
The RMI client only needs to know the naming path under which the stub object has been bound to
by the RMI server.
A JSR 160 RMIConnector needs to be able to retrieve the stub object in order to contact
a remote JSR 160 RMIConnectorServer.
JSR 160 gives two possibilities to retrieve the RMI stub object to be able to contact the
RMIConnectorServer.
The first way to contact an RMIConnectorServer is make the stub object part of
the RMIConnectorServer's address, represented by a JMXServiceURL.
The JSR 160 specification refers to this possibility as the "encoded form".
In case of JRMP, the stub is serialized and its bytes are Base64 encoded and attached to
the JMXServiceURL, so that passing the JMXServiceURL to clients, they have all information
needed to contact the server side (no naming server is needed).
The JMXServiceURL path, in this case, starts with
/stub/.
In case of IIOP, the IOR is attached to the JMXServiceURL (and again no naming server is
needed).
The JMXServiceURL path, in this case, starts with
/ior/.
Simply passing an encoded form JMXServiceURL to a JMXConnector is enough to allow it
to contact the corrispondent JMXConnectorServer: the JMXConnector will take care of
decoding the stub.
Example 3.13. Examples of encoded form JMXServiceURLs
// JRMP encoded form service:jmx:rmi://localhost/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LnJlbW90ZS5ybWkuUk1JU2VydmVySW1wbF9TdHViAAAAAAAAAAICAAB4cgAaamF2YS5ybWkuc2VydmVyLlJlbW90ZVN0dWLp/tzJi+FlGgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc5AAtVbmljYXN0UmVmMgAADjE2LjE5Mi4xMjAuMTI5AAANcQAAAAAAAAAIAOgIQgAAAPlXjcJugAEAeA== // IIOP encoded form service:jmx:iiop://localhost/ior/IOR:000000000000003b524d493a6a617661782e6d616e6167656d656e742e72656d6f74652e726d692e524d495365727665723a303030303030303030303030303030300000000000010000000000000068000102000000000f31362e3139322e3132302e31323900000d93000000000019afabcb0000000002578f08b80000000800000000000000000a0000000000000100000001000000200000000000010001000000020501000100010020000101090000000100010100
The second way to contact an RMIConnectorServer is to specify a path in the JMXServiceURL
that indicates the location of a naming server and the JNDI path where the stub object
can be found.
The JSR 160 specification refers to this possibility as the "JNDI form".
In this case the JMXServiceURL path starts with
/jndi/.
Working with JNDI requires to specify some information about the naming server and the configuration of JNDI itself. These information can be passed to the RMIConnector in several ways; these ways are very similar to the the ways JNDI requires to specify parameters and present no surprise to JNDI users.
For example, the URL 'rmi://namingHost:1099/jndiPath' (not to be confused with a JMXServiceURL) says that
a naming server on the host 'namingHost' is listening on port 1099, that the naming server is an
rmiregistry (indicated by the 'rmi' scheme) and that under the '/jndiPath' path something has been registered.
Similarly, the URL 'iiop://namingHost:900/jndiPath' says that
a naming server on the host 'namingHost' is listening on port 900, that the naming server is a
COS naming service (indicated by the 'iiop' scheme) and that under the '/jndiPath' path something
has been registered.
It is straightforward then to specify a JMXServiceURL that uses the JNDI URL form:
Example 3.14. Examples of JNDI URL form JMXServiceURLs
// JNDI URL form for JRMP service:jmx:rmi://rmiHost/jndi/rmi://namingHost:1099/jndiPath // JNDI URL form for IIOP service:jmx:iiop://rmiHost/jndi/iiop://namingHost:900/jndiPath
Alternatively, JNDI properties can be specified in the usual ways they are specified for JNDI,
namely specifying system properties, a 'jndi.properties' file in the classpath or via an environment Map
passed to the
JMXConnector.connect(Map environment)
method or to the
JMXConnectorFactory.connect(JMXServiceURL url, Map environment)
method.
Since JNDI properties are specified separately, the JMXServiceURL path can be specified
using the JNDI short form, where only the JNDI path is specified in the JMXServiceURL:
Example 3.15. Examples of JNDI short form JMXServiceURLs
// JNDI short form for JRMP service:jmx:rmi://rmiHost/jndi/jndiPath // JNDI short form for IIOP service:jmx:iiop://rmiHost/jndi/jndiPath // Code example that uses the JNDI short form specifying JNDI properties via environment Map // The JNDI environment Map environment = new HashMap(); environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); environment.put(Context.PROVIDER_URL, "rmi://namingHost:1099"); // The JNDI short form JMXServiceURL JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://rmiHost/jndi/jndiPath"); // Connect to the server side JMXConnector connector = JMXConnectorFactory.connect(url, environment);
When working with IIOP, there may be the need to pass some information in order to
correctly create the ORB.
In plain Java code, these properties are passed via system properties or via environment Map.
Similarly, when using the JSR 160 API, ORB properties can be specified as system properties
or via the environment Map
passed to the
JMXConnector.connect(Map environment)
method or to the
JMXConnectorFactory.connect(JMXServiceURL url, Map environment)
method.
JSR 160 specifies two constants to specify the
java.rmi.server.RMIClientSocketFactory
and
java.rmi.server.RMIServerSocketFactory instances that the
RMIConnectorServer should use to export itself to the RMI runtime.
These constants are
javax.management.remote.rmi.RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE and
javax.management.remote.rmi.RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE.
The MX4J implementation provides already an implementation of the
java.rmi.server.RMIClientSocketFactory
and
java.rmi.server.RMIServerSocketFactory interfaces that can be used to
encrypt the communication between the RMIConnector and the RMIConnectorServer using SSL, namely the
mx4j.tools.remote.rmi.SSLRMIClientSocketFactory and
mx4j.tools.remote.rmi.SSLRMIServerSocketFactory.
These classes only work with JDK 1.4 or superior.
Example 3.16. How to specify the RMI socket factories
SSLContext ssl = ...; RMIServerSocketFactory ssf = new SSLRMIServerSocketFactory(ssl); RMIClientSocketFactory csf = new SSLRMIClientSocketFactory(); Map env = new HashMap(); env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); MBeanServer server = ...; JMXServiceURL url = new JMXServiceURL("rmi", "localhost", 0); cntorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, env, server); cntorServer.start();