Java IDL 입문 :Hello World 서버의 개발 - xrath.com 에서 번역됨

# Java IDL 입문:
Hello World 서버의 개발

여기서 소개하는 서버는, 서번트와 서버의 2 개의 클래스로 구성됩니다. 서번트인 `HelloImpl` 는,`Hello` IDL 인터페이스의 구현입니다. 즉,`Hello` 의 각 인스턴스는,`HelloImpl` 의 인스턴스에 의해 구현됩니다. 서번트는,`idlj` 컴파일러에 의해 예의 IDL 로부터 생성되는 `HelloPOA` 의 서브 클래스입니다.

서번트에게는, IDL 오퍼레이션 마다 1 개의 메소드가 포함됩니다. 이 예에서는,`sayHello()` 및 `shutdown()` 메소드입니다. 서번트 메소드는, Java 의 일반적으로의 메소드와 변화는 없습니다. ORB 의 처리, 인수나 결과의 정렬화등을 실시하는 코드는, 스켈리턴으로 구현합니다.

서버 클래스에는 서버의 `main()` 메소드가 포함됩니다. 이 `main()` 메소드에서는, 다음의 처리를 실시합니다.

- ORB 의 인스턴스를 생성해 초기화한다
- 루트 POA 의 참조를 취득해,`POAManager` 를 기동한다
- 서번트의 인스턴스 (1 개의 CORBA `Hello` 객체의 구현)를 생성해, 그것을 ORB 에게 전한다
- 새로운 CORBA 객체를 네이밍 문맥에 등록하기 위해(때문에), CORBA 객체의 객체 참조를 취득한다
- 루트의 네이밍 문맥을 취득한다
- 새로운 객체를 「Hello」라고 하는 이름으로 네이밍 문맥에 등록한다
- 클라이언트로부터 새로운 객체가 불려 가는 것을 기다린다

이 레슨에서는, CORBA 서버 작성의 기본을 배웁니다. 지속 객체 서버를 사용하는 「Hello World」프로그램의 예에 대해서는,「예 2:지속성을 갖춘 Hello World」 를 참조해 주세요. CORBA 서버의 상세한 것에 대하여는,「서버의 개발」 을 참조해 주세요.

이 레슨의 순서는 다음과 같습니다.

1. HelloServer.java 의 생성
2. HelloServer.java 의 이해
3. Hello World 서버의 컴파일

## HelloServer.java 의 생성

`HelloServer.java` 를 생성하려면 , 다음과 같이 합니다.

1. 텍스트 문자 편집기를 기동해,`HelloServer.java` 라는 이름의 파일을 메인 프로젝트 디렉토리의 `Hello` 에 작성합니다.

2. `HelloServer.java` 의 다음의 코드를 텍스트 파일에 기술합니다. 코드의 각 행의 상세한 것에 대하여는, 다음의「HelloServer.java 의 이해」로 설명합니다.

       // HelloServer.java
       // Copyright and License
       import HelloApp. *;
       import org.omg.CosNaming. *;
       import org.omg.CosNaming.NamingContextPackage. *;
       import org.omg.CORBA. *;
       import org.omg.PortableServer. *;
       import org.omg.PortableServer.POA;

       import java.util.Properties;

       class HelloImpl extends HelloPOA {
         private ORB orb;

         public void setORB(ORB orb_val) {
           orb = orb_val;
         }

         // implement sayHello() method
         public String sayHello() {
           return "\nHello world !!\n";
         }

         // implement shutdown() method
         public void shutdown() {
           orb.shutdown(false);
         }
       }

       public class HelloServer {

         public static void main(String args[]) {
           try{
             // create and initialize the ORB
             ORB orb = ORB.init(args, null);

             // get reference to rootpoa & activate the POAManager
             POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
             rootpoa.the_POAManager(). activate();

             // create servant and register it with the ORB
             HelloImpl helloImpl = new HelloImpl();
             helloImpl.setORB(orb);

             // get object reference from the servant
             org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
             Hello href = HelloHelper.narrow(ref);

             // get the root naming context
             org.omg.CORBA.Object objRef =
                 orb.resolve_initial_references("NameService");
             // Use NamingContextExt which is part of the Interoperable
             // Naming Service (INS) specification.
             NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

             // bind the Object Reference in Naming
             String name = "Hello";
             NameComponent path[] = ncRef.to_name( name );
             ncRef.rebind(path, href);

             System.out.println("HelloServer ready and waiting ...");

             // wait for invocations from clients
             orb.run();
           }

             catch (Exception e) {
               System.err.println("ERROR: " + e);
               e.printStackTrace(System.out);
             }

             System.out.println("HelloServer Exiting ...");

         }
       }

3. `HelloServer.java` 를 보존해 닫습니다.

## HelloServer.java 의 이해

여기에서는,`HelloServer.java` 의 각 행에 대해, 코드가 무엇을 하고 있는지, 또 이 어플리케이션으로 왜 필요한가에 임해서 설명합니다.

### 기본 설정

CORBA 서버 프로그램의 구조는, 대부분의 Java 어플리케이션과 같습니다. 즉, 필요한 라이브러리 패키지를 임포트 해, 서버 클래스를 선언해,`main()` 메소드를 정의해, 예외의 처리를 실시합니다.

#### 필요한 패키지의 임포트

우선, 서버 클래스에 필요한 패키지를 임포트 합니다.

    // The package containing our stubs
    import HelloApp. *;

    // HelloServer will use the naming service
    import org.omg.CosNaming. *;

    // The package containing special exceptions thrown by the name service
    import org.omg.CosNaming.NamingContextPackage. *;

    // All CORBA applications need these classes
    import org.omg.CORBA. *;

    // Classes needed for the Portable Server Inheritance Model
    import org.omg.PortableServer. *;
    import org.omg.PortableServer.POA;

    // Properties to initiate the ORB
    import java.util.Properties;

#### 서번트 클래스의 정의

이 예에서는,`HelloServer.java` 내의 `HelloServer` 클래스의 외측에, 서번트 객체의 클래스를 정의하고 있습니다.

    class HelloImpl extends HelloPOA
    {
      // The sayHello() and shutdown() methods go here.
    }

이 서번트는 `HelloPOA` 의 서브 클래스이므로, 컴파일러가 HelloPOA 를 위해서(때문에) 생성한 범용의 CORBA 기능을 상속합니다.

우선,`setORB(ORB)` 메소드로 사용되는 프라이빗 변수 `orb` 를 작성합니다. `setORB` 메소드는, 서번트에게 ORB (값)를 설정할 수 있도록(듯이) 어플리케이션 개발자에 의해 정의되는 어플리케이션 고유의 메소드입니다. 이 ORB 치는, 클라이언트로부터의 `shutdown()` 메소드의 호출에 응해, 고유의 ORB 상에서 `shutdown()` 를 호출하기 위해서(때문에) 사용됩니다.

      private ORB orb;

      public void setORB(ORB orb_val) {
        orb = orb_val;
      }

다음에, 필요한 `sayHello()` 메소드를, 선언해 구현합니다.

      public String sayHello()
      {
        return "\nHello world!!\n";
      }

마지막으로,`shutdown()` 메소드를 같은 방법으로 구현합니다. `shutdown()` 메소드는, ORB 용으로 `org.omg.CORBA.ORB.shutdown(boolean)` 메소드를 호출합니다. `shutdown(false)` 오퍼레이션은, ORB 가 처리의 완료를 기다리지 않고 , 곧바로 종료 할 필요가 있는 것을 지시합니다.

      public void shutdown() {
        orb.shutdown(false);
      }

#### 서버 클래스의 선언

다음에, 서버 클래스를 선언합니다.

    public class HelloServer
    {
      // The main() method goes here.
    }

#### main() 메소드의 정의

모든 Java 어플리케이션에는 `main` 메소드가 필요합니다. 이 메소드를 다음과 같이,`HelloServer` 클래스의 스코프내에서 선언합니다.

      public static void main(String args[])
      {
        // The try-catch block goes here.
      }

#### CORBA 시스템 예외의 처리

어느 CORBA 프로그램에서도, 실행시에 CORBA 시스템 예외가 발생할 가능성이 있으므로,`main()` 메소드의 기능은, 모두 try-catch 블록내에 기술합니다. CORBA 프로그램은, 호출에 수반하는 프로세스 (정렬화, 비정렬화, 업 콜)로 문제가 발생하면(자), 시스템 예외를 발생시킵니다. 이 레슨의 예외 핸들러는 간단한 것으로, 어떤 문제가 일어났는지를 알 수 있도록(듯이), 예외의 이름과 그 스택 트레이스를 표준 출력에 출력합니다.

`main()` 안에, 다음의 try-catch 블록을 기술합니다.

        try{

          // The rest of the HelloServer code goes here.

        } catch(Exception e) {
            System.err.println("ERROR: " + e);
            e.printStackTrace(System.out);
          }

### ORB 객체의 생성 및 초기화

CORBA 서버에는, CORBA 클라이언트와 같게 로컬 ORB 객체가 필요합니다. 각 서버는 ORB 의 인스턴스를 생성해, 그것이 호출을 받았을 때에 서버를 검색할 수 있도록(듯이), 그 서번트 객체를 등록합니다.

try-catch 블록 중(안)에서, ORB 변수를 선언해 초기화합니다.

          ORB orb = ORB.init(args, null);

ORB 의 `init()` 메소드의 호출은, 서버의 커멘드행 인수에게 건네지므로, 실행시에 특정의프로퍼티을 설정할 수 있습니다.

### 루트 POA 에의 참조의 취득 및 `POAManager` 의 활성화

ORB 는,`resolve_initial_references` 메소드를 사용하는 네임 서비스등의 초기적인 서비스에의 객체 참조를 가져옵니다.

루트 POA 에의 참조가 취득되어`POAManager` 가 try-catch 블록 중(안)에서 활성화 합니다.

          POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
          rootpoa.the_POAManager(). activate();

`activate()` 오퍼레이션은, POA 매니저 상태를 액티브하게 변경합니다. 그 결과, 관련지을 수 있었던 POA 는 요구의 처리를 개시합니다. POA 매니저는, 관련지을 수 있고 있는 POA 의 처리 상태를 캡슐화합니다. 각 `POA` 객체에는, 1 개의 `POAManager` 객체를 관련지을 수 있고 있습니다. POA 매니저는, 1 개(살) 이상의 POA 객체에 관련지을 수 있고 있는 일이 있습니다.

### 서번트 객체의 관리

서버란,1 개(살) 이상의 서번트 객체의 인스턴스를 생성하는 프로세스입니다. 서번트는,`idlj` 가 생성한 인터페이스로부터 상속해, 그 인터페이스상에서 실제의 오퍼레이션을 실시합니다. 이 레슨의 `HelloServer` 에는 1 개의 `HelloImpl` 가 필요합니다.

#### 서번트 객체의 인스턴스의 생성

다음과 같이, POA 매니저를 기동한 직후에, try-catch 블록 중(안)에서 서번트 객체의 인스턴스를 생성합니다.

          HelloImpl helloImpl = new HelloImpl();

서번트 클래스를 기술하는 코드에 대해서는, 이미 설명되고 있습니다.

다음의 코드행은,`ORB.shutdown()` 를 종료 오퍼레이션의 일부로서 호출할 수 있도록(듯이) 하기 위한(해),`setORB(orb)` 는 서번트로 정의되고 있습니다. 이 순서가 필요한 것은,`shutdown()` 메소드가 `Hello.idl` 에 정의되고 있기 때문입니다.

          helloImpl.setORB(orb);

종료 오퍼레이션의 구현에는, 다른 방법도 있습니다. 이 예에서는,`Object` 상에서 불려 간 `shutdown()` 메소드는, ORB 의 종료을 실시합니다. 다른 구현예에서는, 종료 메소드의 구현은 플래그를 설정하는 것만으로 끝납니다. 서버가 플래그를 확인해 `shutdown()` 를 호출합니다.

다음의 일련의 코드는, 서번트가 관련지을 수 있었던 객체 참조의 취득에 사용됩니다. `narrow()` 메소드는, CORBA 객체 참조를 적절한 형태로 변환하기 위해서(때문에) 필요합니다.

          org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
          Hello href = HelloHelper.narrow(ref);

### COS 네이밍의 이용

`HelloServer` 는 COS (Common Object Services) 네임 서비스를 이용해, 클라이언트측으로부터 서번트 객체의 오퍼레이션을 이용 가능하게 합니다. 서버는, 다양한 인터페이스를 구현하고 있는 객체의 참조를 발행할 수 있도록(듯이) 하기 위한(해), 네임 서비스에의 객체 참조가 필요합니다. 이러한 객체 참조는, 클라이언트가 메소드를 호출하는데 사용됩니다. 서번트가 객체를 클라이언트측에서 호출하게 할 수가 있도록(듯이) 하는 이제(벌써) 1 개의 방법은, 파일에의 객체 참조를 캐릭터 라인화하는 것입니다.

J2SE v1. 4 에 부속되어 있는 네임 서비스에는, 다음의 2 개의 옵션이 있습니다.

- `orbd` - 서버 매니저 외에, 일시 네임 서비스와 지속 네임 서비스도 포함한다
- `tnameserv` - 일시 네임 서비스

이 예에서는 `orbd` 를 사용합니다.

#### 초기 네이밍 문맥의 취득

try-catch 블록 중(안)에서, 서번트의 객체 참조를 취득하면(자), 다음에 `orb.resolve_initial_references()` 를 호출해 네임서버-에의 객체 참조를 가져옵니다.

          org.omg.CORBA.Object objRef =
              orb.resolve_initial_references("NameService");

캐릭터 라인 「NameService」는, 모든 CORBA ORB 에 대해서 정의되고 있습니다. 이 캐릭터 라인을 건네주면(자), ORB 는 네임 서비스에의 객체 참조인 네이밍 문맥 객체를 돌려줍니다. 캐릭터 라인 NameService 는, 다음 일을 나타내고 있습니다.

- 이 예의 같게 ORBD 의 네임 서비스를 사용할 때는, 지속 네임 서비스가 된다
- `tnameserv` 를 사용할 때는, 일시 네임 서비스가 된다

독자적인 캐릭터 라인 TNameService 는, ORBD 의 네임 서비스를 사용할 때는, 일시 네임 서비스가 되는 것을 나타내고 있습니다.

#### 객체 참조의 네로우 변환

CORBA 목의 객체 참조와도 같이`objRef` 는 범용의 CORBA 객체입니다. 이것을 `NamingContextExt object` 로서 사용하려면 , 적절한 형태에 네로우 변환할 필요가 있습니다. `narrow()` 의 호출은, 전의 문장의 직후에 있습니다.

          NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

이것은,`idlj` 로부터 생성되는 헬퍼 클래스의 사용 방법입니다. 그것들은 `HelloHelper` 에 기능적으로 유사하고 있습니다. 여기서 `ncRef` 객체는 `org.omg.CosNaming.NamingContextExt` 가 되었으므로, 다음의 스텝에서 지시받도록(듯이), 이것을 사용해 네임 서비스에 액세스 해, 서버를 등록할 수가 있습니다.

`NamingContextExt 객체` 는, J2SE v1. 4 로 새롭게 추가된 것으로,Interoperable Naming Service 의 스펙의 일부입니다.

#### 네임서버-에의 서번트의 등록

`narrow()` 의 호출의 직후에, 새로운 `NameComponent` 배열을 작성합니다. `NamingContext.resolve` 에는 작업용에 배열이 필요합니다. `Hello` 객체에의 패스에는 요소가 1 개 밖에 없기 때문에, 단일 요소의 배열을 작성합니다.

          String name = "Hello";
          NameComponent path[] = ncRef.to_name( name );

`path` 와 서번트 객체를 네임 서비스에 인도해, 서번트 객체를 「Hello」id 에 묶습니다.

          ncRef.rebind(path, href);

이것으로, 클라이언트가 초기 네이밍 문맥으로 `resolve("Hello")` 를 호출하면(자), 네임 서비스로부터 `Hello` 서번트에게로의 객체 참조가 돌려주어집니다.

### 호출해 대기

전의 마디에서는, 서버를 준비하기 위한 코드의 설명을 했습니다. 다음의 마디에서는, 클라이언트가 서비스를 요구하는 것을 기다리는 코드에 대해 설명합니다. try-catch 블록내의 마지막에 있는 다음의 코드는, 이것을 실행하기 위한의 것입니다.

          orb.run();

`ORB.run()` 는, 메인 thread에 의해 불려 가면(자), ORB 가 그 메인 thread를 사용해 동작할 수 있게 되기 (위해)때문에, ORB 로부터의 호출을 받을 때까지 대기합니다. 호출은 `main()` 의 try-catch 블록안에 있으므로 , 호출이 종료해 `sayHello()` 가 복귀한 후, 서버는 다시 호출해 기다리러 돌아옵니다. 태스크의 종료후에 `HelloClient` 가 명시적으로 ORB 를 종료 하는 것은 이 때문에입니다.

## Hello World 서버의 컴파일

여기서 `HelloServer.java` 를 컴파일 해, 에러를 수정하고 나서 레슨을 계속합니다.

Windows 의 사용자는, 이 메뉴얼의 패스의 slash (/)를 backslash (\)에 옮겨놓아 주세요.

`HelloServer.java` 를 컴파일 하려면 , 다음과 같이 합니다.

1. `Hello` 디렉토리에 이동합니다.

2. `HelloServer.java` 에 대해서 Java 컴파일러를 실행합니다.

       javac HelloServer.java HelloApp/*.java

3. 파일에 에러가 있으면, 수정해 컴파일 다시 합니다.

4. `HelloServer.class` 와 `HelloImpl.class` 파일은,`Hello` 디렉토리내에 생성됩니다.

### Hello World 서버의 실행

문서「Hello World 어플리케이션의 실행」에서는,`HelloServer` 와 나머지의 어플리케이션의 실행에 대해 말하고 있습니다.

# 서버측의 구현 모델의 이해

CORBA 는 IDL 인터페이스를 구현하는 서버측 매핑 가운데, 적어도 다음의 2 종류를 지원하고 있습니다.

- 상속 모델

  상속 모델을 사용해, 컴파일러가 작성한 스켈리턴의 확장도 실시하는 구현 클래스를 사용해, IDL 인터페이스를 구현합니다.

  상속 모델에게는, 다음의 것이 포함되어 있습니다.

  - OMG 표준의 POA. `My.idl` 내에서 `My` 인터페이스가 정의되고 있는 경우는,`idlj` 컴파일러로 `MyPOA.java` 라고 하는 파일이 생성됩니다. `My` 에 구현을 제공할 필요가 있어, 그것은 `MyPOA` 를 상속하고 있을 필요가 있습니다. 이것은 스트림 베이스의 스켈리턴으로,`org.omg.PortableServer.Servant` 를 확장한 것이어, 모든 POA 서번트 구현의 base class가 되어 있습니다.

    J2SE v1. 4 의 신기능:`-fall` 또는 `-fserver` 의 어느 쪽인가의 인수가 사용될 때 생성되는 디폴트의 서버측 매핑은, CORBA 2.3. 1 스펙의 제 11 장 「POA (Portable Object Adapter)」(formal/99-10-07 )에 준거하고 있습니다. POA 의 상세한 것에 대하여는,「Portable Object Adapter」 를 참조해 주세요.

    POA (Portable Object Adaptor)를 사용하는 이점은, 다음과 같습니다.

    - 프로그래머가, 다른 ORB 제품간에 이식 가능한 객체 구현을 구축할 수 있도록(듯이) 한다
    - 지속성이 있는 식별 정보를 가지는 객체를 지원한다
    - 객체가 투과적으로 기동하도록(듯이) 지원한다
    - 단독의 서번트가 각각 식별되는 복수의 객체를 동시에 지원할 수 있도록(듯이) 한다

  - ImplBase. `My.idl` 내에서 `My` 인터페이스가 정의되고 있는 경우는,`_MyImplBase.java` 라고 하는 파일이 생성됩니다. `My` 에 대해서 그 구현을 제공해, 이 구현은 `_MyImplBase` 로부터 상속하지 않으면 안됩니다.

    주: ImplBase 는 POA 모델이 있으므로 추천 되지 않습니다만, 버젼 1.3 이전의 J2SE 로 기술된 서버와 호환성을 가지기 위해서(때문에) 제공되고 있습니다. 이것은 비표준 모델이므로, 이것을 사용해 새로운 서버를 작성하는 것은 추천하지 않습니다.

- 위양 모델

  위양 모델을 사용해, 다음의 2 개의 클래스를 사용해 IDL 인터페이스를 구현합니다.

  - IDL 로 생성된 Tie 클래스. 컴파일러로 생성된 스켈리턴으로부터 상속됩니다만, 호출은 모두 구현 클래스에 위양 됩니다.
  - IDL 가 생성한 오퍼레이션 인터페이스 (`HelloOperations` 등)를 구현하는 클래스에서, 그것은 IDL 함수를 정의합니다.

  위양 모델은,Tie 모델이나 Tie 위양 모델로서도 알려져 있습니다. 이 모델은 POA 또는 ImplBase 컴파일러로 작성된 스켈리턴의 어느 쪽인지를 상속하므로, 이 문서에서는 POA/Tie 또는 ImplBase/Tie 모델과 같이 기술됩니다.

이 튜토리얼에서는, 서버측 구현의 POA 상속 모델을 취급합니다. 다른 서버측 구현을 사용하는 튜토리얼은, 다음의 문서를 참조해 주세요.

- Java IDL:POA/Tie 서버측 모델을 사용한 「Hello World」의 예

  다른 구현으로부터 상속해야 하는 경우, 표준의 상속 모델은 아니고 Tie 모델을 사용하는 일이 있습니다. Java 의 경우는, 인터페이스의 상속의 개수에 제한은 없습니다만, 클래스의 상속에 사용할 수 있는 슬롯은 1 개 뿐입니다. 상속 모델을 사용했을 경우는, 그 슬롯이 점유 됩니다. Tie 모델을 사용했을 경우는, 그 슬롯이 사용되지 않고, 사용자가 독자적인 목적으로 사용할 수가 있습니다. 다만, 간접 참조의 레벨이 1 개 도입된다고 하는 결점이 있습니다. 즉, 메소드를 호출할 때 여분의 메소드 호출이 발생합니다.

- Java IDL:ImplBase 서버측 모델을 사용한 「Hellow World」의 예

  ImplBase 서버측의 모델은, POA 모델과 같이 상속 모델입니다. `idlj` 컴파일러에 의해,`-oldImplBase` 플래그를 사용해 J2SE 1.4 이전의 버젼의 Java IDL 와 호환성이 있는 서버측 바인딩을 생성합니다.

  `-oldImplBase` 플래그를 사용하는 것은 일반적이지는 않습니다. 이러한 API 는 추천 되고 있지 않습니다. 이 플래그를 사용하는 것은, J2SE 1.3 이전에 쓰여진 기존의 서버와의 호환성을 취하는 경우만입니다. 그 경우, 기존의 MAKEFILE 를 변경해 `idlj` 컴파일러에 `-oldImplBase` 플래그를 추가할 필요가 있습니다. 플래그를 추가하지 않는 경우, POA 베이스의 서버측 매핑이 생성됩니다.

## 상세 정보

예외:시스템 예외
  CORBA 의 시스템 예외의 동작과 Java IDL 의 시스템 예외의 마이너 코드의 상세한 설명
서버의 개발
  CORBA 서버의 프로그래밍에 관한 문제
Java IDL 네임 서비스
  COS 네임 서비스의 상세한 설명

전의 레슨:인터페이스 정의의 기술
다음의 레슨:클라이언트 어플리케이션의 개발
튜토리얼의 홈

Java IDL 탑에

Copyright © 1996-2001 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn.View, CA. 94043-1100 USA., All rights reserved.