부가 기능

본 장에서는 JEUS에서 EJB를 개발할 때 사용할 수 있는 부가 기능들에 대해 설명한다.

1. WorkArea 서비스

WorkArea 서비스는 프로그램이 어떤 묵시적(implicit)인 컨텍스트를 계속 전달할 때 사용할 수 있는 기능이다. 마치 Security 컨텍스트나 트랜잭션 컨텍스트와 같이 별도의 인자로 전달하지 않아도 로컬 또는 원격 메소드를 호출할 때 계속 전달된다. 어떤 컨텍스트를 전달해야 하는 경우나 메소드의 인자수가 많아지는 경우에 WorkArea를 사용할 수 있다.

WorkArea는 일종의 사용자 저장 공간으로 name-value pair 형태의 맵(Map)으로 저장된다. WorkArea를 새로 시작하면 현재의 스레드와 함께 이동하기 때문에 호출된 메소드나 EJB와 같은 컴포넌트에서 계속 사용할 수가 있다. 또한, 원격 EJB를 호출하는 경우에도 전달(propagation)되는 특성이 있다.

WorkArea 서비스를 이용하기 위해 UserWorkArea 인터페이스인 jeus.workarea.UserWorkArea를 사용한다.

  1. 자세한 API 정보는 JEUS API Javadoc 문서의 jeus.workarea 패키지를 참조한다.

  2. 현재 원격 WorkArea 전달(propagation) 기능은 EJB 2.0과 3.0 모두 지원한다. JEUS 기본 RMI 호출이 아닌 IIOP를 사용하는 경우에도 전달된다. 호출을 하는 경우에는 전달되지 않는다.

1.1. UserWorkArea 인터페이스

UserWorkArea 인터페이스는 UserWorkArea의 시작, 종료 및 각 조작에 필요한 모든 메소드를 정의하며 다음과 같다.

UserWorkArea 인터페이스
public interface UserWorkArea {
   public void begin(String name);
   public void complete()
          throws NoWorkAreaException, NotOriginatorException;
   public String getName();
   public String[] retrieveAllKeys();
   public void set(String key, java.io.Serializable value)
          throws NoWorkAreaException, NotOriginatorException,
                 PropertyReadOnlyException;
   public void set(String key, java.io.Serializable value, PropertyModeType mode)
          throws NoWorkAreaException, NotOriginatorException,
                 PropertyReadOnlyException;
   public java.io.Serializable get(String key);
   public PropertyModeType getMode(String key);
   public void remove(String key)
          throws NoWorkAreaException, NotOriginatorException,
                 PropertyReadOnlyException;
}

메소드 정의에 대한 자세한 정보는 Javadoc을 참고한다.

1.2. PropertyMode 타입

WorkArea에 저장되는 값들은 각각의 PropertyMode를 갖는다.

각 PropertyMode 타입은 다음과 같다.

타입 설명

NORMAL

등록된 값에 대해 수정과 삭제가 모두 가능하다.

READ_ONLY

UserWorkArea에 등록된 값에 대해 수정과 삭제가 모두 불가능하다.

1.3. 예외

UserWorkArea에서 정의된 예외는 다음과 같다.

예외 설명

WorkAreaException

WorkArea에서 발생하는 Exception의 최상위 Exception이다.

NotOriginatorException

작업 영역을 시작한 스레드가 아닐 경우 값을 수정하거나 삭제 또는 작업 영역을 닫으려고 할 경우 발생한다.

PropertyReadOnlyException

PropertyMode가 READ_ONLY로 설정된 값을 변경하는 경우 발생한다.

1.4. Nested UserWorkArea

UserWorkArea는 중첩되어 사용될 수 있다. 이미 UserWorkArea가 존재하는 상황에서 새로운 UserWorkArea를 시작하면 그 UserWorkArea는 기존 UserWorkArea에 내포되게 된다.

내포된 UserWorkArea는 상위 UserWorkArea에 저장된 값들을 그대로 이용할 수 있으며 새로운 값들을 추가할 수 있다. 내포된 UserWorkArea에서 추가된 값들은 단지 그 UserWorkArea에서만 값을 갖게 되며 내포된 UserWorkArea가 완료되면 사라진다.

중첩된 UserWorkArea에서의 등록 정보는 다음 그림과 같다.

figure user workarea nested
중첩된 UserWorkArea에서의 등록 정보

1.5. UserWorkArea를 사용하는 응용 프로그램 개발

본 절에서는 실제로 UserWorkArea를 사용하는 EJB 예제를 작성하며 UserWorkArea 인터페이스를 사용하는 방법을 설명한다.

EJB 예제는 UserWorkAreaSampleSender와 UserWorkAreaSampleReceiver 2개의 EJB로 이루어져 있다. Sender에서 UserWorkArea를 생성하여 데이터를 전달하고, Receiver에서 UserWorkArea에 설정된 값을 이용하여 메시지를 생성하여 원래 Sender에서 리턴하는 예제로 과정은 다음과 같다.

  1. UserWorkArea 액세스

    UserWorkArea를 사용하기 위해서는 먼저 JNDI에서 UserWorkArea를 lookup해야 한다.

    다음은 JNDI에서 UserWorkArea를 lookup하는 방법에 대한 예이다.

    UserWorkArea 액세스 : <UserWorkAreaSampleSenderBean.java>
    public class UserWorkAreaSampleSenderBean implements UserWorkAreaSampleSender {
        public String getMessage() {
            InitialContext ic;
            String message = null;
            try {
               ic = new InitialContext();
               //UserWorkArea를 JNDI에서 가져온다.
               UserWorkArea userWorkArea
                 = (UserWorkArea) ic.lookup("java:comp/UserWorkArea");
            } catch (NamingException e) {
                // Do Something...
            }
            return message;
        }
    }
  2. 새 UserWorkArea 시작

    JNDI에서 처음 lookup해온 UserWorkArea는 아무런 정보가 없기 때문에 새로운 UserWorkArea를 시작해야 한다. 만약, UserWorkArea의 이름이 null이면 NullPointException이 발생한다.

    새 UserWorkArea 시작 : <UserWorkAreaSampleSenderBean.java>
    public class UserWorkAreaSampleSenderBean implements UserWorkAreaSampleSender {
        public String getMessage() {
            InitialContext ic;
            String message = null;
            try {
              ic = new InitialContext();
              UserWorkArea userWorkArea
                = (UserWorkArea) ic.lookup("java:comp/UserWorkArea");
              // 새로운 UserWorkArea를 시작한다.
              userWorkArea.begin("UserWorkArea1");
            } catch (NamingException e) {
                // Do Something...
            }
            return message;
        }
    }
  3. WorkArea에 등록 정보 설정

    새로 시작한 UserWorkArea에 등록 정보를 설정한다. 등록 정보는 <key, value, mode>로 이루어진다. 'key’는 String이며 'value’는 직렬화(Serialization)가 가능한 객체이다.

    값을 설정할 때 현재 UserWorkArea가 없으면 NoWorkAreaException이 발생한다. 시작한 UserWorkArea가 아니면 NotOriginatorException이 발생하며, 이미 READ_ONLY로 설정된 값을 수정할 경우 PropertyReadOnlyException이 발생한다.

    WorkArea에 등록 정보 설정 : <UserWorkAreaSampleSenderBean.java>
    public class UserWorkAreaSampleSenderBean implements UserWorkAreaSampleSender {
        public String getMessage() {
            InitialContext ic;
            String message = null;
            try {
                ic = new InitialContext();
                UserWorkArea userWorkArea
                  = (UserWorkArea) ic.lookup("java:comp/UserWorkArea");
                userWorkArea.begin("UserWorkArea1");
                // userWorkArea에 값을 NORMAL로 설정한다.
                userWorkArea.set("name", "johan");
                // userWorkArea에 값을 READ_ONLY로 설정한다.
                userWorkArea.set("company", "TmaxSoft", PropertyModeType.READ_ONLY);
                UserWorkAreaSampleReceiver receiver
                  = (UserWorkAreaSampleReceiver) ic.lookup("receiver");
                message = receiver.createMessage();
            } catch (NamingException e) {
                // Do Something...
            } catch (NoWorkAreaException e) {
                // Do Something...
            } catch (PropertyReadOnlyException e) {
                // Do Something...
            } catch (NotOriginatorException e) {
                // Do Something...
            }
    
            return message;
        }
    }
  4. WorkArea에 설정된 등록 정보 가져오기

    Receiver에서 전파된 UserWorkArea에서 설정된 등록 정보를 가져와 메시지를 생성한다. 저장된 정보를 가져올 때 UserWorkArea에 존재하지 않는 key를 사용하면 null이 리턴된다.

    WorkArea에 설정된 등록 정보 가져오기 : <UserWorkAreaSampleReceiverBean.java>
    public class UserWorkAreaSampleReceiverBean implements UserWorkAreaSampleReceiver {
        public String createMessage() {
            InitialContext ic;
            String message = null;
            try {
                ic = new InitialContext();
                UserWorkArea userWorkArea
                  = (UserWorkArea) ic.lookup("java:comp/UserWorkArea");
                // UserWorkArea에 저장한 값을 가져온다.
                String name = (String)userWorkArea.get("name");
                String company = (String)userWorkArea.get("company");
                message = "Hello " + name + " from " + company;
    
            } catch (NamingException e) {
                // Do Something...
            }
    
            return message;
        }
    }
  5. UserWorkArea 완료하기

    시작한 UserWorkArea를 완료한다. 완료하는 것은 반드시 시작된 Originator에서만 가능하며 그 이외에서 완료하려면 NotOriginatorException이 발생한다.

    UserWorkArea 완료하기 : <UserWorkAreaSampleSenderBean.java>
    public class UserWorkAreaSampleSenderBean implements UserWorkAreaSampleSender {
        public String getMessage() {
            InitialContext ic;
            String message = null;
            try {
                ic = new InitialContext();
                UserWorkArea userWorkArea
                  = (UserWorkArea) ic.lookup("java:comp/UserWorkArea");
                userWorkArea.begin("UserWorkArea1");
                userWorkArea.set("name", "user1");
                userWorkArea.set("company", "TmaxSoft", PropertyModeType.READ_ONLY);
                UserWorkAreaSampleReceiver receiver
                  = (UserWorkAreaSampleReceiver) ic.lookup("receiver");
                message = receiver.createMessage();
                userWorkArea.complete(); // UserWorkArea를 종료한다.
    
            } catch (NamingException e) {
                // Do Something...
            } catch (NoWorkAreaException e) {
                // Do Something...
            } catch (PropertyReadOnlyException e) {
                // Do Something...
            } catch (NotOriginatorException e) {
                // Do Something...
            }
    
            return message;
        }
    }