3 장. JBoss의 네이밍

JNDI 네이밍 서비스

이번 장에서는 네이밍 서비스에 기반을 둔 JBoss JNDI와 JBoss와 J2EE에서의 JNDI의 역할에 대해 논의해보도록 하겠습니다. JNDI API의 기본에 대한 소개와 일반적인 사용법에 대한 표기에 대해서도 역시 다루어지게 될 것입니다. JJBoss에서의 2EE 컴포넌트 네이밍 환경의 설정을 위한 표준 배치 서술자 또한 논의될 것입니다. 마지막에 다루어질 주제는 JBoss 네이밍 서비스의 환경과 아키텍쳐입니다.

JBoss 네이밍 서비스는 J2EE에서 중요한 역할을 담당하는데, 그 이유는 네이밍 서비스에서 이름이 객체에 맵핑되도록 하기 때문입니다. 이와 같은 사항은 어떠한 프로그래밍 환경에서도 필요로 하는 기초적인 것으로 개발자와 관리자는 객체와 서비스를 식별이 가능한 이름으로 참조하기 원하기 때문입니다. 진보적인 네이밍 서비스의 좋은 사례로는 인터넷 도메인 네임 시스템(DNS)을 들수 있습니다. DNS 서비스는 여러분이 숫자로된 인터넷 주소가 아닌 논리적인 이름을 통해 호스트를 참조할 수 있도록 합니다. JNDI 또한 J2EE 컴포넌트내에서 개발자와 관리자가 이름-객체 바인딩을 생성시키게 하는 유사한 역할을 담당합니다.

3.1. JNDI 개요

JNDI는 JDK1.3 버전 이상에 번들링되는 표준 자바 API 입니다. JNDI는 다양한 기존 네이밍 서비스를 위한 범용 인터페이스를 제공합니다: DNS, LDAP, Active Directory, RMI registry, COS registry, NIS, 및 파일 시스템. JNDI API는 논리적으로 네이밍 서비스에 액세스할때 사용하는 클라이언트 API와 네이밍 서비스를 위한 JNDIimplementations를 생성하도록 하는 서비스 제공 인터페이스(SPI)로 나뉘어집니다.

SPI 계층은 범용 JNDI 클라이언트 인터페이스를 사용하는 네이밍 서비스를 노출시키는 핵심 JNDI 클래스를 가능케 하도록 해야하는 네이밍 서비스 제공자(provider)의 추상화입니다. 네이밍 서비스를 위한 JNDI의 구현부는 JNDI 프로바이더로 참조됩니다. JBoss의 네이밍은 SPI 클래스에 기반을 둔 예제 JNDI 구현입니다. 여기서 JNDI SPI는 J2EE 컴포넌트 개발자에게 꼭 필요한 것은 아닙니다.

클라이언트와 서비스 제공자 API에 대해 다루고 있는 JNDI 소개와 자습서는 http://java.sun.com/products/jndi/tutorial/에서 읽으실 수 있습니다.

3.1.1. JNDI API

JNDI API의 메인 패키지는 javax.naming 입니다. 여기에는 다섯개의 인터페이스와 10개의 클래스 그리고 예외처리에 대한 것들이 몇개 있습니다. 한개의 키 클래스인 InitialContext와 두개의 키 인터페이스 Context , Name가 있습니다.

3.1.1.1. Names

이름의 표기법은 JNDI에서 근본적인 중요성을 갖습니다. 네이밍 시스템은 다음과 같은 이름 신택스에 따라 결정합니다. 네이밍 시스템의 신택스는 사용자가 이름으로 표시되는 문자열을 컴포넌트로 번역할 수 있도록 합니다. 이름은 네이밍 시스템과 함께 객체를 찾는데 사용됩니다. 간단하게 생각하자면, 네이밍 시스템은 고유한 이름을 갖는 객체의 집합이라고도 볼 수 있습니다. 네이밍 시스템내에서 객체를 찾기위해서는 네이밍 시스템에 이름을 제공해야 하며, 네이밍 시스템은 이름으로 저장된 객체를 반환합니다.

예를 들어 유닉스 파일 시스템의 네이밍 변환을 살펴보도록 하겠습니다. 각각의 파일은 파일 시스템의 루트로부터 각각의 경로 다음에 슬래쉬 캐릭터("/")가 뒤에 붙는 상대적인 경로로 이름이 붙여집니다. 파일의 경로는 왼쪽에서 오른쪽 순서로 오게됩니다. 즉, /usr/jboss/readme.txt라는 경로는 루트 파일 시스템내의 usr 디렉터리밑에 있는 jboss 디렉토리안에 존재하는 readme.txt라는 이름의 파일입니다. JBoss 네이밍은 네이밍 변환으로 유닉스 스타일의 네임스페이스를 사용합니다.

javax.naming.Name 인터페이스는 컴포넌트의 순서대로 붙여진 일반적인 이름으로 표현합니다. 혼합된(composite) 이름(확장된 다중 네임스페이스를 갖는 것)이나 복합적인(compound) 이름(단일 계층구조의 네이밍 시스템내에서 사용되는 것)이 될 수 있습니다. 이름의 컴포넌트들은 번호가 매겨집니다. 이름의 인덱스가 N이면 0부터 시작해서 N을 포함하지 않는 범위의 컴포넌트를 갖습니다. 가장 왼쪽의 컴포넌트는 인덱스가 0입니다. 빈 이름은 컴포넌트를 갖지 않습니다.

혼합된 이름은 확장된 다중 네임스페이로된 혼합된 이름의 시퀀스입니다. 혼합된 이름의 예로는 유닉스 명령어인 scp와 함께 사용되는 hostname+file 입니다. 다음 명령은 localfile.txt를 호스트 ahost.someorg.org에 있는 tmp 디렉터리의 remotefile.txt 파일로 복사하게 됩니다:

scp localfile.txt ahost.someorg.org:/tmp/remotefile.txt

복합적인 이름은 계층적인 네임스페이스로부터 파생되었습니다. 복합된 이름에서의 각각의 컴포넌트는 원자적인 이름이며, 이것은 더이상 작은 컴포넌트로 쪼갤 수 없는 문자열을 의미합니다. 유닉스 파일 시스템에서의 파일 경로이름이 복합된 이름의 좋은 예입니다. ahost.someorg.org:/tmp/remotefile.txt는 DNS와 UNIX 파일 시스템 네임스페이스를 확장한 복합적인 이름입니다. 복합된 이름의 컴포넌트들은 ahost.someorg.org/tmp/remotefile.txt 입니다. 컴포넌트는 네이밍 시스템의 네임스페이스에서의 이름 문자열입니다. 만일 컴포넌트가 계층구조 네임스페이스로부터 온 것이라면, 이 컴포넌트는 javax.naming.CompoundName 클래스를 사용하여 쪼개질 수 없는 부분으로 다시 나눌 수 있습니다. JNDI API는 복합적인 이름을 위한 Name 인터페이스의 구현으로써 javax.naming.CompositeName 클래스를 제공합니다.

3.1.1.2. Contexts

javax.naming.Context 인터페이스는 네이밍 서비스와 상호작용을 위한 주요 인터페이스입니다. Context 인터페이스는 이름-객체 바인딩 세트를 표현합니다. 모든 context는 context가 문자열 이름을 javax.naming.Name 인스턴스로 어떻게 해석할지를 결정하는 관련된 네이밍 변환을 갖습니다. 객체와 바인딩되는 이름을 만들기위해서는 Context의 bind 메쏘드를 호출하고 그 인수로 이름과 객체를 지정합니다. 객체는 나중에 Context의 lookup 메쏘드를 사용하여 설정된 이름으로 가져올 수 있습니다. 일반적으로 Context는 이름을 객체에 바인딩하고, 이름의 언바인딩, 모든 이름-객체 바인딩의 목록을 얻을 수 있는 오퍼레이션을 제공합니다. Context에 바인딩시킨 객체는 그 자체가 Context 타입일 수 있습니다. 바운드된 Context 객체는 호출된 bind 메쏘드가 있는 Context의 subcontext로써 참조됩니다.

일례로 유닉스 파일 시스템에서의 컨텍스트인 /usr 경로이름을 갖는 디렉터리를 생각해보겠습니다. 다른 파일 디렉토리에 대한 상대적인 디렉토리 이름을 갖는 파일은 subcontext(보통 서브 디렉터리처럼 참조됨)입니다. 경로이름이 /usr/jboss 인 파일 디렉터리에서는 jboss 컨텍스트가 usr의 subcontext입니다. 또다른 예로 org와 같은 DNS 도메인을 들 수 있습니다. 여기서 DNS 도메인은 컨텍스트입니다. DNS 도메인에 또 다른 DNS 도메인이 상대적으로 이름이 붙는 경우 역시 subcontext의 예가 됩니다. jboss.org라는 DNS 도메인에서 jboss DNS 도메인은 오른쪽에서 왼쪽방향으로 해석되는 DNS 네임이므로 org의 subcontext입니다.

3.1.1.2.1. InitialContext를 사용하여 컨텍스트 획득하기

모든 네이밍 서비스 연산자들은 Context 인터페이스의 구현쪽에서 수행됩니다. 따라서 여러분이 사용하고자 하는 네이밍 서비스를 위한 Context를 얻을 수 있는 방법이 필요합니다. javax.naming.IntialContext 클래스는 Context 인터페이스를 구현하며, 네이밍 서비스와의 상호작용을 위한 시작 포인트를 제공합니다.

여러분이 InitialContext를 생성하는 경우, 환경으로부터 속성을 가지고 초기화됩니다. JNDI에서는 각각의 속성의 값을 다음의 두 소스로부터 순차적으로 값을 합쳐 결정하게 됩니다.

이 두 소스 모두에서 발견되는 각각의 속성들의 값은 다음과 같이 결정됩니다. 만약 속성이 JNDI 팩토리의 목록에 지정된 표준 JNDI 속성중에 하나라면, 모든 값들은 하나의 콜론으로 분리된 목록으로 합쳐지게 됩니다. 다른 속성들의 경우, 맨처음 발견된 값만이 사용됩니다. JNDI 환경 속성을 지정하는 권장되는 메쏘드는 여러분의 코드에서 JNDI 제공자를 지정하는 정보를 외부로 나타나게 할 수 있는 jndi.properties 파일을 이용하는 것으로 이를 통해 여러분의 코드를 변경하거나 다시 컴파일할 필요가 없이 JNDI 제공자를 바꿀 수 있게됩니다.

InitialContext 클래스에 의해 내부적으로 사용되는 Context 구현부는 런타임시 결정됩니다. 디폴트 정책은 javax.naming.spi.InitialContextFactory 구현부의 클래스 이름을 포함하는 환경 속성 java.naming.factory.initial을 사용합니다. 여러분은 사용하는 네이밍 서비스 제공자로부터 InitialContextFactory 클래스의 이름을 얻습니다.

예제 3.1, “jndi.properties 예제 파일” 에서는 로컬호스트의 1099 포트에서 동작하는 JBossNS 서비스에 연결하기 위해 사용하는 클라이언트 어플리케이션을 위한 예제 jndi.properties 파일입니다. 클라이언트 어플리케이션은 어플리케이션의 클래스경로상에서 사용이 가능한 jndi.properties 파일을 가질 필요가 있습니다. 이것들은 JBossNS JNDI 구현상 필요한 것들입니다. 다른 JNDI 제공자들은 다른 속성과 값을 갖을 것입니다.

예제 3.1. jndi.properties 예제 파일

### JBossNS properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

3.1.2. J2EE 와 JNDI - 어플리케이션 컴포넌트 환경

JNDI는 J2EE 사양의 근간을 이루고 있습니다. JNDI의 핵심 사용목적의 하나는 J2EE 컴포넌트 코드를 코드가 배치된 환경과 분리시키는 것입니다. 어플리케이션 컴포넌트의 환경 사용을 통해 어플리케이션 컴포넌트는 그 소스 코드를 손대지 않고도 커스터마이징시킬 수 있게 됩니다. 어플리케이션 컴포넌트 환경은 ENC(엔터프라이즈 네이밍 컨텍스트-Enterprise Naming Context)로도 불립니다. 이것은 어플리케이션 컴포넌트 컨테이너가 JNDI 컨텍스트 형태내에서 컨테이너 컴포넌트에 사용가능한 ENC를 만들어야 하는 책임을 갖습니다. ENC는 다음과 같은 방법으로 J2EE 컴포넌트의 생명주기내에 참여된 참가자들에 의해 활용됩니다.

J2EE 플랫폼에서 JNDI의 사용을 고려한 완전한 시방서(specification)는 J2EE 1.3 시방서의 5절에서 찾을 수 있습니다. J2EE 시방서는 http://java.sun.com/j2ee/download.html에서 구할 수 있습니다.

어플리케이션 컴포넌트 인스턴스는 JNDI API를 사용하는 ENC에 위치합니다. 어플리케이션 컴포넌트 인스턴스는 인수가 없는 생성자(constructor)를 사용하여 javax.naming.InitialContext 객체를 생성한 후, java:comp/env 이름아래 아래에서 네이밍 환경에서 찾습니다. 어플리케이션 컴포넌트의 환경 엔트리들은 ENC내에 직접 저장되거나 subcontext내에 저장됩니다. 예제 3.2, “ENC 액세스 예제 코드” 에서는 자신의 ENC에 액세스하는 컴포넌트 코드의 전형적인 원시 코드를 볼 수 있습니다.

예제 3.2. ENC 액세스 예제 코드

// 어플리케이션 컴포넌트의 ENC를 획득하기
Context iniCtx = new InitialContext();
Context compEnv = (Context) iniCtx.lookup("java:comp/env");

어플리케이션 컴포넌트 환경은 어플리케이션 서버 컨테이너의 제어 쓰레드가 어플리케이션 컴포넌트와 상호작용할 때 컴포넌트에 의해서만 액세스가 가능한 로컬 환경입니다. 즉, EJB Bean1은 EJB Bean2의 ENC 요소에 액세스할 수 없으며, 그 반대도 마찬가지입니다. 이와 유사하게 웹 어플리케이션 Web1은 웹 어플리케이션 Web2의 ENC 요소에 액세스할 수 없으며, 이와 같은 상황은 Bean1 혹은 Bean2등과 같은 것들에 대해서도 마찬가지입니다. 또한 임의의 클라이언트 코드가 어플리케이션 서버 VM 내부에서 실행되던지 아니면 외부에서 실행되던지간에 컴포넌트의 java:comp JNDI 컨텍스트에 액세스할 수 없습니다. ENC의 목적은 어플리케이션 컴포넌트가 배치되어 있는 환경 타입에 상관없도록 보장하는 별도의 분리된, 읽기만 가능한 네임스페이스입니다. ENC는 각각의 컴포넌트가 자신의 ENC 컨텐츠를 정의하기 때문에 다른 컴포넌트들과는 분리되어야 합니다. 즉, 컴포넌트 AB는 동일한 이름으로 정의될 수 있으나 서로 다른 객체를 참조하게 됩니다. 예를 들어, EJB Bean1 에서 빨간색에 대한 RGB 코드 값을 십육진수로 참조하는 java:comp/env/red 환경 엔트리를 정의하더라도 웹 어플리케이션 Web1에서도 배치 환경 언어 로케일을 red라는 동일한 이름에 바인딩시킬 수 있습니다.

JBoss에서 네이밍의 범위(scope)는 보통 3가지가 사용됩니다: java:comp, java: 그리고 다른 이름. 앞서 살펴보았던 것처럼 java:comp 컨텍스트와 subcontext들은 특정한 컨텍스트와 관련된 어플리케이션 컴포넌트에서만 사용이 가능합니다. java: 쪽에 직접 Subcontext와 객체를 바인딩시키면 JBoss 서버 가상 머신내에서만 보여지고 원격 클라이언트에서는 볼 수 없습니다. 다른 어떤 컨텍스트나 객체 바인딩은 컨텍스트 또는 객체에서 직렬화 지원을 제공하여 원격 클라이언트쪽에서 사용이 가능하게 됩니다. 이러한 네이밍 범위의 구분방법에 대해서는 3.2 섹션, “JBossNS 아키텍쳐”에서 집중적으로 다룰 것 입니다.

데이터베이스 풀이 위치한 곳과 관련된 JBoss 서버 내부에서만 사용할 수 있는 javax.sql.DataSource 커넥션 팩토리의 경우 java: 컨텍스트에 바인딩되도록 제한하면 유용해지는데 이는 좋은 예가 될 것입니다. 반면, EJB 홈 인터페이스는 원격 클라이언트에서 액세스할 수 있도록 전역적으로 보이는 이름으로 바인딩되어야 할 것입니다.

3.1.2.1. ENC 사용법 관행

JNDI는 어플리케이션 컴포넌트로부터 정보를 잘 다룰수 있도록 노출화하는 API로 사용됩니다. 어플리케이션 컴포넌트가 정보에 액세스하기위해 사용하는 JNDI 이름은 EJB 컴포넌트의 표준 ejb-jar.xml 배치 서술자에서 정의되며, 웹 컴포넌트의 경우에는 표준 web.xml 배치 서술자에서 정의합니다. JNDI로 저장하고 가져올 수 있는 정보의 타입들에는 다음과 같은 것들이 있습니다:

배치 서술자 요소 각각의 타입들은 정보가 연결되어 있는 JNDI 컨텍스트의 이름을 고려한 JNDI 사용방법의 관행을 갖습니다. 또한 표준 배치 서술자 요소를 추가할때 어플리케이션 컴포넌트를 배치 환경의 JNDI 이름으로 맵핑해주는 JNDI 이름을 지정하는 배치 서술자 요소가 JBoss 서버에 존재합니다.

3.1.2.1.1. ejb-jar.xml ENC 요소

EJB 2.0 배치 서술자는 EJB 컴포넌트와 환경의 컬렉션을 서술해줍니다. EJB 컴포넌트의 세 타입(세션, 엔티티 그리고 메지시-구동) 각각은 EJB 로컬 네이밍 컨텍스트의 시방서를 지원합니다. ejb-jar.xml 서술은 EJB가 오퍼레이트할때 필요한 환경의 로지컬 뷰입니다. 일반적으로 EJB 컴포넌트를 개발하는 사람들은 개발할 EJB가 어떤 환경에 배치될지를 모르기때문에, 논리적인 이름을 사용하여 배치 환경에 종속적이지 않은 컴포넌트 환경을 기술합니다. EJB 컴포넌트의 논리적인 이름을 대응되는 배치 환경의 리소스로 연결해주는 책임은 배치 관리자에게 있습니다.

그림 3.1, “표준 ejb-jar.xml 2.0 배치 서술자에서의 ENC 요소”에서는 비-ENC 요소가 없는 EJB 배치 서술자 DTD의 그래픽 뷰를 보여주고 있습니다. 세션 요소만 엔티티와 메시지-구동을 위한 ENC 요소로 완전히 확장시켜 보여주고 있습니다. 완전한 ejb-jar.xml DTD는 선 사이트의 http://java.sun.com/dtd/ejb-jar_2_0.dtd에서 구할 수 있습니다.

표준 ejb-jar.xml 2.0 배치 서술자에서의 ENC 요소.

그림 3.1. 표준 ejb-jar.xml 2.0 배치 서술자에서의 ENC 요소.

3.1.2.1.2. web.xml ENC 요소

서블릿 2.3 배치 서술자는 웹 컴포넌트들과 이들의 환경에 대한 컬렉션을 기술합니다. 웹 어플리케이션용 ENC는 웹 어플리케이션내의 모든 서블릿과 JSP 페이지에 대해 전역적으로 선언되어집니다. 일반적으로 웹 어플리케이션 개발자들은 개발하는 웹 어플리케이션이 어디에 배치되어질지 모르기때문에, 논리적인 이름을 사용하여 배치 환경에 비종속적인 컴포넌트 환경을 기술합니다. 웹 컴포넌트의 논리적인 이름을 대응되는 배치 환경 리소스로 연결시키는 것은 배치 관리자의 몫입니다.

그림 3.2, “표준 서블릿 2.3 web.xml 배치 서술자에서의 ENC 요소”에서는 비-ENC 요소가 없는 웹 어플리케이션 배치 서술자 DTD의 그래픽적인 뷰를 보여주고 있습니다. 완전한 web.xml DTD는 선 웹 사이트의 http://java.sun.com/dtd/web-app_2_3.dtd에서 구할 수 있습니다.

표준 서블릿 2.3 web.xml 배치 서술자에서의 ENC 요소들.

그림 3.2. 표준 서블릿 2.3 web.xml 배치 서술자에서의 ENC 요소들.

3.1.2.1.3. jboss.xml ENC 요소

JBoss EJB 배치 서술자는 EJB 컴포넌트 EJN JNDI 이름으로부터 실제 배치된 JNDI 이름을 제공합니다. 논리적인 레퍼런트를 배치된 어플리케이션 서버 환경의 어플리케이션 컴포넌트가 대응되는 물리적인 리소스로 만들어주도록 매핑시키는 것은 어플리케이션 배치담당자의 책임입니다. JBoss에서는 이러한 작업을 jboss.xml 배치 서술자를 사용하여 ejb-jar.xml 서술자를 구현합니다. 그림 3.3, “JBoss 3.2 jboss.xml 배치 서술자에서의 ENC 요소.”에서는 비-ENC요소가 없는 JBoss EJB 배치 서술자 DTD의 그래픽 뷰를 보여주고 있습니다. 이 그림은 앞서 보았던 ejb-jar.xml과 대응되는 요소를 갖는 가상의 이상적인 뷰입니다.

JBoss 3.2 jboss.xml 배치 서술자에서의 ENC 요소.

그림 3.3. JBoss 3.2 jboss.xml 배치 서술자에서의 ENC 요소.

3.1.2.1.4. jboss-web.xml ENC 요소

JBoss의 웹 배치 서술자에서는 웹 어플리케이션의 ENC JNDI 이름으로부터 실제 배치된 JNDI 이름을 매핑시키도록 합니다. 논리적인 레포런스들을 배치된 어플리케이션 서버 환경에 대응되는 물리적인 리소스로 웹 어플리케이션에 구현하도록 매핑시키는 것은 어플리케이션 배치책임자가 할일입니다. JBoss에서 이러한 작업은 jboss-web.xml 배치 서술자를 사용하여 web.xml 서술자를 구현합니다. 그림 3.4, “JBoss 3.2 jboss-web.xml 배치 서술자의 ENC 요소.”에서는 비-ENC 요소가 없는 JBoss 웹 배치 서술자 DTD의 그래픽뷰를 보여주고 있습니다. 완전한 jboss-web.xml DTD는 JBoss 웹 사이트의 http://www.jboss.org/j2ee/dtd/jboss_web_3_2.dtd나 배포판의 docs/dtd 디렉터리에서 구할 수 있습니다.

JBoss 3.2 jboss-web.xml 배치 서술자의 ENC 요소.

그림 3.4. JBoss 3.2 jboss-web.xml 배치 서술자의 ENC 요소.

3.1.2.1.5. Environment 엔트리

Environment 엔트리들은 컴포넌트 ENC내에 저장된 정보의 가장 간단한 형태이며 유닉스나 윈도우에서 찾아볼 수 있는 오퍼레이팅 시스템 환경 변수와 유사합니다. Environment 엔트리들은 이름-값으로 연결되어 컴포넌트를 외부로 노출시켜 그 이름으로 값을 참조할 수 있게 합니다.

Environment 엔트리는 표준 배치 서술자내에서 env-entry 요소를 사용하여 선언합니다. env-entry 요소는 다음과 같은 자식 요소들을 갖습니다:

ejb-jar.xml 배치 서술자에서 env-entry가 사용된 예제가 예제 3.3, “ejb-jar.xml에서 env-entry 요소의 사용 예제”에 있습니다. env-entry는 완전한 이름과 값 사양이기 때문에 JBoss에 특정한 배치 서술자는 없습니다. 예제 3.4, “ENC env-entry 액세스 코드의 일부분”에서는 배치 서술자에 선언되어진 maxExemptionstaxRate env-entry 값을 액세스하는 예제 코드의 일부분을 볼 수 있습니다.

예제 3.3. ejb-jar.xml에서 env-entry 요소의 사용 예

<!-- ... -->
<session>
    <ejb-name>ASessionBean</ejb-name>
    <!-- ... -->
    <env-entry>
        <description>소득세 공제의 최대 허용액</description>
        <env-entry-name>maxExemptions</env-entry-name>
        <env-entry-type>java.lang.Integer</env-entry-type>
        <env-entry-value>15</env-entry-value>
    </env-entry>
    <env-entry>
        <description>세율</description>
        <env-entry-name>taxRate</env-entry-name>
        <env-entry-type>java.lang.Float</env-entry-type>
        <env-entry-value>0.23</env-entry-value>
    </env-entry>
</session>
<!-- ... -->    

예제 3.4. ENC env-entry 액세스 코드의 일부분

InitialContext iniCtx = new InitialContext();
Context envCtx = (Context) iniCtx.lookup("java:comp/env");
Integer maxExemptions = (Integer) envCtx.lookup("maxExemptions");
Float taxRate = (Float) envCtx.lookup("taxRate");
3.1.2.1.6. EJB 레퍼런스

다른 EJB들과 상호작용하는 것은 EJB와 웹 컴퍼넌트에서는 일반적입니다. EJB 홈 인터페이스가 아래쪽에 연결되는 JNDI 이름은 배치 시간에 결정되기 때문에, 컴포넌트 개발자가 배치자에 의해 링크되어질 EJB의 레퍼런스를 선언할 수 있는 방법이 필요합니다. EJB 레퍼런스는 이 요구조건을 충족합니다.

EJB 레퍼런스는 배치된 EJB 홈 인터페이스를 가리키는 어플리케이션 네이밍 환경에서의 링크입니다. 어플리케이션 컴포넌트에서 사용되는 이름은 배치 환경에서 EJB 홈의 실제 이름과 분리된 논리적인 링크입니다. J2EE 시방서에서는 엔터프라이즈 빈즈를 참조하는 모든 것은 어플리케이션 컴포넌트의 환경인 java:comp/env/ejb 컨텍스트내에 구성되도록 권고하고 있습니다.

EJB 레퍼런스는 배치 서술자내에서 ejb-ref 요소를 사용하여 선언됩니다. 각각의 ejb-ref 요소는 참조되는 엔터프라이즈 빈을 위한 어플리케이션 컴포넌트를 참조하는 데 필요한 인터페이스를 기술합니다. ejb-ref 요소는 다음과 같은 자식 요소들을 갖습니다:

EJB 레퍼런스는 선언부에 ejb-ref 요소를 갖는 어플리케이션 컴포넌트에 한정됩니다. 즉, 런타임시 다른 어플리케이션 컴포넌트들이 EJB 레퍼런스에 액세스할 수 없으며, 다른 어플리케이션 컴포넌트에서 이름 충돌을 없애기위해 똑같은 ejb-ref-name를 갖는 ejb-ref 요소를 정의할 수 있습니다. 예제 3.5, “ejb-jar.xml ejb-ref 서술자의 샘플”에서는 ejb-ref 요소의 사용을 보여주기 위해 ejb-jar.xml 의 일부분을 발췌하여 보여주고 있습니다. 예제 3.5, “ejb-jar.xml ejb-ref 서술자의 샘플”에서 정의한 ShoppingCartHome 레퍼런스에 액세스하는 것을 보여주는 샘플 코드는 예제 3.6, “ ENC ejb-ref 액세스 코드의 일부분”에서 보여주고 있습니다.

예제 3.5. ejb-jar.xml ejb-ref 서술자의 샘플

<!-- ... -->
<session>
    <ejb-name>ShoppingCartBean</ejb-name>
    <!-- ...-->
</session>

<session>
    <ejb-name>ProductBeanUser</ejb-name>
    <!--...-->
    <ejb-ref>
        <description>This is a reference to the store products entity </description>
        <ejb-ref-name>ejb/ProductHome</ejb-ref-name>
        <ejb-ref-type>Entity</ejb-ref-type>
        <home>org.jboss.store.ejb.ProductHome</home>
    </ejb-ref>
    <remote> org.jboss.store.ejb.Product</remote>
</session>

<session>
    <ejb-ref>
        <ejb-name>ShoppingCartUser</ejb-name>
        <!--...-->
        <ejb-ref-name>ejb/ShoppingCartHome</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <home>org.jboss.store.ejb.ShoppingCartHome</home>
        <remote> org.jboss.store.ejb.ShoppingCart</remote>
        <ejb-link>ShoppingCartBean</ejb-link>
    </ejb-ref>
</session>

<entity>
    <description>The Product entity bean </description>
    <ejb-name>ProductBean</ejb-name>
    <!--...-->
</entity>

<!--...--> 

예제 3.6.  ENC ejb-ref 액세스 코드의 일부분

InitialContext iniCtx = new InitialContext();
Context ejbCtx = (Context) iniCtx.lookup("java:comp/env/ejb");
ShoppingCartHome home = (ShoppingCartHome) ejbCtx.lookup("ShoppingCartHome"); 
3.1.2.1.7. jboss.xmljboss-web.xml을 갖는 EJB 레퍼런스

JBoss를 위한 jboss.xml EJB 배치 서술자는 두가지 방법으로 EJB 레퍼런스에 영향을 미칩니다. 첫 번째는 session의 자식 요소인 jndi-nameentity 요소가 사용자로 하여금 EJB 홈 인터페이스를 위한 배치 JNDI 이름을 지정할 수 있도록 합니다. EJB에 대한 jndi-namejboss.xml내에 정의되지 않았을 경우에는 홈 인터페이스가 ejb-jar.xmlejb-name 값쪽에 연결됩니다. 즉, 예제 3.5, “ejb-jar.xml ejb-ref 서술자의 샘플”에서 ShoppingCartBean라는 ejb-name을 갖는 세션 EJB는 jboss.xmljndi-name이 지정되지 않으면 ShoppingCartBean 이라는 JNDI 이름에 연결된 자신의 홈 인터페이스를 갖게 됩니다.

두 번째는 컴포넌트의 ENC ejb-ref쪽으로 방향을 설정해주는 것입니다. ejb-link 요소는 다른 엔터프라이즈 어플리케이션내의 EJB들을 참조하는데 사용할 수 없습니다. 여러분이 ejb-ref에서 외부 EJB를 액세스할 필요가 있다면, 배치된 EJB 홈의 JNDI 이름을 jboss.xml ejb-ref/jndi-name 요소를 사용하여 지정해줄 수 있습니다.

jboss-web.xml 배치자는 웹 어플리케이션 ENC ejb-ref 참조가 되는 목적지를 설정하는데에만 사용됩니다. JBoss의 ejb-ref에 대한 컨텐츠 모델은 다음과 같습니다:

예제 3.7, “ jboss.xml ejb-ref 샘플의 일부분”에서는 jboss.xml 서술자의 일부분을 발췌하여 다음과 같은 사용방법을 보여주고 있습니다:

예제 3.7.  jboss.xml ejb-ref 샘플의 일부분

<!-- ... -->
<session>
    <ejb-name>ProductBeanUser</ejb-name>
    <ejb-ref>
        <ejb-ref-name>ejb/ProductHome</ejb-ref-name>
        <jndi-name>jboss/store/ProductHome</jndi-name>
    </ejb-ref>
</session>
                        
<entity>
    <ejb-name>ProductBean</ejb-name>
    <jndi-name>jboss/store/ProductHome</jndi-name>
     <!-- ... -->
</entity>
<!-- ... -->
3.1.2.1.8. EJB 로컬 레퍼런스

EJB 2.0은 RMI call by value 시맨틱을 사용하지 않는 로컬 인터페이스들을 추가합니다. 이 인터페이스들은 call by reference 시맨틱을 사용하며 따라서 어떠한 RMI 직렬화에 따른 오버헤드를 초래하지 않습니다. EJB 로컬 레퍼런스는 배치된 EJB 로컬 홈 인터페이스를 가리키는 어플리케이션 컴포넌트 네이밍 환경에서의 링크입니다. 어플리케이션 컴포넌트에 의해 사용되는 이름은 배치 환경에서의 실제 EJB 로컬 홈 이름으로부터 컴포넌트를 분리시켜주는 논리적인 링크입니다. J2EE 시방서(specification)에서는 모든것이 어플리케이션 컴포넌트의 환경에서의 java:comp/env/ejb 컨텍스트내에 조직화되어지는 엔터프라이즈 빈즈를 참조하도록 권고하고 있습니다.

EJB 로컬 레퍼런스는 배치 서술자내에서 ejb-local-ref 요소를 사용하여 선언됩니다. 각각의 ejb-local-ref 요소는 참조되는 엔터프라이즈 빈을 갖는 어플리케이션 컴포넌트를 레퍼런싱하는 인터페이스의 필요사항을 기술합니다. ejb-local-ref 요소는 다음과 같은 자식 요소들을 갖습니다:

EJB 로컬 레퍼런스는 ejb-local-ref 요소를 포함하고 있는 선언을 갖는 어플리케이션 컴포넌트에 국한됩니다. 즉, 이것은 EJB 로컬 레퍼런스를 다른 어플리케이션 컴포넌트에서는 런타임에서 액세스할 수 없다는 것을 의미하며, 다른 어플리케이션 컴포넌트들은 이름 충돌을 막기위해 똑같은 ejb-ref-name을 갖는 ejb-local-ref 요소들을 정의해야 합니다. 예제 3.8, “ ejb-jar.xml ejb-local-ref 서술자의 일부 예제”에서는 ejb-local-ref 요소를 사용하고 있는 방식을 보여주고 있습니다. 예제 3.8, “ ejb-jar.xml ejb-local-ref 서술자의 일부 예제”에서 선언된 ProbeLocalHome 레퍼런스로 액세스하고 있는 코드의 예가 예제 3.9, “ENC ejb-local-ref 액세스 코드의 일부”에 제공되고 있습니다.

예제 3.8.  ejb-jar.xml ejb-local-ref 서술자의 일부 예제

<!-- ... -->
    <session>
        <ejb-name>Probe</ejb-name>
        <home>org.jboss.test.perf.interfaces.ProbeHome</home>
        <remote>org.jboss.test.perf.interfaces.Probe</remote>
        <local-home>org.jboss.test.perf.interfaces.ProbeLocalHome</local-home>
        <local>org.jboss.test.perf.interfaces.ProbeLocal</local>
        <ejb-class>org.jboss.test.perf.ejb.ProbeBean</ejb-class>
        <session-type>Stateless</session-type>
        <transaction-type>Bean</transaction-type>
    </session>
    <session>
        <ejb-name>PerfTestSession</ejb-name>
        <home>org.jboss.test.perf.interfaces.PerfTestSessionHome</home>
        <remote>org.jboss.test.perf.interfaces.PerfTestSession</remote>
        <ejb-class>org.jboss.test.perf.ejb.PerfTestSessionBean</ejb-class>
        <session-type>Stateless</session-type>
        <transaction-type>Container</transaction-type>
        <ejb-ref>
            <ejb-ref-name>ejb/ProbeHome</ejb-ref-name>
            <ejb-ref-type>Session</ejb-ref-type>
            <home>org.jboss.test.perf.interfaces.SessionHome</home>
            <remote>org.jboss.test.perf.interfaces.Session</remote>
            <ejb-link>Probe</ejb-link>
        </ejb-ref>
        <ejb-local-ref>
            <ejb-ref-name>ejb/ProbeLocalHome</ejb-ref-name>
            <ejb-ref-type>Session</ejb-ref-type>
            <local-home>org.jboss.test.perf.interfaces.ProbeLocalHome</local-home>
            <local>org.jboss.test.perf.interfaces.ProbeLocal</local>
            <ejb-link>Probe</ejb-link>
        </ejb-local-ref>
    </session>
    <!-- ... -->

예제 3.9. ENC ejb-local-ref 액세스 코드의 일부

InitialContext iniCtx = new InitialContext();
Context ejbCtx = (Context) iniCtx.lookup("java:comp/env/ejb");
ProbeLocalHome home = (ProbeLocalHome) ejbCtx.lookup("ProbeLocalHome");
3.1.2.1.9. 리소스 관리자 커넥션 팩토리 레퍼런스

리소스 관리자 커넥션 팩토리 레퍼런스는 어플리케이션 컴포넌트 코드가 리소스 관리자 커넥션 팩토리 레퍼런스를 호출한 논리적인 이름을 사용하여 리소스 팩토리를 참조할 수 있게 합니다. 리소스 관리자 커넥션 팩토리 레포런스들은 표준 배치 서술자내의 resource-ref 요소로 정의됩니다. Deployerjboss.xmljboss-web.xml을 사용하여 타겟 오퍼레이션이 되는 환경내에 존재하는 실제 리소스 관리자 커넥션 팩토리들로 리소스 관리자 커넥션 팩토리 레포런스를 연결시킵니다.

각각의 resource-ref 요소는 단일 리소스 관리자 커넥션 팩토리 레퍼런스를 기술합니다. resource-ref 요소는 다음의 자식 요소들로 구성되어집니다:

J2EE 시방서에서는 모든 리소스 관리자 커넥션 팩토리 레퍼런스가 각각의 리소스 관리자 타입에 대한 서로다른 subcontext를 사용하여 어플리케이션 컴포넌트 환경의 subcontexts내에 구성되도록 권장하고 있습니다. subcontext 이름에 권장되는 리소스 관리자 타입에는 다음과 같은 것들이 있습니다:

예제 3.10, “ web.xml resource-ref 서술자의 일부”에서는 resource-ref 요소의 사용방법을 보여주기위해 예제로 제공되는 web.xml 서술자의 일부분을 보여주고 있습니다. 예제 3.11, “ENC resource-ref access 예제 코드의 일부”에서는 어플리케이션 컴포넌트가 resource-ref에서 정의된 DefaultMail 리소스를 액세스하여 사용하는 코드의 일부입니다.

예제 3.10.  web.xml resource-ref 서술자의 일부

<web>
    <!-- ... -->
    <servlet>
        <servlet-name>AServlet</servlet-name>
        <!-- ... -->
    </servlet>
    <!-- ... -->
    <!-- JDBC DataSources (java:comp/env/jdbc) -->
    <resource-ref>
        <description>The default DS</description>
        <res-ref-name>jdbc/DefaultDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
    <!-- JavaMail Connection Factories (java:comp/env/mail) -->
    <resource-ref>
        <description>Default Mail</description>
        <res-ref-name>mail/DefaultMail</res-ref-name>
        <res-type>javax.mail.Session</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
    <!-- JMS Connection Factories (java:comp/env/jms) -->
    <resource-ref>
        <description>Default QueueFactory</description>
        <res-ref-name>jms/QueueFactory</res-ref-name>
        <res-type>javax.jms.QueueConnectionFactory</res-type>
        <res-auth>Container</res-auth>
    </resource-re>      

예제 3.11. ENC resource-ref access 예제 코드의 일부

Context initCtx = new InitialContext();
javax.mail.Session s = (javax.mail.Session)
initCtx.lookup("java:comp/env/mail/DefaultMail");
3.1.2.1.10. jboss.xml 과 jboss-web.xml에서의 리소스 관리자 커넥션 팩토리 레퍼런스

JBoss의 jboss.xml EJB 배치 서술자와 jboss-web.xml 웹 어플리케이션 배치 서술자의 용도는 res-ref-name 요소에 의해 정의된 논리적인 이름으로 JBoss에 배치된 리소스 팩토리의 JNDI 이름을 연결해주도록 하는 것입니다. 이것은 jboss.xml 이나 jboss-web.xml 서술자내에서 resource-ref 요소를 사용하여 구현하게 됩니다. JBoss의 resource-ref 요소는 다음과 같은 자식 요소들로 구성되어집니다:

예제 3.12, “jboss-web.xml resource-ref 서술자 예제의 일부분”에서는 예제 3.10, “ web.xml resource-ref 서술자의 일부”에서 주어진 resource-ref 요소들과 맵핑하는 예를 보여주고 있는 간단한 jboss-web.xml 서술자의 일부분을 입니다.

예제 3.12. jboss-web.xml resource-ref 서술자 예제의 일부분

<jboss-web>
    <!-- ... -->
    <resource-ref>
        <res-ref-name>jdbc/DefaultDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <jndi-name>java:/DefaultDS</jndi-name>
    </resource-ref>
    <resource-ref>
        <res-ref-name>mail/DefaultMail</res-ref-name>
        <res-type>javax.mail.Session</res-type>
        <jndi-name>java:/Mail</jndi-name>
    </resource-ref>
    <resource-ref>
        <res-ref-name>jms/QueueFactory</res-ref-name>
        <res-type>javax.jms.QueueConnectionFactory</res-type>
        <jndi-name>QueueConnectionFactory</jndi-name>
    </resource-ref>
    <!-- ... -->
</jboss-web>
3.1.2.1.11. 리소스 환경 레퍼런스

리소스 환경 레퍼런스는 논리적인 이름을 사용하는 리소스(JMS 목적지등)와 관련된 관리되는 객체를 참조하는 요소들입니다. 리소스 환경 레퍼런스는 표준 배치 서술자내에서 resource-env-ref 요소를 사용하여 정의됩니다. Deployerjboss.xmljboss-web.xml 서술자를 사용하여 타겟 오퍼레이션이 되는 환경에서 실제 관리되는 객체의 위치로 리소스 환경 레퍼런스를 연결시킵니다.

각각의 resource-env-ref 요소는 참조하는 어플리케이션 컴포넌트가 가져야하는 참조되는 관리 객체의 요구사항을 기술합니다. resource-env-ref 요소는 다음과 같은 자식 요소들을 갖습니다:

예제 3.13, “ejb-jar.xml resource-env-ref 예제의 일부”에서는 세션 빈으로 선언된 resource-ref-env 요소의 예를 보여주고 있습니다. 예제 3.14, “ ENC resource-env-ref 액세스 코드의 일부”에서는 resource-env-ref를 이용하여 선언된 StockInfo 큐를 어떻게 찾아내는지를 보여주는 코드의 일부분입니다.

예제 3.13. ejb-jar.xml resource-env-ref 예제의 일부

<session>
    <ejb-name>MyBean</ejb-name>
    
    <resource-env-ref>
        <description>This is a reference to a JMS queue used in the
            processing of Stock info
        </description>
        <resource-env-ref-name>jms/StockInfo</resource-env-ref-name>
        <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
    </resource-env-ref>
    <!-- ... -->
</session>

예제 3.14.  ENC resource-env-ref 액세스 코드의 일부

InitialContext iniCtx = new InitialContext();
javax.jms.Queue q = (javax.jms.Queue)
envCtx.lookup("java:comp/env/jms/StockInfo");
3.1.2.1.12. 리소스 환경 레퍼런스와 jboss.xml, jboss-web.xml

JBoss의 jboss.xml EJB 배치 서술자와 jboss-web.xml 웹 어플리케이션 배치 서술자의 용도는 resource-env-ref-name 요소를 사용하여 정의한 논리적인 이름을 JBoss내에 배치된 관리되는 객체의 JNDI 이름으로 연결해주는 것입니다. 이러한 과정은 jboss.xml 혹은 jboss-web.xml 서술자내의 resource-env-ref 요소를 제공함으로써 가능하게 됩니다. JBoss의 resource-env-ref 요소는 다음과 같은 자식 요소들을 갖습니다:

예제 3.15, “jboss.xml resource-env-ref 서술자 예제의 일부분”에서는 StockInfo resource-env-ref에 대한 매핑 예제를 보여주는 jboss.xml 서술자 에제의 일부분입니다.

예제 3.15. jboss.xml resource-env-ref 서술자 예제의 일부분

<session>
    <ejb-name>MyBean</ejb-name>
        
        <resource-env-ref>
        <resource-env-ref-name>jms/StockInfo</resource-env-ref-name>
        <jndi-name>queue/StockInfoQueue</jndi-name>
    </resource-env-ref>
    <!-- ... -->
</session>  

3.2. JBossNS 아키텍쳐

JBossNS 아키텍쳐는 자바 소켓/RMI 기반의 javax.naming.Context 인터페이스 구현입니다. 이것은 원격으로 액세스될 수 있는 클라이언트/서버 구현입니다. 이러한 구현은 최적화되어있기 때문에 동일한 VM내에서 액세스하게되면, JBossNS 서버는 소켓을 사용하지 않게됩니다. 동일한 VM에서는 전역적인 싱글톤으로 사용이 가능한 객체의 레포런스를 통해 액세스가 발생됩니다. 그림 3.5, “JBossNS 아키텍쳐에서의 중요한 컴포넌트들.”에서는 JBossNS 구현과 여기에 관련된 중요한 클래스들을 보여주고 있습니다.

JBossNS 아키텍쳐에서의 중요한 컴포넌트들.

그림 3.5. JBossNS 아키텍쳐에서의 중요한 컴포넌트들.

우리는 NamingService MBean 으로 시작해보도록 하겠습니다. NamingService MBean은 JNDI 네이밍 서비스를 제공합니다. 이것은 J2EE 기술기반의 컴포넌트에서 광범위하게 사용되는 중요한 서비스입니다. NamingService를 위한 설정가능한 속성들은 다음과 같습니다:

또한 NamingServicejava:comp 컨텍스트를 만들게 되는데, 이 컨텍스트는 자기에게 액세스하려는 java:comp 컨텍스트를 java:comp 컨텍스트에 액세스하는 쓰레드의 컨텍스트 클래스 로더를 기초로 분리되어 집니다. 이를 통해 J2EE 스펙에서 필요로 하는 어플리케이션 컴포넌트의 사설 ENC가 제공됩니다. 이러한 격리는 자신의 javax.naming.ObjectFactory로써 org.jboss.naming.ENCFactory를 사용하는 컨텍스트에 javax.naming.Reference를 바인딩시켜 이루어지게 됩니다. 클라이언트가 java:comp이나 subcontext를 룩업하게 될때, ENCFactory는 쓰레드 컨텍스트 ClassLoader를 점검하고 ClassLoader를 키로 사용하여 맵상에서 룩업을 수행합니다.

클래스 로더의 인스턴스에 대한 컨텍스트 인스턴스가 존재하지 않는다면, 컨텍스트 인스턴스가 만들어지고 ENCFactory 맵내에 클래스 로더와 관계를 맺습니다. 따라서, 어플리케이션 컴포넌트의 ENC의 정확한 격리는 실행되는 컴포넌트 쓰레드와 관계있는 고유한 ClassLoader를 수신받는 각각의 컴포넌트에 의존합니다.

NamingService는 자신의 기능을 org.jnp.server.Main MBean쪽으로 위임합니다. 중복된 MBeans이 되는 이유는 JBossNS가 독립적인 JNDI 구현부로써 시작되기 때문이며 여전히 그러한 방식으로 동작합니다. NamingService MBean에는 JBoss 서버쪽에 Main 인스턴스를 내장하기 때문에 동일한 JBoss 서버를 의미하는 동일한 VM에서의 JNDI 사용은 어떠한 소켓의 오버헤드도 유발시키지 않습니다. NamingService의 설정가능한 속성들은 JBossNS Main MBean의 설정가능한 속성입니다. NamingService MBean의 속성값을 설정하는 것은 NamingService가 갖고 있는 Main MBean에 대응되는 속성을 간단히 설정해주면 됩니다. NamingService가 시작되면, 포함하고 있는 Main MBean을 시작시켜 JNDI 네이밍 서비스를 활성화시킵니다.

또한, NamingService는 JMX detyped 호출 오퍼레이션을 통해 Naming 인터페이스 오퍼레이션을 노출시킵니다. 이를 통해 네이밍 서비스를 임의의 프로토콜을 사용하는 JMX 아답터를 통해 액세스할 수 있습니다. 우리는 이번 장의 마지막부분에서 invoke 오퍼레이션을 사용하여 네이밍 서비스에 액세스하기위해 HTTP를 어떻게 사용하는지에 대한 예를 살펴보도록 할 것입니다.

여기서는 쓰레드와 쓰레드 컨텍스트 클래스 로더의 세부적인 사항을 살펴보지는 않지만, JNDI 자습서에서는 적당한 만큼 요약해서 다루고 있습니다. 자세한 정보는 http://java.sun.com/products/jndi/tutorial/beyond/misc/classloader.html에서 찾아보실 수 있습니다.

Main MBean이 시작되면, 다음과 같은 일들을 수행하게 됩니다:

3.2.1. 네이밍 InitialContext 팩토리

JBoss JNDI 프로바이더는 현재 세가지 다른 InitialContext 팩토리 구현을 지원하고 있습니다. 가장 일반적으로 사용하는 팩토리는 org.jnp.interfaces.NamingContextFactory 구현입니다. 이것의 속성들은 다음과 같은 것들이 포함됩니다:

클라이언트가 이 JBossNS 속성값들을 갖는 InitialContext를 생성할 때, org.jnp.interfaces.NamingContextFactory 객체는 일련의 오퍼레이션에서 사용되어질 Context 인스턴스를 생성할 때 사용됩니다. NamingContextFactoryjavax.naming.spi.InitialContextFactory 인터페이스의 JBossNS 구현입니다. NamingContextFactory 클래스가 하나의 Context를 생성하도록 요청받게 되면, InitialContext 환경과 전역 JNDI 네임스페이스내의 컨텍스트 이름과 함께 하나의 org.jnp.interfaces.NamingContext 인스턴스를 만듭니다. 실제로 JBossNS 서버에 연결하는 업무를 수행하는 것은 NamingContext 인스턴스이며, Context 인터페이스를 구현합니다. 환경에서의 Context.PROVIDER_URL 정보는 NamingServer RMI 레퍼런스를 얻기위한 서버를 가리킵니다.

NamingContext 인스턴스를 NamingServer 인스턴스에 결합시키는 것은 첫번째로 수행되는 Context 오퍼레이션상에서 느린 방식으로 일어납니다. Context 오퍼레이션이 수행되고 NamingContext에는 관련된 NamingServer가 없을 경우에는 환경 속성들 중에서 Context.PROVIDER_URL이 정의되었는지를 알아봅니다. Context.PROVIDER_URL은 사용될 Context가 있는 JBossNS 서버의 host와 포트를 정의합니다. 만일 프로바이더의 URL이 있다면, NamingContext는 제일 먼저 host와 포트가 쌍으로 이루어진 키로 조합되어 있는 Naming 인스턴스가 이미 생성되어졌는지를 NamingContext 클래스의 정적인 맵을 확인함으로써 점검합니다. host와 포트 한쌍이 얻어졌다고 할 때는 이미 존재하는 Naming 인스턴스를 간단히 사용합니다. 해당 host와 포트에 대한 Naming 인스턴스가 생성된 것이 없다면, NamingContextjava.net.Socket을 사용하여 host와 포트에 연결하고 소켓과 호출한 get 메쏘드로부터 java.rmi.MarshalledObject를 읽음으로써 서버로부터 Naming RMI 스터브를 가져옵니다. 새로 얻어진 Naming 인스턴스는 host와 포트의 쌍으로 구성된 NamingContext 서버 맵내에 캐쉬됩니다. 컨텍스트와 연관된 JNDI 환경내에 프로바이더 URL이 지정되어 있지 않다면, NamingContext는 Main MBean에의해 설정된 VM의 Naming 인스턴스를 그냥 사용합니다.

Context 인터페이스의 NamingContext 구현은 모든 오퍼레이션들을 NamingContext와 관련된 Naming 인스턴스쪽으로 위임합니다. Naming 인터페이스를 구현하는 NamingServer 클래스는 Context 저장소로 java.util.Hashtable을 사용합니다. 하나의 주어진 JBossNS 서버에 대한 각각 구별되는 JNDI 이름을 위한 하나의 고유한 NamingServer 인스턴스가 존재합니다. 여기에는 그때 그때마다 NamingServer 인스턴스를 참조하는 활성화된 일시적인 NamingContext 인스턴스가 0개 이상 있습니다. NamingContext의 용도는 Naming 인터페이스 아답터에 대해 Context처럼 동작하여 NamingContext로 넘겨지는 JNDI 이름들의 번역을 관리하는 것입니다. JNDI 이름은 상대적이거나 URL이기 때문에, 이것이 참조하고 있는 JBossNS 서버의 컨텍스트내의 절대적인 이름으로 변환될 필요가 있습니다. 이러한 번역은 NamingContext의 중요한 기능입니다.

3.2.1.1. 클러스터링된 환경하에서의 네이밍 발견

JBoss를 클러스터링으로 구축한 경우, 여러분은 Context.PROVIDER_URL 값을 지정하지 않고, 클라이언트가 네트워크상에서 사용가능한 네이밍 서비스를 질의하도록 선택할 수 있습니다. 이러한 작동방식은 JBoss 서버를 all 환경으로 동작시키거나 이에 상응하는 설정을 갖는 org.jboss.ha.framework.server.ClusterPartitionorg.jboss.ha.jndi.HANamingService 서비스가 배치된 경우에만 가능합니다. 네이밍의 발견 프로세스는 멀티캐스트 요청 패킷을 discovery address/port로 전송하는 것과 임의의 노드가 응답을 할 때까지 기다리는 과정으로 구성됩니다. 응답은 Naming 인터페이스의 HA-RMI 버전입니다. 다음에 오는 InitialContext 속성들은 discovery 환경설정에 영향을 미칩니다:

3.2.1.2. HTTP InitialContext 팩토리 구현(Implementation)

JNDI 네이밍 서비스는 HTTP를 통해 액세스될 수 있습니다. JNDI 클라이언트 시점으로 볼때, 이것은 클라이언트에서 지속적으로 JNDI Context 인터페이스를 사용하는 과정에서 인지하지 않는 변화입니다. Context 인터페이스를 통한 오퍼레이션들은 HTTP 프로토콜을 사용하여 자신의 JMX 호출 오퍼레이션을 사용하는 NamingService로 요청을 넘겨주는 서블릿에 보내지게 됩니다. HTTP를 액세스 프로토콜로 사용할 때 얻을 수 있는 장점은 표준 서블릿 롤 기반의 보안을 사용해서 JNDI 서비스에 안전하게 액세스할 수 있는 능력뿐만 아니라 HTTP를 허용한 방화벽과 프록시 환경을 통해서도 보다 수월하게 액세스할 수 있다는 것입니다.

HTTP를 통해 JNDI에 액세스하려면 팩토리 구현으로써 org.jboss.naming.HttpNamingContextFactory를 사용합니다. 이 팩토리에 대한 지원되는 InitialContext 환경 속성의 완전한 세트는 다음과 같습니다:

HttpNamingContextFactory로부터 반환받는 JNDI Context implementation 은 여기서 만들어진 호출을 JMX 버스를 통해 NamingService쪽으로 호출을 포워딩시키는 연계(bridge) 서블릿으로 위임하고 HTTP를 통해 다시 응답되는 것을 마샬링하는 프록시입니다. 프록시에서는 오퍼레이션할 수 있도록 하는 연계 서블릿의 URL이 무엇인지 알아야할 필요가 있습니다. 이 값은 JBoss 웹 서버가 잘 알려진 퍼블릭 인터페이스를 갖고 있을 경우 서버쪽에 연결될 수도 있습니다. JBoss 웹 서버가 하나 이상의 방화벽이나 프록시 뒷단에 위치하고 있을 경우, 프록시는 어떤 URL이 필요한지 알 수가 없습니다. 이런 경우에는 프록시는 클라이언트쪽 VM에서 설정되어져야 하는 시스템 속성 값을 사용합니다. HTTP를 통해 JNDI를 동작시키는 것에 대한 보다 자세한 정보는 3.2.2 절, “HTTP를 통해 JNDI 액세스하기”를 참고하십시오.

3.2.1.3. Login InitialContext Factory Implementation

JBoss는 발전해오면서 IntialContext 팩토리 환경을 통해 로그인 정보를 제공하도록 지원하지 않고 있습니다. 왜냐하면 JAAS에서 보다 유연성있는 보안 프레임워크를 지원하고 있기 때문입니다. 간단하게 하기위해 그리고 다른 어플리케이션 서버 환경에서 이런 메커니즘을 사용하도록 한 것을 마이그레이션하기 위해서는 InitialContext 팩토리 구현부에서 이것을 허용해야 합니다. JAAS는 여전히 이러한 구현내에서 사용되지만, 클라이언트 어플리케이션내에서 JAAS 인터페이스의 manifest는 사용되지 않습니다.

이러한 기능을 제공하는 팩토리 클래스는 org.jboss.security.jndi.LoginInitialContextFactory 입니다. 다음은 이 팩토리에서 지원하는 InitialContext 환경 속성들입니다:

3.2.2. HTTP를 통해 JNDI 액세스하기

소켓 부트스트랩 프로토콜을 갖는 레가시 RMI/JRMP에 더하여 JBoss에서는 HTTP를 통해 자신의 JNDI 네이밍 서비스에 액세스할 수 있도록 지원을 제공합니다. 이러한 기능성은 http-invoker.sar에 의해 제공됩니다. http-invoker.sar의 구조는 다음과 같습니다:

http-invoker.sar
+- META-INF/jboss-service.xml
+- invoker.war
| +- WEB-INF/jboss-web.xml
| +- WEB-INF/classes/org/jboss/invocation/http/servlet/InvokerServlet.class
| +- WEB-INF/classes/org/jboss/invocation/http/servlet/NamingFactoryServlet.class
| +- WEB-INF/classes/org/jboss/invocation/http/servlet/ReadOnlyAccessFilter.class
| +- WEB-INF/classes/roles.properties
| +- WEB-INF/classes/users.properties
| +- WEB-INF/web.xml
| +- META-INF/MANIFEST.MF
+- META-INF/MANIFEST.MF

jboss-service.xml 서술자에서는 HttpInvokerHttpInvokerHA MBean들을 정의합니다. 이러한 서비스들은 JMX 버스상에서 적절한 대상이 되는 MBean쪽으로 HTTP를 통해 전송할 수 있는 메쏘드 호출의 라우팅을 처리합니다.

http-invoker.war 웹 어플리케이션에는 HTTP 전송에 대한 세부적인 처리를 담당하는 서블릿들이 포함되어 있습니다. NamingFactoryServlet은 JBoss JNDI 네이밍 서비스 javax.naming.Context implementation을 위한 요청들의 생성을 처리합니다. InvokerServlet은 RMI/HTTP 클라이언트에의해 만들어진 호출을 처리합니다. ReadOnlyAccessFilter는 인증되지 않은 클라이언트에서 읽기-가능으로만 액세스할 수 있도록 단일 JNDI 컨텍스트를 만들어주는 동안 JNDI 네이밍 서비스를 안전하게 합니다.

JNDI 컨텍스트를 위한 HTTP 호출자(invoker) 프록시/서버의 구조

그림 3.6. JNDI 컨텍스트를 위한 HTTP 호출자(invoker) 프록시/서버의 구조

환경을 살펴보기전에 http-invoker 서비스의 오퍼레이션을 살펴보도록 하겠습니다. 그림 3.6, “JNDI 컨텍스트를 위한 HTTP 호출자(invoker) 프록시/서버의 구조”에서는 JBoss의 JNDI 프록시 구조에 대한 논리적인 뷰와 이것들이 http-invoker의 JBoss 서버쪽 컴포넌트들과의 관계를 볼 수 있습니다. 프록시는 Context.INITIAL_CONTEXT_FACTORY 속성을 org.jboss.naming.HttpNamingContextFactory로, Context.PROVIDER_URL 속성을 NamingFactoryServlet의 HTTP URL로 설정한 InitialContext를 사용하여 NamingFactoryServlet으로부터 획득됩니다. 얻어진 프록시는 Context 인터페이스 구현을 제공하는 하나의 org.jnp.interfaces.NamingContext 인스턴스내에 내장됩니다.

프록시는 하나의 org.jboss.invocation.http.interfaces.HttpInvokerProxy 인스턴스이고 org.jnp.interfaces.Naming 인터페이스를 구현합니다. 내부적으로 HttpInvokerProxyNaming 인터페이스 메쏘드 호출을 HTTP post를 통한 InvokerServlet으로 마샬링하는 하나의 호출자(invoker)를 포함합니다. InvokerServlet에서는 이러한 요구들을 JMX 호출쪽으로 NamingService로 번역하고, 해당 HTTP post 응답내에서 프록시에 호출에 대한 응답을 반환합니다.

이 컴포넌트들 모두를 함께 묶어줄때 필요한 설정 값들이 몇개 있으며 그림 3.7, “설정 파일과 JNDI/HTTP 컴포넌트사이의 관계” 에서 설정 파일과 이에 대응되는 컴포넌트사이의 관계를 보여주고 있습니다.

설정 파일과 JNDI/HTTP 컴포넌트사이의 관계

그림 3.7. 설정 파일과 JNDI/HTTP 컴포넌트사이의 관계

http-invoker.sar/META-INF/jboss-service.xml 서술자에서는 NamingService를 위한 HttpInvokerProxy를 생성하는 HttpProxyFactory를 정의합니다. HttpProxyFactory를 설정하기 위해 필요한 속성들은 다음과 같습니다:

http-invoker.sar/invoker.war/WEB-INF/web.xml 서술자에서는 자신들의 초기화 파라메터들을 갖고 NamingFactoryServletInvokerServet의 매핑을 정의합니다. JNDI/HTTP에 대한 NamingFactoryServlet의 설정은 다음과 같이 정의되는 JNDIFactory 항목입니다:

JNDI/HTTP에 상대적인 InvokerServlet의 설정은 다음과 같이 정의되는 JMXInvokerServlet 입니다:

3.2.3. HTTPS를 통한 JNDI 액세스

HTTP/SSL을 통해 JNDI에 액세스할 수 있도록 하기위해서 여러분은 웹 컨테이너상에서 SSL 연결이 가능하도록 할 필요가 있습니다. 이것에 대한 상세한 내용은 톰캣을 서블릿 컨테이너로 통합하기에서 다루어지고 있습니다. 우리는 단순한 샘플 클라이언트를 가지고 HTTPS의 사용에 대한 데모를 하도록 하겠습니다. 여기서 샘플 클라이언트는 JNDI 프로바이더의 URL로써 HTTPS를 사용하게 됩니다. 우리는 예제속에서 하나의 SSL 커넥터 설정을 제공하기때문에 여러분이 SSL 연결 설정의 세부내용에 관심이 없더라도 예제 자체적으로 포함되어 있습니다.

또한 HTTPS URL을 사용하기위한 HttpProxyFactory 설정의 환경도 함께 제공합니다. 이러한 설정을 제공하고 있는 예제를 설치하면 http-invoker.sar jboss-service.xml 서술자에서 관련 부분들을 볼 수 있습니다. 표준 http 설정으로부터 상대적으로 변경된 모든 부분들은 8443 포트를 사용하게 되는 HTTPS URL 설정에 대한 InvokerURLPrefixInvokerURLSuffix 속성들입니다.

<!-- HTTPS를 통해 네이밍 서비스의 인터페이스를 노출시킴 -->
<mbean code="org.jboss.invocation.http.server.HttpProxyFactory" 
       name="jboss:service=invoker,type=https,target=Naming">
    <!-- The Naming service we are proxying -->
    <attribute name="InvokerName">jboss:service=Naming</attribute>
    <!-- Compose the invoker URL from the cluster node address -->
    <attribute name="InvokerURLPrefix">https://</attribute>
    <attribute name="InvokerURLSuffix">:8443/invoker/JMXInvokerServlet </attribute>
    <attribute name="UseHostName">true</attribute>
    <attribute name="ExportedInterface">org.jnp.interfaces.Naming </attribute>
    <attribute name="JndiName"/>
    <attribute name="ClientInterceptors">
        <interceptors>
            <interceptor>org.jboss.proxy.ClientMethodInterceptor </interceptor>
            <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
            <interceptor>org.jboss.naming.interceptors.ExceptionInterceptor </interceptor>
            <interceptor>org.jboss.invocation.InvokerInterceptor </interceptor>
        </interceptors>
    </attribute>
</mbean>

최소한 HTTPS를 사용하는 하나의 JNDI 클라이언트가 https URL 프로토콜 핸들러로써 설정되어야 합니다. 우리는 HTTPS를 위한 Java Secure Socket Extension(JSSE)를 사용할 것입니다. JSSE 문서에서는 https를 사용하기 위해 필요한 것들에 대해서 아주 잘 설명하고 있으며, 다음의 과정들은 예제 3.16, “전송으로 HTTPS를 사용하는 JNDI 클라이언트”에서 보여주고 있는 클라이언트 예제를 설정하는데 필요합니다:

예제 3.16. 전송으로 HTTPS를 사용하는 JNDI 클라이언트

package org.jboss.chap3.ex1;

import java.security.Security;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;

/**
 * 전송으로 HTTPS를 사용하는 간단한 JNDI 클라이언트.
 *
 * @author Scott.Stark@jboss.org
 * @version $Revision: 1.8 $
 */
public class ExClient
{
    public static void main(String args[]) throws Exception
    {
        // JSSE가 설치되어 있지 않을 수도 있기 때문에 선의 JSSE 프로바이더를 인스톨합니다.
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        System.out.println("Added JSSE security provider");

         Properties env = new Properties();
	     env.setProperty(Context.INITIAL_CONTEXT_FACTORY,
                         "org.jboss.naming.HttpNamingContextFactory");
         env.setProperty(Context.PROVIDER_URL,
                         "https://localhost:8443/invoker/JNDIFactory");
         Context ctx = new InitialContext(env);
         System.out.println("Created InitialContext, env="+env);
         Object data = ctx.lookup("jmx/rmi/RMIAdaptor");
         System.out.println("lookup(jmx/rmi/RMIAdaptor): "+data);
    }
}

클라이언트를 테스트하시위해서는 먼저 3장의 예제를 빌드시켜 chap3 환경 파일세트를 생성하십시오.

[nr@toki examples]$ ant -Dchap=chap3 config 
Buildfile: build.xml

validate:
     [java] ImplementationTitle: JBoss [WonderLand]
     [java] ImplementationVendor: JBoss.org
     [java] ImplementationVersion: 3.2.6RC2 (build: CVSTag=Branch_3_2 date=200409270100)
     [java] SpecificationTitle: JBoss
     [java] SpecificationVendor: JBoss (http://www.jboss.org/)
     [java] SpecificationVersion: 3.2.6
     [java] JBoss version is: 3.2.6

fail_if_not_valid:

init:
     [echo] Using jboss.dist=/tmp/jboss-3.2.6

compile-src:

compile:

config:

config:
     [echo] Preparing chap3 configuration fileset
    [mkdir] Created dir: /tmp/jboss-3.2.6/server/chap3
     [copy] Copying 221 files to /tmp/jboss-3.2.6/server/chap3
     [copy] Copied 1 empty directory to /tmp/jboss-3.2.6/server/chap3
     [copy] Copying 1 file to /tmp/jboss-3.2.6/server/chap3/conf
     [copy] Copying 1 file to /tmp/jboss-3.2.6/server/chap3/conf
     [copy] Copying 1 file to /tmp/jboss-3.2.6/server/chap3/deploy/jbossweb-tomcat50.sar
     [copy] Copying 1 file to /tmp/jboss-3.2.6/server/chap3/deploy/http-invoker.sar/META
-INF
     [copy] Copying 1 file to /tmp/jboss-3.2.6/server/chap3/deploy/http-invoker.sar/invo
ker.war/WEB-INF
BUILD SUCCESSFUL
Total time: 6 seconds

그런 다음, chap3 환경 파일세트를 사용하여 JBoss 서버를 시작시킵니다:

[nr@toki bin]$ sh run.sh -c chap3
=========================================================================

  JBoss Bootstrap Environment

  JBOSS_HOME: /tmp/jboss-3.2.6
...

마지막으로 ExClient를 다음과 같이 하여 실행시킵니다:

[nr@toki examples]$ ant -Dchap=chap3 -Dex=1 run-example
Buildfile: build.xml
 
validate:
...
                
run-example:

run-example1:
     [java] JSSE already available
     [java] Created InitialContext, env={java.naming.provider.url=https://localhost:8443/
invoker/JNDIFactorySSL, java.naming.factory.initial=org.jboss.naming.HttpNamingContextFactory}
     [java] lookup(jmx/rmi/RMIAdaptor): org.jboss.invocation.jrmp.interfaces.JRMPInvokerProxy@873b9f
BUILD SUCCESSFUL
Total time: 6 seconds

3.2.4. HTTP를 통해 JNDI에 안전하게 액세스하기

HTTP를 통해 JNDI로 액세스할 때의 잇점중에 하나는 standard web declarative security를 사용하여 네이밍을 오퍼레이션할 수 있을뿐만 아니라 JNDI InitialContext 팩토리에 안전하게 액세스하는것이 쉽다는 것입니다. 이것은 JNDI/HTTP 전송의 서버측 핸들링이 두 개의 서블릿으로 구현되기 때문에 가능합니다. 이 서블릿들은 이미 앞에서 살펴보았던 defaultall 설정 배치 디렉토리내의 http-invoker.sar/invoker.war 디렉터리에 포함되어 있습니다. JNDI에 안전하게 액세스할 수 있도록 하기위해서는 여러분이 invoker.war/WEB-INF/web.xml 서술자를 편집하고 모든 안전하지 못한 서블릿 매핑을 제거해야 할 필요가 있습니다. 즉, 예제 3.17, “ JNDI 서블릿에 안전하게 액세스하도록 하는 web.xml 서술자 예제”에서 보여지는 web.xml 서술자에서는 사용자가 인증되고 HttpInvoker의 역할을 갖고 있을 경우에만 invoker.war 서블릿으로 액세스가 허용됩니다.

예제 3.17.  JNDI 서블릿에 안전하게 액세스하도록 하는 web.xml 서술자 예제

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
          "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
          "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <!-- ### Servlets -->
    <servlet>
        <servlet-name>JMXInvokerServlet</servlet-name>
        <servlet-class>
            org.jboss.invocation.http.servlet.InvokerServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>   <servlet>
        <servlet-name>JNDIFactory</servlet-name>
        <servlet-class>
            org.jboss.invocation.http.servlet.NamingFactoryServlet
        </servlet-class>
        <init-param>
            <param-name>namingProxyMBean</param-name>
            <param-value>jboss:service=invoker,type=http,target=Naming</param-value>
        </init-param>
        <init-param>
            <param-name>proxyAttribute</param-name>
            <param-value>Proxy</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>  
    <!-- ### Servlet Mappings -->
    <servlet-mapping>
        <servlet-name>JNDIFactory</servlet-name>
        <url-pattern>/restricted/JNDIFactory/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>JMXInvokerServlet</servlet-name>
        <url-pattern>/restricted/JMXInvokerServlet/*</url-pattern>
    </servlet-mapping>   <security-constraint>
        <web-resource-collection>
            <web-resource-name>HttpInvokers</web-resource-name>
            <description>An example security config that only allows users with
                the role HttpInvoker to access the HTTP invoker servlets </description>
            <url-pattern>/restricted/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>HttpInvoker</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>JBoss HTTP Invoker</realm-name>
    </login-config>   <security-role>
        <role-name>HttpInvoker</role-name>
    </security-role>
</web-app>

web.xml 서술자는 어떤 서블릿이 안전할지와 안전한 서블릿에 접근할 수 있도록 허용된 역할(roles)만을 정의합니다. 여러분은 war에 대한 인증(authentication)과 권한(authorization)을 처리할 수 있는 보안 도메인에 대한 추가적인 정의도 해주어야만 합니다. 이러한 작업은 jboss-web.xml 서술자를 통해 이루어지며, 예제에서 사용된 http-invoker 보안 도메인은 다음과 같습니다:.

<jboss-web>
    <security-domain>java:/jaas/http-invoker</security-domain>
</jboss-web>

security-domain 요소에서는 인증과 권한을 위해 사용되는 JAAS 로그인 모듈 설정에 사용되어질 보안 도메인의 이름이 정의됩니다. 보안 도메인 이름의 보다 상세한 의미와 설정은 8.1.6 절, “JBoss에서 보안성 선언 가능하게하기”를 살펴보십시오.

3.2.5. 읽기만 가능한 안전하지 않은 컨텍스트를 갖는 JNDI에 안전하게 액세스하기

JNDI/HTTP 네이밍 서비스를 위한 또 다른 가능한 기능은 인증되지 않은 사용자들이 읽기만 가능한 모드로 액세스할 수 있는 컨텍스트를 정의해주는 것입니다. 이것은 인증 계층에의해 사용되는 서비스를 위해 매우 중요한 사항입니다. 예를 들어, SRPLoginModule은 인증과정을 수행하기 위해 SRP 서버 인터페이스를 찾아볼 필요가 있습니다. 이것이 가능하게 하려면, web.xml 서술자에서 몇가지 추가적인 설정이 필요하게 됩니다. 다음 다이어그램에서는 일기만 가능한 액세스에 필요한 web.xml 서술자의 요소를 보여주고 있습니다:

<web-app>
    <filter>
        <filter-name>ReadOnlyAccessFilter</filter-name>
        <filter-class>org.jboss.invocation.http.servlet.ReadOnlyAccessFilter</filter-class>
        <init-param>
            <param-name>readOnlyContext</param-name>
            <param-value>readonly-context</param-value>
        </init-param>
        <init-param>
            <param-name>invokerName</param-name>
            <param-value>jboss:service=Naming</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>ReadOnlyAccessFilter</filter-name>
        <url-pattern>/readonly/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>ReadOnlyJNDIFactory</servlet-name>
        <servlet-class>
            org.jboss.invocation.http.servlet.NamingFactoryServlet
        </servlet-class>
        <init-param>
            <param-name>namingProxyMBean</param-name>
            <param-value>
                jboss:service=invoker,type=http,target=Naming,readonly=true
            </param-value>
        </init-param>
        <init-param>
            <param-name>proxyAttribute</param-name>
            <param-value>Proxy</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>  
    <!-- A mapping for the JMXInvokerServlet that only allows invocations
         of lookups under a read-only context. This is enforced by the
         ReadOnlyAccessFilter
     -->
    <servlet-mapping>
        <servlet-name>JMXInvokerServlet</servlet-name>
        <url-pattern>/readonly/JMXInvokerServlet/*</url-pattern>
    </servlet-mapping>
</web-app>

위와 같은 설정하에서 어떤 사람들은 readonly-context나 이것의 서브컨텍스트상에서 Context.lookup 오퍼레이션이 수행되기를 바랄 수도 있으나 이 컨텍스트에서는 어떠한 다른 오퍼레이션도 가능하지 않습니다. 또한 다른 컨텍스트에 대해서도 어떠한 종류의 오퍼레이션들도 수행되지 않습니다. readonly-context/data 바인딩에서의 룩업에 대한 코드의 일부분이 아래에 보여집니다:

Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, 
                "org.jboss.naming.HttpNamingContextFactory");
env.setProperty(Context.PROVIDER_URL, 
                "http://localhost:8080/invoker/ReadOnlyJNDIFactory");

Context ctx2 = new InitialContext(env);
Object data = ctx2.lookup("readonly-context/data");

3.2.6. 추가적인 네이밍 MBean들

JBoss내에 존재하는 내장되어 있는 JBossNS 서버를 설정하는 네이밍서비스 MBean에 더하여, JBoss에는 네이밍과 관련된 세개의 추가적인 MBean들이 존재합니다. 이것들은 각각 ExternalContext, NamingAlias, 그리고 JNDIView 입니다.

3.2.6.1. org.jboss.naming.ExternalContext MBean

ExternalContext MBean은 여러분이 외부의(external) JNDI 컨텍스트들을 JBoss 서버의 JNDI 네임스페이스에 연합시킬 수 있도록 합니다. 여기서 "외부(external)"가 지칭하는것은 JBoss 서버 VM 내부에서 동작하는 JBossNS 네이밍 서비스에 대해 바깥쪽에 위치한 네이밍 서비스 입니다. 여러분은 JNDI 프로바이더의 루트 컨텍스트가 직렬화(serializable)되지 않은 경우라도 LDAP 서버, 파일 시스템, DNS 서버등등을 포함시킬 수 있습니다. 이러한 연합과정은 네이밍 서비스가 원격 액세스를 지원하는 경우, 원격 클라이언트에서 가능하게 할 수 있습니다.

외부 JNDI 네이밍 서비스를 합치기위해서는 jboss-service.xml 설정 파일에 ExternalContext MBean 서비스의 설정을 추가시켜야만 합니다. ExternalContext 서비스의 설정 속성들은 다음과 같습니다:

아래에 보여진 MBean 정의에서는 두 개의 설정이 존재합니다: 하나는 LDAP 서버를 위한것이고 다른 하나는 로컬 파일 시스템 디렉터리를 위한 것입니다:

<!-- Bind a remote LDAP server -->
<mbean code="org.jboss.naming.ExternalContext" 
       name="jboss.jndi:service=ExternalContext,jndiName=external/ldap/jboss">
    <attribute name="JndiName">external/ldap/jboss</attribute>
    <attribute name="Properties">jboss.ldap</attribute>
    <attribute name="InitialContext"> javax.naming.ldap.InitialLdapContext </attribute>
    <attribute name="RemoteAccess">true</attribute>
</mbean>

<!-- Bind the /usr/local file system directory  -->
<mbean code="org.jboss.naming.ExternalContext" 
       name="jboss.jndi:service=ExternalContext,jndiName=external/fs/usr/local">
    <attribute name="JndiName">external/fs/usr/local</attribute>
    <attribute name="Properties">local.props</attribute>
    <attribute name="InitialContext">javax.naming.IntialContext</attribute>
</mbean>

첫 번째 환경설정에서는 external/ldap/jboss 이름으로 JBoss JNDI 네임스페이스에 외부 LDAP 컨텍스트를 연결하고 있습니다. 예제 jboss.ldap 속성 파일은 다음과 같습니다:

java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url=ldap://ldaphost.jboss.org:389/o=jboss.org
java.naming.security.principal=cn=Directory Manager
java.naming.security.authentication=simple
java.naming.security.credentials=secret

이러한 설정으로 여러분은 다음과 같은 코드를 통해 JBoss VM내에서 ldap://ldaphost.jboss.org:389/o=jboss.org에 위치한 외부 LDAP 컨텍스트에 액세스할 수 있습니다:

InitialContext iniCtx = new InitialContext();
LdapContext ldapCtx = iniCtx.lookup("external/ldap/jboss");

이 경우에는 JBoss 서버 VM의 바깥쪽에서도 동일한 코드를 사용해도 동작하게 되는데, 그 이유는 RemoteAccess 속성이 true로 설정되어 있기때문입니다. 이 속성이 false로 설정되어있다면, 외부 IntialContext를 다시 생성시킬 수 없는 ObjectFactory를 갖는 Reference 객체를 원격 클라이언트가 수신받기 때문입니다.

두 번째 환경설정에서는 external/fs/usr/local 이라는 이름으로 JBoss JNDI 네임스페이스쪽에 /usr/local이라는 로컬 파일 시스템 디렉터리를 연결하고 있습니다. 예제 local.props 속성 파일은 다음과 같습니다:

java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory
java.naming.provider.url=file:///usr/local

위와 같은 환경설정하에서 여러분은 다음과 같은 코드를 사용하여 JBoss VM내부에서 file:///usr/local에 위치한 외부 파일 시스템 컨텍스트에 액세스할 수 있습니다:

InitialContext iniCtx = new InitialContext();
Context ldapCtx = iniCtx.lookup("external/fs/usr/local");

3.2.6.2. org.jboss.naming.NamingAlias MBean

NamingAlias MBean은 하나의 JNDI 이름을 다른 것으로 해주는 하나의 JNDI javax.naming.LinkRef 폼으로 별칭(alias)을 생성할 수 있도록 해주는 간단한 유틸리티 서비스입니다. 이것은 유닉스 파일 시스템에서의 심볼릭 링크와 유사합니다. 별칭이 가능하기위해서는 jboss-service.xml 환경 파일에 NamingAlias MBean에 대한 환경을 추가시켜야 합니다. NamingAlias 서비스의 설정 속성들은 다음과 같습니다:

다음의 예제에서는 QueueConnectionFactory라는 JNDI 이름을 ConnectionFactory 이름으로 매핑시키고 있습니다.

<mbean code="org.jboss.naming.NamingAlias" 
       name="jboss.mq:service=NamingAlias,fromName=QueueConnectionFactory">
    <attribute name="ToName">ConnectionFactory</attribute>
    <attribute name="FromName">QueueConnectionFactory</attribute>
</mbean>

3.2.6.3. org.jboss.naming.JNDIView MBean

JNDIView MBean은 사용자가 JMX 에이전트 뷰 인터페이스를 사용하여 JBoss 서버내에 존재하고 있는 JNDI 네임스페이스 트리를 볼 수 있도록 합니다. JNDI MBean을 사용하여 JBoss의 JNDI 네임스페이스를 보려면, http 인터페이스를 사용하여 JMX 에이전트 뷰를 연결해야 합니다. http://localhost:8080/jmx-console/라는 위치가 디폴트로 설정되어 있습니다. 이 페이지에서 여러분은 도메인으로 정렬된 등록된 MBean들의 항목이 있는 섹션을 찾을 수 있습니다. 이에 대한 화면은 그림 3.8, “설정된 JBoss MBean들의 JMX Console 뷰”처럼 보여질 것입니다.

설정된 JBoss MBean들의 JMX Console 뷰

그림 3.8. 설정된 JBoss MBean들의 JMX Console 뷰

JNDIView 링크를 선택하면 JNDIView MBean 오퍼레이션들의 목록을 갖는 JNDIView MBean 뷰가 나타납니다. 이것은 그림 3.9, “JNDI MBean의 JMX Console 뷰”처럼 보여지게 됩니다.

JNDI MBean의 JMX Console 뷰

그림 3.9. JNDI MBean의 JMX Console 뷰

list 오퍼레이션은 단순한 텍스트 뷰를 사용하여 하나의 html 페이지로써 JBoss 서버의 JNDI 네임스페이스를 덤프시킵니다. 그림 3.10, “JNDIView의 list 오퍼레이션에 의해 출력된 JMX 콘솔 뷰”는 list 오퍼레이션을 호출함으로써 만들어진 뷰의 화면입니다..

JNDIView의 list 오퍼레이션에 의해 출력된 JMX 콘솔 뷰

그림 3.10. JNDIView의 list 오퍼레이션에 의해 출력된 JMX 콘솔 뷰