JAX-RPC 는 Java API for XML-based Remote Procedural Calls이다. 몇 년이 지나긴 했지만 즉시 acronym RPC를 떠올릴 수도 있다. RPC(Remote Procedural Call)는 한 시스템의 컴포넌트가 네트워크를 통해 리모트 시스템의 컴포넌트에게 메시지를 전달할 때 일어난다. 이 장거리 커뮤니케이션 기술과 EJB(Enterprise JavaBeans),JMX(Java Management eXtensions ), RMI(Java Remote Method Invocation) APIs 핵심과는 매우 가까운 관계가 있다.

EJB, JMX, RMI와 달리 JAX-RPC는 .NET 같은 자바 활용 플랫폼이 아닌 곳에서 컴포넌트를 호출할 수 있으며, 이는 데이터 전송 매커니즘이 XML이기 때문에 가능하다. Java와 .NET 연산 플래폼 간의 연계를 위한 움직임은 WS-I 또는 WebServices Interoperability(웹서비스 호환성)로 불리고 있다. WS-I는 W3C (World Wide Web Consortium)로 제어되며 XML-RPC 를 구축하기 위하여 XML, HTTP, SOAP, MIME , WSDL (Web Services Definition Language) 같은 다른 W3C 기술의 호스트를 결합시킨다. W3C에 의해 유지되는 관계로 표준 XML-RPC는 충분히 플랫폼-중립적이어서 Java와 .net이 밀접하게 호환되도록 시스템이 설계되는 것이 가능하다.

JAX-RPC는 SOAP 1.1 와 WSDL 1.1의 자바 표준 구현이다. JAX-RPC를 이해하기 위해서는 WSDL 또한 이해해야 한다. WSDL은 단지 웹서비스의 스트럭처와 비헤이비어를 서술하는 전문화된 XML 언어일 뿐이므로 걱정하지말기 바란다. 웹서비스에서의 WSDL 파일은 Enterprise JavaBean 컴포넌트에서의 디플로이먼트 디스크립터와 같은 역할을 한다, 이 둘은 컨테이너 내부에서 컴포넌트 스터브를 생성하는 데 사용하는 인터페이스와 오브젝트 구현을 XML 의미로 서술한다. WSDL 파일은 또한 외부로 통하는 포트와 웹 서비스를 전달하는 전송 프로토콜을 규정한다.

전송상의 데이터가 XML로 캡슐화되어있기 때문에 서로 다른 플랫폼의 클라이언트들에는 원격 서비스와 커뮤니케이션하는 표준 방식이 있다. XML과 원시 언어 또는 복잡한 데이터 간의 모든 플랫폼 지정 데이터의 변환은 JAX-RPC 컨테이너에 의해 자동적으로 핸들링된다. 또한 JAX-RPC는 포트 80을 통해 커뮤니케이션을 허용하는 전송 프로토콜로 HTTP를 사용해서 SOAP를 호출할 수 있다. 이것은 JAX-RPC 웹서비스가 Tomcat과 같은 웹서비스를 제공하는 서블렛 컨테이너의 다른 애플리케이션 컴포넌트 같이 구동할 수 있다는 것을 의미한다.

웹서비스 분석

웹서비스가 어떻게 구축되는 지 알기 위한 첫번째 단계는 WSDL 용어를 이해하는 것이다. 이 언어는 웹서비스 컨셉에 관해 높은 단계의 "분석적인 참조"가 된다. 추상성이 증가되는 순서대로 각각의 용어에 대해서 알아보자.

  • 타입(type)은 Java 타입을 서술한다. wsdl:types 요소는 간단한 표준 XML 타입이나 좀 더 복잡한 타입을 표현할 수 있는 XML 정의를 포함한다.
  • 메시지(message)는 이름과 타입 매개변수를 매핑하는 부분들로 구성되어 있다.
  • 연산(operation)은 Java에서 메서드를 서술한다. 연산은 매개변수를 서술하는 입력 메시지와 Java 메서드의 리턴된 타입을 서술하는 출력 메시지로 구축된다.
  • 포트타입(port type)은 SEI(Service Endpoint Interface)를 캡슐화하고 정의한다. 포트 타입은 연산을 위해 SEI의 메서드를 매핑한다.
  • 바인딩(binding)은 포트 타입을 특정 프로토콜에 매핑한다. 이 매핑이 포트 타입의 비헤이비어로 대체될 수 있기 때문에 바인딩은 주어진 포트 타입의 지정 프로토콜 비헤이비어를 기술하기도 한다. 예를 들어 SOAP 프로토콜을 통해 포트타입을 호출하면 HTTP로 같은 포트 타입을 호출한 것과는 다른 비헤이비어가 생성된다. (예를 들어 SOAP 프로토콜을 통해 호출된 포트타입의 비헤이비어는 HTTP로 같은 포트 타입을 호출했을 때와 다르다.) SOAP의 경우에 하나 이상의 오류 정의는 이 바인딩으로 포트 타입에 매핑될 것이다.
  • 포트(port)는 URL과 같은 특정 공개 주소로 바인딩을 매핑한다.
  • 서비스(service)는 포트들의 모음을 캡슐화한다.

따라서 WSDL에서의 웹서비스는 실제로 공개적으로 접근 가능한 포트와 포트 타입 연산 간의 프로토콜 바인딩 모음인 것이다. 이에 대한 친숙한 예로, J2EE에서 서블렛 컨테이너의 URL과 Service Endpoint Interface 구현 오브젝트간의 SOAP 바인딩 모음을 들 수 있다. 혹은 더 간단히, 웹서비스는 Java 인터페이스 오브젝트와 URL 간의 매핑이므로 메서드 혹은 절차 호출을 원격으로 수행할 수 있게 한다는 사실에서도 알 수 있다.

서비스 디스크립터 작성

J2SE 1.4.2 SDK, Tomcat 5.0 for Java WSDP 1.4, Java WSDP 1.4를 설치하자. 이 기술들이 있는 웹페이지에서 설치 명령어를 찾을 수 있다. 그러나 설치 순서를 기억해야 한다. Java와 Tomcat for JWSDP를 먼저 설치한다면 JWSDP 설치가 간단해질 것이다. Java WSDP 1.4를 설치하는 동안 브라우저에는 이 제품을 통합하도록 권장하는 웹컨테이너 옵션 선택 창이 뜰 것이다. JWSDP 1.4 다운로드를 위한 Tomcat이 이미 설치되어 있다면 웹컨테이너 메뉴에 추가하면 된다. 그러면 JWSDP는 자동적으로 Tomcat 설치 디렉토리에 통합될 것이다.

Tomcat 웹서비스 설치에는 새로 출시된 모든 Java 웹서비스 API에 대한 샘플이 포함되어있다. 그러나 이에 대한 문서는 매우 부족한 관계로 이 테크팁에서는 그 샘플들 중 JAX-RPC 예제를 수정한 버전을 이용하겠다. 수정된 예는 서버의 현재시간을 보여주는 간단한 웹 서비스로 특별하진 않지만 중요한 요점을 가르쳐줄 것이다. 사용자가 웹서비스를 직접 작성할 때 이것과 비교하면 좋다.

예제 애플리케이션을 다운로드하고 HelloWorld 디렉토리 옆의 <JWSDP_HOME>/jaxrpc/samples에 압축을 푼다. 그 후에 /etc디렉토리를 찾는다. /etc디렉토리에서 TimeService.wsdl이 파일을 찾을 수 있을 것이다.

이 WSDL 파일을 열 때 앞서 설명한 용어들을 재빨리 기억할 필요가 있다. 가장 높은 단계인 wsdl:definitions 요소와 여러 wsdl:message요소들을 발견하게 될 것이다.

   <?xml version="1.0" encoding="UTF-8"?>
   <!-- TimeService.wsdl -->
 

   <definitions 
     name="TimeService" 
     targetNamespace="http://time.org/wsdl" 
     xmlns:tns="http://time.org/wsdl" 
     xmlns="http://schemas.xmlsoap.org/wsdl/" 
     xmlns:ns2="http://time.org/types" 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
 

   <message name="TimeSEI_sayTimeBack">
    <part name="String_1" type="xsd:string"/>
   </message>
    
   <message name="TimeSEI_sayTimeBackResponse">
    <part name="result" type="xsd:string"/>
   </message>
   ...

중요한 것이 몇 가지 있다. 먼저 http://time.org namespace 는 완전히 지어낸 것이며 웹서비스를 생성할 때 실제 네임스페이스와 교체하게 될 것이다. 둘째로 파일은 각각 결국 같은 연산에 매핑되는 두 개의 메시지를 정의한다. 각 메시지 이름은 TimeSEI_로 시작한다. TimeSEI는 타임서버 엔드포인트 인터페이스를 의미하며 존재하지 않는 Java Service Endpoint Interface 오브젝트를 참조한다. 마지막으로 sayTimeBacksayTimeBackResponse를 모두 보유하고 있는 것은 약간 장황하고 복잡하게 보일 수도 있지만 다음의 포트 타입과 연산 정의(operation definition) 문맥을 고려할 때 이들을 보유 해야하는 이유를 알게 될 것이다.

   <portType name="TimeSEI">
     <operation name="sayTimeBack" parameterOrder="String_1">
       <input message="tns:TimeSEI_sayTimeBack"/>
       <output message="tns:TimeSEI_sayTimeBackResponse"/>
     </operation>
   </portType>

연산 정의시 기억해두어야 할 것은 각 연산은 반드시 하나가 아닌 두개의 메시지를 포함해야 한다는 것이다. 이는 WSDL과 JAX-RPC이 SOAP 프로토콜을 이용하여 연산하도록 구축되어있기 때문이다. SOAP 메시지들은 한쪽 방향으로만 작용하지만 RPC는 반드시 양방향 비헤이비어이다. 연산과 연산으로 매핑된 Java 메서드는 입력 매개변수와 리턴되는 값을 정의한다. SOAP에 잘 매핑하기 위해, 양방향 커뮤니케이션에는 두개의 개별적인 메시지가 필요하다.

portType 의 이름이 TimeSEI인 것에 주목하자. 다시말해, 이것은 존재하지 않는 Service Endpoint Interface에 대한 매핑이다. 위의 정의에 따르면 TimeSEI 인터페이스 오브젝트는 다음과 같은 서명을 갖고있는 단일 공개 메서드를 노출한다.

   public String sayTimeBack(String) throws RemoteException;  

메시지와 포트 타입 정의를 읽음으로써 이 모든 정보를 조합할 수 있다.

자, 이제 SOAP 프로토콜 바인딩에 대해 알아보자.

   <binding name="TimeSEIBinding" type="tns:TimeSEI">
     <operation name="sayTimeBack">
       <input>
         <soap:body 
           encodingStyle=
            "http://schemas.xmlsoap.org/soap/encoding/" 
           use="encoded" 
           namespace="http://time.org/wsdl"/>
       </input>
       <output>
         <soap:body 
           encodingStyle=
            "http://schemas.xmlsoap.org/soap/encoding/"
           use="encoded" 
           namespace="http://time.org/wsdl"/>
       </output>
       <soap:operation soapAction=""/>
     </operation>
    
     <soap:binding 
       transport="http://schemas.xmlsoap.org/soap/http" 
       style="rpc"/>
   </binding>

이 바인딩은 code>sayTimeBack 연산에서의 입력물과 출력물 메시지 바디의 인코딩 스타일을 정의한다. 이 연산은 SOAP을 이용하여 인코딩되며 다른 연산 메시지와 충돌되는 것을 막기위해 특별한 네임스페이스를 할당한다. 마지막으로 바인딩은 RPC 바인딩 스타일과 SOAP 호출이 HTTP가 되게 하는 전송 메커니즘을 선언한다. 남는 것은 서비스 정의 자체이다.

   <service name="TimeService">
     <port name="TimeSEIPort" binding="tns:TimeSEIBinding">
       <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
     </port>
   </service>
  
 </definitions>

서비스 정의를 TimeService라 이름 짓고 그 포트를 바인딩에 매핑한다. 이로써 간단한 웹 서비스 정의가 완료되었다.

서비스 구현

자, 이제 서비스 구현을 작성할 시간이다. 두가지 다른 접근법을 사용할 수 있다. 사용자가 직접 SEL 스터브를 작성하여 웹 아카이브의 구현 클래스와 수동으로 패키징하거나 Java WSDP 1.4에 제공되는 ANT build를 사용할 수 있다. ANT는 JWSDP 1.4 환경의 이점을 살려 SEI 스터브를 자동적으로 생성할 수 있다. 두번째 접근법이 훨씬 빠르므로 기본적인 JAX-RPC 프레임워크의 복잡성을 다룰 시간적 여유가 생긴다.

이 단계를 완성하기 위해 반드시 작성해야 하는 몇 가지 파일이 있다. SEI 구현 클래스부터 시작하자.이 예제에서 사용한 것은 TimeOnServer/src/server/time/TimeImpl이다. 다음은 이 클래스의 컨텐츠이다.

   package time;

   import java.util.Date;

   public class TimeImpl implements time.TimeSEI, 
     java.rmi.Remote {

       public String sayTimeBack(java.lang.String str) {
           Date date = new Date(System.currentTimeMillis());
           String result = " Hello, " + str 
               + ".  The time on the server is " 
               + date.toString();
           return result;
       }
   }

이 간단한 클래스는 time.TimeSEI인터페이스와 java.rmi.Remote 인터페이스를 구현한다. TimeSEI는 포트 타입 정의로 선언되었었다는 사실을 상기하자. 그러나 인터페이스는 여전히 작성되지 않았다. 이 인터페이스는 JWSDP ANT build로 생성할 수 있으며 구현 클래스와 같은 패키지 안에 있어서 임포트할 필요가 없다.

그러나 JAX-RPC 레퍼런스 구현을 위해 특별한 디스크립터 파일을 작성해야 할 필요가 있다. 이것은 컨테이너에 필요한 사항이므로 TimeImpl 클래스에 대한 포트 타입 정의로부터 어떻게 TimeSEI 레퍼런스를 매핑하는지 알 수 있다.

   <!-- jaxrpc-ri.xml -->
   <webServices
       xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/dd"
       version="1.0"
       targetNamespaceBase="http://time.org/wsdl"
       typeNamespaceBase="http://time.org/types"
       urlPatternBase="/ws">

       <endpoint
           name="Time"
           displayName="Time Service"
           description="A simple web service"
           wsdl="/WEB-INF/TimeService.wsdl"
           interface="time.TimeSEI"
           implementation="time.TimeImpl"
           model="/WEB-INF/model-wsdl-rpcenc.xml.gz"/>

       <endpointMapping
           endpointName="Time"
           urlPattern="/time"/>

   </webServices>

endpoint 요소는 그것의 SEI로의 경로와 구현 클래스를 포함한 서비스의 속성을 설명하며, 관리 툴을 위해 엔드포인트에 대한 몇가지 기본 메타데이터를 정의한다. 또한 endpointMapping은 서비스 엔트포인트로 URL 패턴을 바인딩한다.

실제 웹 서비스를 위해 이 파일을 형성하여 프로젝트를 정확하게 정의했는지 확인 하기 위해 web.xml 파일을 체크해야 한다. 이로써 서비스를 구축하고 디플로이할 준비가 완료된 것이다. PATH 세팅이 ANT (<JWSDP_HOME>/apache-ant/bin)로의 경로를 포함하고 있도록 확인해야 한다. 그 후 커멘트 라인 인터페이스 안의 /TimeOnServer 디렉토리를 탐색하여 다음의 커멘드를 입력하자.

   ant  

ANT는 TimeSEI 인터페이스를 생성할 것이다. 그것의 구현 스터브 클래스도 생성하며 새로운 웹 서비스의 상호작용을 핸들링 하기 위해 SOAP 요청과 반응 구조를 다중 분류하는 배열 역시 생성할 것이다. ANT는 모든 관련된 파일들을 WAR 파일(jaxrpc-TimeOnServer.war)에 조합하면 완료된다. 이 아케이브를 tomcat_jwsdp/webapps 디렉토리에 복사하여 startup.bat 파일을 더블 체킹하거나 /tomcat_jwsdp/bin 디렉토리에서 startup.sh스크립트를 구동하여 Tomcat을 기동시킬 수 있다.

이 때, 충분히 운용할 수 있는 웹 서비스를 보유하고 있어야 하지만, 테스트를 할 때는 웹 서비스에 클라이언트를 구동하는 것으로 충분하다.

간단한 클라이언트 구현

예제 애플리케이션에는 간단한 클라이언트를 포함하고 있다. 이를 구동하기 위해서는 /TimeOnServer 디렉토리의 커멘드 라인 인터페이스에 다음 커멘드를 입력해야한다.

   ant run-client

이 커멘드는 클라이언드 클래스들을 생성하고 컴파일하며 클라이언트를 구동한다. 모든 것이 성공적이라면 클라이언트를 구동하여 출력 시 마지막 몇 줄은 다음과 같이 나타나야 한다.

   run-client:
        [java]  Howdy, stranger. 
        The time on the server is Sun Aug 01 01:01:46 CDT 2004

   BUILD SUCCESSFUL
   Total time: 20 seconds

어떻게 JAX-RPC 서비스가 작용되는지 좀 더 자세히 알고 싶으면 예제의 소스코드를 읽고 생성된 WAR 파일 안의 Service Endpoint Interface나 SOAP 요청/반응 오브젝트 같은 클래스 파일을 읽자. 프로젝트의 구축환경을 사용자 정의하고 싶다면 build.xml file에 프로젝트 이름을 업데이트하는 것을 잊지 말기 바란다. 또한 Understanding your JAX-RPC SI Environment, Part 2 도 참조하기 바란다. 이 아티클은 몇 가지 개발, 디플로이먼트, 혁신 시나리오를 제공하고 있다.

"Java EE" 카테고리의 다른 글

2004/10/05 15:17 2004/10/05 15:17

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/281

댓글을 달아 주세요

  1. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 05:41
[로그인][오픈아이디란?]

◀ Prev 1  ... 564 565 566 567 568 569 570 571 572  ... 626  Next ▶