내용 목차
본 장에서는 EJB의 상호 운용성 및 RMI/IIOP에 대해서 설명한다.
JEUS는 다른 WAS나 이기종 시스템 간에 원격 EJB 호출을 지원하기 위해 RMI/IIOP 프로토콜을 지원한다. RMI/IIOP는 OMG(http://omg.org)에서 정한 CORBA(Common Object Request Broker Architecture)에 기반한 것이며 EJB 상호 운용성(Interoperability)을 위해서 EJB 스펙에서 정한 표준 방식이다. JEUS 간에 또는 다른 WAS로부터 원격 호출을 지원해야 한다면 RMI/IIOP 상호 운용 기능을 사용할 것을 고려할 수 있다. RMI/IIOP 원격 호출 방식은 다른 WAS나 이기종 시스템을 지원하는 방식 중의 하나이다. 다른 WAS로부터 JEUS의 EJB를 호출하고 트랜잭션을 연동하는(또는 반대로) 다른 방법도 존재하지만 본 장에서는 RMI/IIOP 방식에 대해서만 설명한다.
상호 운용은 JEUS의 EJB를 다른 시스템에서 호출하는 것과 다른 WAS의 EJB를 JEUS에서 호출하는 것 2가지로 나눌 수 있다. 즉, JEUS가 RMI/IIOP 서버, 클라이언트 또는 둘 다 될 수 있다. 모든 경우에 마찬가지로 이를 지원할 수 있는 ORB(Object Request Broker) 런타임이 필요하며 트랜잭션과 보안의 상호 운용 또한 지원해야 한다.
JEUS에는 CORBA Naming Service를 지원하기 위한 COS Naming Server 및 Stub 클래스 없이도 Dynamic Stub을 메모리에서 자동으로 생성해 주는 ORB 런타임을 내장하고 있으며, 트랜잭션의 상호 운용을 위해 OTS(Object Transaction Service) 스펙과 보안 상호 운용을 위해 CSIv2(Common Secure Interoperability version 2) 스펙을 구현하고 있다.
CORBA 및 RMI/IIOP에 대해 이해하려면 다음의 관련 링크를 참조한다.
트랜잭션의 상호 운용은 OTS(Object Transaction Service) 스펙을 기반으로 이루어진다. Object는 트랜잭션에 영향을 받는 CORBA Object를 의미한다.
OTS를 사용하게 될 경우 ORB에 트랜잭션을 처리할 수 있는 Interceptor(일종의 Listener)를 추가하게 된다. 특별히 추가된 Interceptor가 IIOP 프로토콜 헤더의 트랜잭션 관련 부분을 처리한다. 이를 통해서 클라이언트 또는 서버 역할을 하는 JEUS는 다른 원격 시스템(다른 WAS 또는 JEUS) 간의 트랜잭션 전파(Transaction propagation)를 지원한다.
현재 지원하는 OTS의 스펙 버전은 1.2이다.
CSIv2는 상호 운용에 있어 보안을 보장해주기 위한 스펙이다. CSI를 사용하면 앞서의 OTS와 마찬가지로 보안처리가 가능한 Interceptor가 ORB에 추가되며, Interceptor가 보안에 관한 헤더 및 그 밖의 처리를 수행한다.
보안 상호 운용은 EJB Reference의 IOR(Interoperable Object Reference)에 CSI를 위한 보안 정보가 첨부됨으로써 시작된다. Naming Service에 IOR이 등록되면 이를 사용하려는 클라이언트의 ORB와 JEUS MS가 IIOP 프로토콜의 보안 레벨에서 협상(negotiation)을 처리한다. 또한 JEUS MS는 다른 EJB Bean을 호출할 경우 CSI 서비스가 필요하다면 클라이언트로 동작한다.
보안 상호 운용에 대한 자세한 내용은 CORBA의 CSIv2 스펙을 참고한다.
기본적으로 상호 운용은 설정되지 않았기 때문에 이를 사용하려면 반드시 관련된 서버 설정을 해야 한다.
JEUS의 EJB를 RMI/IIOP로 노출시키기 위해서는 MS의 Enable Interop 설정을 활성화해야 하고, deploy되는 EJB에 IIOP export 관련 설정이 있어야 한다. 반대로 JEUS를 RMI/IIOP 클라이언트로만 사용하는 경우에는 해당 MS의 Enable Interop 설정만 활성화하면 된다.
상호 운용과 관련된 사항은 WebAdmin을 사용하여 설정할 수 있다.
MS에서 제공하는 기본적인 JNDI Naming Service 외에 CORBA 객체를 위한 COS Naming Service를 추가할 수 있다. COS Naming Service에는 RMI/IIOP로 노출되는 EJB의 Reference(Stub)가 저장되고 이를 EJB 클라이언트에서 찾아서(lookup) 사용하게 된다.
COS Naming Service는 필요한 시점에 자동으로 시작되며, MS JVM에 구동되어 'BASEPORT + 4(예: 9740)'을 서비스 포트로 사용한다.
'BASEPORT'는 WebAdmin에서 [Servers] 메뉴의 서버 목록에서 서버를 선택한 후 [Resource] > [Listener] 메뉴의 'base' 항목에 설정된 Listener의 'Listen Port'이다.
RMI/IIOP 클라이언트 및 서버에 필요한 상호 운용 기능을 사용하려면 상호 운용성 속성이 활성화되어야 한다. 이 속성이 활성화되어야 ORB가 초기화된다.
상호 운용성 속성을 활성화하려면 WebAdmin의 [Servers] 메뉴를 선택한 후 조회된 서버 목록에서 원하는 서버를 클릭한다. Server 화면의 고급 선택사항에서 'Enable Interop'을 설정한다.
CSIv2 기능을 사용하려면 좀 더 자세한 설정이 필요한데 이는 “5.2.3. CSIv2 보안 상호 운용 설정”을 참고한다.
CSIv2 기능을 수행하기 위해서 2가지 추가적인 보안 환경 파일과 JEUS Security Manager의 정보를 이용한다. 설정할 추가적인 보안 환경 파일은 Keystore과 Truststore 파일이다.
보안 환경 파일 | 설명 |
---|---|
Keystore 파일 | X.509를 위한 Key를 저장하고 Oracle 사에 의해서 공급된 X.509 keystore를 구현한 파일이다. Secure Socket Layer(SSL)가 호출됐을 때 이 파일이 클라이언트에게 보내진다. |
Truststore 파일 | X.509 클라이언트 측 증명 설정 파일이며, 형식은 Keystore와 같다. |
이 파일들의 경로와 필요한 정보는 WebAadmin이나 시스템 프로퍼티를 사용해서 설정할 수 있다.
CSIv2 관련 사항은 Enable Interop의 Interop Ssl Config에 설정한다.
CSIv2 관련 설정은 실행 스크립트의 시스템 프로퍼티를 통해서도 가능하다. 그러나 시스템 프로퍼티보다 WebAdmin 설정이 우선된다는 것을 유념한다.
다음은 이를 위한 실행 스크립트 옵션이다. 다음에 설정한 값은 "–D"를 이용해서 설정된다.
[표 5.1] Keystore와 Truststore 파일에 관련된 JVM –D 파라미터
파라미터 | 설명 |
---|---|
jeus.ssl.keystore | Keystore 파일까지 절대 경로이다. (기본값: DOMAIN_HOME/config/keystore) |
jeus.ssl.keypass | Keystore 파일에 주어진 패스워드값이다. (기본값: jeuskeypass) |
jeus.ssl.truststore | Truststore 파일까지 절대 경로이다. (기본값: DOMAIN_HOME/config/truststore) |
jeus.ssl.trustpass | Truststore 파일에 주어진 패스워드값이다. (기본값: jeustrustpass) |
신뢰하는 노드 사이에서는 호출자의 authentication과 authorization이 불필요할 때도 있다.
jeus.ejb.csi.trusthosts 시스템 프로퍼티에 IP 주소를 설정하면 신뢰하는 노드의 불필요한 보안 점검을 피할 수 있다. JEUS Security Manager는 불특정 접근자에게 anonymous principal을 나타내는 'guest'를 사용한다.
EJB를 RMI/IIOP로 노출시키려면 jeus-ejb-dd.xml에 EJB별로 <export-iiop>를 설정해야 한다. <export-iiop>가 설정되면 EJB Home Reference가 COS Naming Service에 주어진 <export-name>으로 등록된다. 이렇게 등록이 되어야만 외부에서 COS Naming Service를 통해 EJB Reference를 가져와서 사용할 수 있다.
다음은 EJB RMI/IIOP을 설정한 jeus-ejb-dd.xml의 예이다.
[예 5.1] EJB RMI/IIOP 설정 : <<jeus-ejb-dd.xml>>
...
<jeus-bean>
<ejb-name>CalcEJB</ejb-bean>
<export-name>ejb/Calc</export-name>
<export-iiop>
<only-iiop>true</only-iiop>
</export-iiop>
</jeus-bean>
...
다음은 설정 태그에 대한 설명이다.
태그 | 설명 |
---|---|
<only-iiop> | EJB를 RMI와 RMI/IIOP로 각각 노출할지 아니면 RMI/IIOP만 노출할지를 설정한다. 각각 노출한다면 COS Naming Server에는 RMI/IIOP Stub이 등록되고, JEUS Naming Server에는 일반 RMI Stub이 등록된다. |
현재는 EJB Home과 EJB Object Reference만 RMI/IIOP로 노출할 수 있다. EJB 3.0 비즈니스 뷰는 RMI/IIOP로 노출할 수 없다.
RMI/IIOP 클라이언트는 다른 JEUS나 다른 벤더의 WAS 또는 Standalone 클라이언트가 될 수 있다. 본 절에서는 각각 어떤 방식으로 EJB를 사용할 수 있는지 설명한다.
JEUS MS에서 운용되는 애플리케이션에서 JEUS나 다른 벤더의 WAS 위에 있는 RMI/IIOP EJB를 호출하기 위한 방법은 다음과 같다.
먼저, COS Naming Server에서 EJB Home Reference(Stub)를 찾아와야 한다. 직접 찾아오는 경우에는 JNDI API의 corbaname URL을 사용해서 얻어올 수있다.
[예 5.2] corbaname lookup 사용
InitialContext ctx = new InitialContext(); Object obj = ctx.lookup("corbaname:iiop:1.2@192.168.11.22:9740#ejb/Calc"); CalcHome home = (CalcHome)PortableRemoteObject.narrow(obj, CalcHome.class); Calc calcRef = home.create();
URL은 "corbaname:iiop:1.2@<host>:<port>#<name>" 형식으로 <host>와 <port>는 COS Naming Server의 주소이다. 또는 직접 COS Naming Server를 PROVIDER URL로 지정하여 InitialContext를 얻어서 사용할 수도 있다.
다음의 예와 같이 PROVIDER URL을 지정하는 방식은 여러 가지가 있기 때문에 이 중에서 한 가지 방식으로 지정한다.
[예 5.3] PROVIDER URL 사용
Hashtable env = new Hashtable(); env.put(Context.PROVIDER_URL, "iiop://192.168.11.22:9740"); // env.put(Context.PROVIDER_URL, "iiopname://192.168.11.22:9740"); // env.put(Context.PROVIDER_URL, "corbaname:iiop:1.2@192.168.11.22:9740"); // env.put(Context.PROVIDER_URL, "corbaloc:iiop:1.2@192.168.11.22:9740"); InitialContext ctx = new InitialContext(env); Object obj = ctx.lookup("ejb/Calc"); CalcHome home = (CalcHome)PortableRemoteObject.narrow(obj, CalcHome.class); Calc calcRef = home.create();
Dependency Injection을 사용하거나 "java:comp/env/" 형식의 논리적인 JNDI 이름을 사용하는 클라이언트의 경우에는 jeus-web-dd.xml과 같은 애플리케이션 JEUS DD 파일에서 <export-name>을 위의 corbaname URL로 매핑한다.
[예 5.5] RMI/IIOP EJB 매핑 : <<jeus-web-dd.xml>>
<ejb-ref> <jndi-info> <ref-name>ejb/Calc</ref-name> <export-name>corbaname:iiop:1.2@192.168.11.22:9740#ejb/Calc</export-name> </jndi-info> </ejb-ref>
다른 벤더의 WAS에서 운용되는 애플리케이션에서 JEUS의 RMI/IIOP EJB를 호출하기 위한 방법은 “5.3.1. JEUS Managed Server”의 방식과 거의 동일하다.
이 경우 JEUS처럼 별도의 ORB 설정이 필요한지 확인하고, 필요하다면 설정을 해야 한다. 자세한 내용은 해당 제품의 관련 문서를 참고한다.
Standalone 클라이언트는 별도의 ORB 런타임 및 관련된 설정이 되어 있지 않기 때문에, 먼저 기본적으로 필요한 jclient.jar 클라이언트 라이브러리 외에도 JEUS 시스템 라이브러리에 위치한 corba-omgapi.jar와 corba-orb.jar를 클래스 패스에 추가하고 jeus.client.interop=true 시스템 프로퍼티를 추가해야 한다.
EJB Home Reference(Stub)를 얻어오는 방식은 “5.3.1. JEUS Managed Server”와 비슷하다. 단지, JEUS에서 제공하는 JNDI 프로바이더를 추가적으로 지정한다.
[예 5.6] Standalone 클라이언트 사용
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JNSContextFactory"); env.put(Context.PROVIDER_URL, "iiop://192.168.11.22:9740"); InitialContext ctx = new InitialContext(env); Object obj = ctx.lookup("ejb/Calc"); CalcHome home = (CalcHome)PortableRemoteObject.narrow(obj, CalcHome.class); Calc calcRef = home.create();
알려진 문제점들은 다음과 같다.
서버로 접속할 수 없을 때 재접속을 1분 동안 무한 시도하는 현상
JEUS에 내장된 ORB에서 기본적으로 서버로 연결할 수 없을 때 재접속을 60초 동안 재시도하는데, 이때 별도의 sleep time 없이 진행된다. 따라서 수많은 로그 메시지가 찍히거나 CPU가 과점되는 문제가 있다. 이를 방지하기 위해서는 다음과 같은 옵션을 클라이언트에서 시스템 프로퍼티로 설정해야 한다. (기본값: 60000, 단위: ms)
com.sun.corba.ee.transport.ORBCommunicationsRetryTimeout=1
PortableRemoteObject.narrow() 호출 후에 NullPointerException이 발생하는 현상
클라이언트에서 다음과 같이 호출을 하는 경우 home 객체가 null이 리턴되면서 NullPointerException이 발생하는 경우가 있다.
[예 5.7] NullPointerException이 발생하는 경우
CalcHome home = (CalcHome)PortableRemoteObject.narrow(obj, CalcHome.class); // null is returned Calc calcRef = home.create(); // NullPointerException
이 문제는 CORBA Stub 클래스를 찾지 못한 경우 발생한다. JEUS MS에서
Enable Interop 설정이 제대로 되어 있지 않은 경우이다. 해당 설정이
있으면 올바른 ORB가 초기화되어 Stub을 동적으로 메모리에 자동 생성한다. 외부 클라이언트의 경우에는 동적 Stub를
생성하는 기능이 없는 경우에 이런 에러가 발생할 수 있다.
Standalone 클라이언트의 경우에는 시스템 프로퍼티에 다음과 같이 설정되어 있는지를 확인한다.
jeus.client.interop=true
WebLogic에서 JEUS에 dot(.)이 포함된 이름의 EJB를 찾지 못하는 현상
"com.acme.CalcHome"과 같이 dot(.)이 포함된 형식으로 <export-name>을 지정한 경우 WebLogic에서는 lookup이 실패한다. 이는 WebLogic에서 dot(.)을 slash(/)와 동일하게 취급하여 내부적으로 "com/acme/CalcHome"과 같이 요청을 보내기 때문이다. 이런 경우에는 dot(.)이 포함된 이름을 사용하지 않도록 한다.