Revision History | |
---|---|
Revision $Revision: 1.5 $ | $Date: 2002/10/14 20:46:19 $ |
RMI adaptors allow clients to connect to a JMX Agent from a remote JVM using RMI.
MX4J's features two RMI adaptors:
The JRMP Adaptor supports also SSL for secure connections, and both the adaptors support remote notification listeners and filters.
Note that RMI is not a protocol, and here must be intended as "Remote Method Invocation using Java". The underlying protocol can be anyone, and in fact two protocols are supported by the MX4J's RMI adaptors: JRMP and IIOP.
JRMP is the Java Remote Method Protocol, and it's the RMI default protocol.
IIOP is the Internet Inter ORB Protocol, and it's the CORBA default protocol.
Remote Method Invocation in Java can have JRMP or IIOP as underlying protocols, and the remote
invocation process is usually referred to, respectively, as "RMI" and "RMI over IIOP".
"RMI" is a short for "RMI over JRMP".
The JRMP adaptor exposes the JMX Agent to RMI over JRMP calls from remote JVMs.
It needs a naming service such as the rmiregistry or the NamingService MBean (see MX4J documentation)
to be active before being started, and proper directives to find the naming service (such as a jndi.properties file
in the classpath).
Below you can see the snippet of the code needed in the server
to create, register and start the JRMP adaptor.
Example 3.3. Deploying the JRMP adaptor
public class Server { public static void main(String[] args) throws Exception { // Create a MBeanServer MBeanServer server = MBeanServerFactory.createMBeanServer(); // Create and start the naming service ObjectName naming = new ObjectName("Naming:type=rmiregistry"); server.createMBean("mx4j.tools.naming.NamingService", naming, null); server.invoke(naming, "start", null, null); // Create the JRMP adaptor ObjectName adaptor = new ObjectName("Adaptor:protocol=JRMP"); m_server.createMBean("mx4j.adaptor.rmi.jrmp.JRMPAdaptor", adaptor, null); JRMPAdaptorMBean mbean = (JRMPAdaptorMBean)StandardMBeanProxy.create(JRMPAdaptorMBean.class, server, adaptor); // Set the JNDI name with which will be registered String jndiName = "jrmp"; mbean.setJNDIName(jndiName); /* // Optionally, you can specify the JNDI properties, // instead of having in the classpath a jndi.properties file mbean.putJNDIProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); mbean.putJNDIProperty(Context.PROVIDER_URL, "rmi://localhost:1099"); */ // Registers the JRMP adaptor in JNDI and starts it mbean.start(); } }
Let's look now at the client, and how it can interact with the JRMP Adaptor.
All you need is the corrispondent RMI connector for the registered RMI adaptor,
and proper directives to find the naming service.
There are 2 RMI connectors, namely:
Example 3.4. Using the JRMP connector
public class Client { public static void main(String[] args) throws Exception { // Create a JRMPConnector JRMPConnector connector = new JRMPConnector(); // Pass in the adaptor's JNDI name, no properties String jndiName = "jrmp"; connector.connect(jndiName, null); // Use the connector directly to retrieve some information // about host name and IP address String remoteHostName = connector.getRemoteHostName(); String remoteHostAddress = connector.getRemoteHostAddress(); // Get the remote MBeanServer from the connector // And use it as if it is an MBeanServer RemoteMBeanServer server = connector.getRemoteMBeanServer(); ObjectName objName = new ObjectName("examples:mbean=MyService"); ObjectInstance instance = server.createMBean("examples.mbeans.rmi.MyRemoteServiceObject", objName, null); NotificationListener listener = new NotificationListener() { public void handleNotification(Notification n, Object handback) { // Do something } }; server.addNotificationListener(objName, listener, null, null); // and so on } }
It is VERY important to use the connectors in the client, and not to try to lookup directly the
adaptor in JNDI.
This because the connectors do some trick to handle the listeners to be invoked remotely by the server.
It is definitely simpler to use the RMIConnector class.
The JRMP adaptor can be setup to use SSL to allow secure RMI connections.
Using SSL with RMI over JRMP requires the use of custom RMI socket factories, and requires the server to
setup a keystore where a private key and the corresponding public key wrapped in a X509 self-signed
certificate are stored.
The certificate is then sent to the client when the connection is established, and the client must trust
the server's certificate by looking it up in a truststore (in the client JVM). If the certificate found
in the truststore matches the one sent by the server, the SSL connection is complete and data exchange may
begin.
The operations needed to setup the JRMP adaptor over SSL are the following:
The operations needed to setup the client are the following:
Below you can find the code snippets for the server; the client is exactly equal as before.
Example 3.5. Deploying the JRMP adaptor over SSL
// Generate the keystore keytool -genkey -v -keystore key.store -storepass storepwd -keypass keypwd -dname "CN=Simone Bordet, OU=Project Administrator, O=MX4J, L=Torino, S=TO, C=IT" -validity 365 // Export the X509 certificate keytool -export -v -storepass storepwd -keystore key.store | keytool -import -v -storepass storepwd -keystore trust.store -noprompt // Deploy the MBeans public class Server { public static void main(String[] args) throws Exception { // Create a MBeanServer MBeanServer server = MBeanServerFactory.createMBeanServer(); // Create the SSL ServerSocket factory ObjectName ssl = new ObjectName("Adaptor:service=SSLServerSocketFactory"); server.createMBean("mx4j.adaptor.ssl.SSLAdaptorServerSocketFactory", ssl, null); SSLAdaptorServerSocketFactoryMBean factory = (SSLAdaptorServerSocketFactoryMBean)StandardMBeanProxy.create(SSLAdaptorServerSocketFactoryMBean.class, server, ssl); factory.setKeyStoreName("key.store"); factory.setKeyStorePassword("storepwd"); factory.setKeyManagerPassword("keypwd"); // Create and start the naming service ObjectName naming = new ObjectName("Naming:type=rmiregistry"); server.createMBean("mx4j.tools.naming.NamingService", naming, null); server.invoke(naming, "start", null, null); // Create the JRMP adaptor ObjectName adaptor = new ObjectName("Adaptor:protocol=JRMP"); m_server.createMBean("mx4j.adaptor.rmi.jrmp.JRMPAdaptor", adaptor, null); JRMPAdaptorMBean mbean = (JRMPAdaptorMBean)StandardMBeanProxy.create(JRMPAdaptorMBean.class, server, adaptor); // Set the JNDI name with which will be registered String jndiName = "jrmp"; mbean.setJNDIName(jndiName); // Set the SSL ServerSocket Factory mbean.setSSLFactory(ssl.toString()); // Register the JRMP adaptor in JNDI and start it mbean.start(); } }
The IIOP adaptor exposes the JMX Agent to RMI over IIOP calls from remote JVMs.
It needs a naming service such as tnameserv
to be active before being started, and proper directives to find the naming service (such as a jndi.properties file
in the classpath). Below you can see the snippet of the code needed in the server
to create, register and start the IIOP adaptor.
Example 3.6. Deploying the IIOP adaptor
public class Server { public static void main(String[] args) throws Exception { // Create a MBeanServer MBeanServer server = MBeanServerFactory.createMBeanServer(); // Create and start tnameserv ObjectName naming = new ObjectName("Naming:type=tnameserv"); server.createMBean("mx4j.tools.naming.CosNamingService", naming, null); server.setAttribute(naming, new Attribute("Delay", new Integer(5000))); server.invoke(naming, "start", null, null); // Create the IIOP adaptor ObjectName adaptor = new ObjectName("Adaptor:protocol=IIOP"); m_server.createMBean("mx4j.adaptor.rmi.iiop.IIOPAdaptor", adaptor, null); IIOPAdaptorMBean mbean = (IIOPAdaptorMBean)StandardMBeanProxy.create(IIOPAdaptorMBean.class, server, adaptor); // Set the JNDI name and properties with which will be registered String jndiName = "jrmp"; mbean.setJNDIName(jndiName); mbean.putJNDIProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"); mbean.putJNDIProperty(Context.PROVIDER_URL, "iiop://localhost:900"); // Register the IIOP adaptor in JNDI and start it mbean.start(); } }
The client is exactly equal as before, just replace JRMPConnector with IIOPConnector and remember to give to the client the proper directives to find the naming service (such a jndi.properties file in the classpath, but this time with the CosNaming values).