RMI Adaptors and RMI Connectors / RMI 어댑터와 RMI 커넥터

Simone Bordet

(번역)전 준식(locus@nextel.co.kr)

Jin Woo, Min (Korean Translation)

고친 과정
고침 $Revision: 1.2 $$Date: 2002/09/27 09:35:39 $

소개

RMI 어댑터는 클라이언트가 원격 JVM에서 RMI를 사용하여 JMX 에이전트에 접속할 수 있게 한다.

MX4J는 두가지 RMI 어댑터가 있다 :

  • JRMP Adaptor (class mx4j.adaptor.rmi.jrmp.JRMPAdaptor)
  • IIOP Adaptor (class mx4j.adaptor.rmi.iiop.IIOPAdaptor)

JRMP 어댑터는 보안 연결을 위해서 SSL을 지원하며, 두개의 어댑터는 모두 원격 notification 리스너와 필터를 제공한다.

RMI가 프로토콜이 아니고 여기서의 의도는 "자바를 사용한 원격 메소드 호출"로서 사용한 것에 유의하라. 내부 프로토콜은 어떤 것이나 될 수 있다. MX4J의 RMI 어댑터는 실제로 두가지 프로토콜을 지원한다. JRMP, IIOP

JRMP는 Java Remote Method Protocol이며 RMI의 기본 프로토콜 이다. IIOP는 Internet Inter ORB Protocol이며, CORBA의 기본 프로토콜이다.

Java에서 원격 메소드 호출(Remote Method Invocation)은 JRMP나 IIOP를 하부 프로토콜로 사용할 수 있고, 원격 호출 프로세스는 "RMI"나 "RMI over IIOP"로 알려져 있다. "RMI"는 "RMI over JRMP"의 단축말이다.

JRMP 어댑터

JRMP 어댑터는 원격 JVM에서 호출을 RMI over JRM로 JMX 에이전트에 노출한다. 이는 rmiregistry나 NamingService MBean(MX4J 문서를 참고)와 같은 naming service가 시작되기 전에 실행되어 있어야 한고, naming 서비스를 찾을 수 있도록 정확한 위치(클래스 패스내에 jndi.properties)가 필요하다.

예 3.3. JRMP 어댑터를 배치하기

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

      // Registers the JRMP adaptor in JNDI and starts it
      mbean.start();
   }
}
		
			

클라이언트를 보면, JRMP 어댑터와 어떻게 interact 하는지를 알 수 있다.
필요한 것은 모든 것이 RMI Connector와 naming 서비스를 찾을수 있는 적절한 위치이다.
여기에 2가지 RMI connector가 있다.

  • JRMP Connector (class mx4j.connector.rmi.jrmp.JRMPConnector)
  • IIOP Connector (class mx4j.connector.rmi.iiop.IIOPConnector)
각 connector는 상응하는 adaptor와 연결할 수 있다.
naming 서비스를 찾기 위해서는 jndi.properties파일이 필요하거나, RMIConnector에 전달될 적절한 naming properties를 포함한 Hashtable 이다. 아래 코드를 보면 어댑터에 연결하기 위해 필요한 것을 알 수 있다.

예 3.4. JRMP 어댑처를 배치하기

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

클라이언트에서 RMIConnector 클래스를 사용하는 것은 매우 중요하고, JNDI에서 어댑터를 직접 찾아서는 안된다.
RMIConnector는 하부 전송 프로토콜(JRMP or IIOP)이 무엇인지를 이해할 수 있는 트릭을 사용하기 때문이다.
이는 명확히 RMIConnector 클래스를 사용하는 것을 간단하게 한다.

SSL을 사용한 JRMP 어댑터

JRMP 어댑터는 안전하게 RMI 연결을 할 수 있도록 SSL을 사용하도록 설정할 수 있다. RMI or JRMP를 SSL과 같이 사용하기 위해서는 커스텀 RMI 소켓 팩토리를 사용하여야 한며, 서버가 개인키와 해당되는 X509로 wrapping된 self-signed 인증서가 보관된 keystore 를 설정하여야 한다. 인증서는 클라이언트와 연결되었을때 클라이언트에 전송되며, 클라이언트은 클라이언트 JVM네의 truststore에서 서버인증서를 신뢰하여야 한다. 서버가 보낸 truststore에 있는 인증서와 일치하면, SSL 연결은 끝나고, 데이터 교환이 시작된다.

JRMP 어댑터 over SSL을 설정하기 위해서 필요한 operation은 다음과 같다 :

  • JDK keytool을 사용하여 keystore파일을 생성한다.
  • JDK keytool을 사용하여 truststore파일에 X509 인증서를 export한다
  • 방금 생성한 keystore에 대한 정보와 함께 SSL ServerSocket factory MBean을 deploy한다.
  • 방금 deploy한 SSL ServerSocket Factory MBean에 대한 정보를 JRMP 어댑터 MBean에 전달하여 deploy한다.
  • JRMP 어댑터를 시작한다.

클라이언트에서 설정해야 할 operation들은 다음과 같다 :

  • 서버 인증서를 담고 있는 trust.store 생성 파일을 클라이언트에 복사한다.
  • 다음 시스템 프로퍼티와 같이 java 인터프리터를 호출한다. javax.net.ssl.trustStore=<path>/trust.store

다음 코드는 서버에 대한 것이다. 클라이언트는 전의 것과 완전히 동일하다.

예 3.5. SSL을 사용한 JRMP 어댑터 배치

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

IIOP 어댑터

IIOP 어댑터는 원격 JVM에서 RMI over IIOP를 통해서 JMX 에이전트를 호출하는 데 표출된다. 시작되기전에 tnameserv와 같은 naming service가 시작되어 있어야만 하며, naming service를 찾기위한 적절한 지시(클래스패스내의 jndi.properties와 같이)가 있어야 한다. 다음에서 서버내에서 IIOP 어댑터를 생성하고, 등록하여 시작하는 코드 예제를 볼 수 있다.

예 3.6. IIOP 어댑터를 배치하기

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

단지 JRMPConnector를 IIOPConnector로 바꾸기만 하고 클라이언트에게 정확하게 네이밍 서비스를 찾을 수 있도록 지시하면 (jndi.properties 파일의 경로와 같이, 이런 경우 CosNaming 값을 정한다.) 클라이언트는 이전 것과 완전히 동일하다.