이미 웹 서비스와 자바 기술 대해 작성된 문서들이 많이 있다. 이 중 심도깊은 내용을 다루는 문서도 있었지만, 사람들은 여전히 자바 기술을 사용하여 웹 서비스를 생성하도록 도와주는 간결하고 직접적인 문서를 원한다. 이번 테크팁은 이를 위한 것이다. 간단한 웹 서비스를 구축하는 과정과 XML기반의 RPC(JAX-RPC)를 위해 Java API를 사용하여 서비스에 접근하는 클라이언트를 구축하는 과정에 대해 단계적으로 다룬다. 이 단계는 J2EE 1.4 tutorial에 있는 Chapter 8: Building Web Services with JAX-RPC를 기반으로 한다. 이들은 웹 서비스와 웹서비스의 클라이언트를 생성하는 기본적인 단계들이다.
  1. 서비스를 위한 위한 SEI(service endpoing interface)와 SEI의 실행 클래스 코드를 작성한다.
  2. SEI와 실행클래스를 컴파일한다.
  3. WSDL과 매핑 파일들을 생성한다.
  4. 서비스를 패키지화하고 배치한다. 특별한 동일 클래스들(클라이언트와의 커뮤니케이션에 사용된)은 서비스가 배치되는 동안에 응용서버에 의해 생성된다.
  5. 클라이언트 클래스 소스를 작성한다.
  6. Stub 파일들을 생성한다.
  7. 클라이언트 클래스들을 컴파일한다.
  8. 클라이언트를 패키지화한다.
SEI와 실행 클래스 코드 작성

JAX-RPC 웹 서비스를 개발하는 데 있어서 시작 포인트는 SEI(service endpoint interface)이다. 이것은 단순히 클라이언트가 그 서비스에 호출할 수 있는 방법을 선언하는 자바 인터페이스이다.

JAX-RPC를 통하여 클라이언트들에게 사용 가능한 웹서비스를 만들어 주기 위해 2개의 자바 클래스를 생성할 필요가 있다. 하나는 SEI를 정의하는 것, 그리고 다른 하나는 SEI 구현하는 것이다. 이 두 클래스들의 소스 코드는 이번 테크팁의 샘플 코드인 ttmay2005-ws.jar를 사용한다. 다음은 웹 서비스를 위한 SEI를 정의하는 클래스이다.
   package helloservice;
   import java.rmi.Remote;
   import java.rmi.RemoteException;

   public interface HelloIF extends Remote {
       public String sayHello(String s) throws RemoteException;
   } 
SEI는 다음의 규칙을 따라야 한다.
  • java.rmi.Remote 인터페이스를 확장한다.
  • public / final / static과 같은 일정한 선언을 가져서는 안된다.
  • 메소드들은 java.rmi.RemoteException이나 그것의 하위 클래스들 중의 하나를 throw해야한다. (메소드들은 또한 service-specific exception들을 throw할 수 있다.)
  • 메소드 매개변수들과 리턴 타입들은 반드시 JAX-RPC타입들에 의해 지원되어야한다. (JAX-RPC 타입 목록를 위해)
다음은 실행 클래스의 코드이다. 이 클래스는 문자열 매개변수를 수용하며, 그 매개변수를 약간 수정된 문자열을 리턴하기 위해 사용한다.
   package helloservice;
   public class HelloImpl implements HelloIF {

       public String message = "Hello there, ";
       public String sayHello(String s) {
           return message + s;
       }
   } 
SEI 클래스와 실행 클래스 컴파일하기

SEI 클래스와 실행 클래스를 생성한 후에는 그들을 컴파일해야한다. 이를 위한 쉬운 방법은 ant 설정 도구(http://ant.apache.org/)를 사용하는 것이다. 웹 서비스를 위한 구축 파일(build.xml)은 이 팁의 샘플 코드에 있다. 샘플을 위한 구축 파일과 같은 디렉토리에서 ant를 실행하여 구축할 수 있다. 현재의 디렉토리를 그 샘플 코드를 설치한 ws/helloservice 밑으로 변경한다. 그리고 다음의 명령을 입력한다.
   ant 
빌드하는데 가장 먼저 이뤄지는 것은 웹서비스를 위한 디렉토리를 생성하는 것이다. 그런 다음 파일들을 컴파일한다. 컴파일 단계는 다음의 javac 명령어들을 실행하는 것과 동일하다.
   src\helloservice>javac -d ..\..\build -cp ..\
   ..\build HelloIF.java
   
   src\helloservice>javac -d ..\..\build -cp ..\..\
   build HelloImpl.java
(참고: 각각의 명령은 이 문서상에서는 두 줄로 나타내지만 실제로는 한 라인에 입력해야 한다.)

WSDL과 매핑 파일들의 생성

WSDL 파일은 웹서비스를 표현한다. 클라이언트에게 그 서비스에 대한 요구를 하는 데 있어서 어떤 포맷을 이용해야 하는 지를 말해주는 것이 바로 WSDL 파일이다. Wscompile는 JAX-RPC SEI와 WSDL 파일 사이에 매핑을 제공하는 J2EE 1.4 SDK에 패키지된 툴이다. SEI로부터 WSDL 파일을 생성시키거나 WSDL 파일로부터 SEI를 생성시키기 위해 wscompile툴을 구동할 수 있다. 이 만약 이 팁을 위한 구조를 설정하기 위해 ant 명령어를 사용하게 되면, 그것은 wscompile 도구를 구동하여 웹서비스를 위한 WSDL 파일을 생성한다. 그 구조는 또한 mapping.xml 파일을 생성하는데, 매핑 파일은 웹서비스의 WSDL 정의를 자바 인터페이스에 매핑한다.

만약 ant로 빌드하지 않는다면 디렉토리의 안에 다음의 명령을 구동하여 mapping.xml과 WSDL 파일을 새로 만들 수 있다.
   wscompile -define -mapping build\mapping.xml -d build 
   -nd build -classpath build config-interface.xml
(참고: 이 문서상에서는 두 줄로 나타내지만 실제로는 한 라인에 입력해야 한다.)

wscompile 명령에 있는 플래그는 각각 다음과 같은 의미이다.
-classpath. build 디렉토리에서 SEI를 읽도록 wscompile 툴을 지시한다. 
-define. WSDL을 생성하도록 wscompile을 지시한다.
-mapping. 매핑 파일을 생성하도록 wscompile를 지시한다.  
-d. Build 하위 디렉토리에 클래스 파일을 쓰도록 wscompile를 지시한다. 
-nd. Build 하위 디렉토리에 WSDL 파일을 쓰도록 wscompile를 지시한다. 
wscompile 툴을 구동할 때, 또한 SEI에 대한 정보를 명시하는 wscompile 구성 파일을 제공해야 한다. 구성 파일은 이 테크팁의 샘플 코드로 제공되는데, 그 구성파일은 config-interface.xml이라 하며 다음의 내용을 포함하고 있다.
   <?xml version="1.0" encoding="UTF-8"?>
   <configuration 
     xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
     <service 
         name="MyHelloService" 
         targetNamespace="urn:Foo" 
         typeNamespace="urn:Foo" 
         packageName="helloservice">
         <interface name="helloservice.HelloIF/>
     </service>
   </configuration>
이 구성 파일은 wscompile에게 MyHelloService.wsdl라는 이름의 WSDL 파일을 생성하도록 명령한다. 그 파일은 또한 다음의 정보와 명령을 제공된다.
  • 서비스명은 MyHelloService이다.
  • SEI는 helloservice.HelloIF이다.
  • helloservice 패키지에 그 서비스 클래스를 놓는다.
  • WSDL 대상과 타입 네임 스페이스는 urn:Foo이다. 네임 스페이스로 무엇을 이용할 것인지는 사용자가 선택할 수 있다. 네임 스페이스의 역할은 자바 패키지 이름의 사용과 비슷하다.즉, 그렇지 않으면 충돌할 수 있는 이름을 식별하는 것이다. 예를 들어, 어떤 회사는 회사의 모든 자바 코드가 com.wombat.* 패키지 안에 있도록 결정할 수 있다. 마찬가지로, 또한 네임스페이스 http://wombat.com을 사용하기로 결정할 수도 있다.
서비스의 패키지와 배치

그 다음으로 서비스를 패키지화하고 배치시킬 필요가 있다. 이를 위해서는 배치 기술어에 서비스에 대한 세부사항을 명시할 필요가 있다. 웹 서비스는 서블릿이나 비상태유지 세션빈(관련된 서비스를 하는데 상태정보를 유지하지 않은 bean;stateless session bean)으로써 구현될 수 있다. 웹 서비스는 서블릿들이 Web Archive (WAR) 파일에 패키지됨에 따라 구현된다. WAR 파일에 있는 WEB-INF 디렉토리는 웹 어플리케이션(web.xml, sun-web.xml)과 특별한 웹 서비스 배치 기술어 파일(webservices.xml)을 위한 두 개의 표준 배치 기술어 파일을 포함한다. 웹 서비스는 Bean이 EJB-JAR 파일에 비상태유지 세션 빈이 패키지됨에 따라 구현되며, 배치 기술어 파일은 META-INF 디렉토리에 있다.

이번 테크팁을 빌드를 하기 위해 ant 명령을 사용한다면, 사용자를 위해 서비스를 패키지한다. 특히 이 빌드는,
  • WAR 내용을 모으기 위해 임시 디렉토리를 생성한다.
  • 임시 디렉토리에서 두 하위디렉토리(WEB-INF와 build)를 생성한다.
  • WEB-IN디렉토리에서 두 하위 디렉토리(클래스들과 wsdl)를 생성한다.
  • HelloIF.class와 HelloImpl.class를 WEB-INF/classes 디렉토리로 복사한다.
  • MyHelloService.wsdl을 WEB-INF/wsdl 디렉토리로 복사한다.
  • mapping.xml 파일을 그 구축 디렉토리로 복사한다.
  • 임시 디렉토리로부터 WAR 파일을 새로 만든다. WAR파일은 WEB-INF 디렉토리에서 web.xmlsun-web.xml 배치 기술어, webservices.xml 파일을 둔다.
다른 대안으로, J2EE 1.4 Application Server의 배치 툴 유틸리티을 사용하는 웹서비스를 패키지 할 수 있다.

WAR 파일이 새로 만들어진 후에는, 이를 deploytool이나 다른 어플리케이션을 사용하여 배치시킬 수 있다. 배치가 성공적이면, 웹브라우저에 URL http://localhost:8080/ttmay2005/hello?WSDL를 입력하여 배치된 서비스의 WSDL 파일을 보게될 것이다.. (Application Server가 port 8080에 배치되었다고 가정). 그 다음 세션(“데스크탑 클라이언트”)에 있는 wscompile 명령이 성공하기 위해 서버로부터 이 XML파일을 다운로드 하는 것에 의존하기 때문에 이를 실행할 수 있음을 주의하기 바란다.

클라이언트 클래스 생성

그 웹서비스를 배치시킨 후에는, 클라이언트 프로그램으로부터 웹서비스에 접근할 수 있다. HelloClient는 이 테크팁의 샘플 코드로 제공된 데스크탑 클라이언트 프로그램이다. 이는 MyHelloService의 sayHello 메소드를 호출한다. 원격 서비스를 위한 프록시(proxy) 를 사용하는 지역 객체인 stub을 통해 이 호출을 하게 된다. stub이 개발 시간(실행시간과 대조적)에 생성되기 때문에, 그것은 보통 정적stub(static stub)이라고 불린다. 다음은HelloClient (정적 stub을 위한 코드)에 대한 원시 코드이다.

   package staticstub;

   import javax.xml.rpc.*;

   public class HelloClient {

       private static String endpointAddress =
           "http://localhost:8080/ttmay2005/hello";

       public static void main(String[] args) {

           System.out.println("Endpoint address = "
             + endpointAddress);

           try {
              Stub stub = createProxy();
              stub._setProperty
                (Stub.ENDPOINT_ADDRESS_PROPERTY,
                 endpointAddress); 
              HelloIF hello = (HelloIF)stub;
              System.out.println(hello.sayHello("Duke!"));
           } catch (Exception ex) {
              ex.printStackTrace();
           }
       }    

       private static Stub createProxy() {
           return 
               (Stub) (new MyHelloService_Impl().
                   getHelloIFPort());
       }
   }  

Stub 파일들 생성

이전에 언급한 대로, 클라이언트는 서비스에 접근하기 위해 stub로 불리는 로컬 프록시를 사용한다. 따라서 그 서비스에 접근하는 클라이언트를 사용할 수 있기 전에, 그 stub 파일들을 생성해야한다. 이를 실행하는 방법은 wscompile와 같은 툴을 사용하는 것이다. 좀전에 한 것처럼, wscompile툴을 호출하기 위해 ant 명령어를 구동할 수 있다. 현재 디렉토리를 그 샘플 코드를 설치한 곳 밑에 있는 ttMay2005/helloclient 디렉토리로 바꾸기 바란다. 그리고 나서, 다음의 명령을 입력한다.
   ant stubs
Stub 태스크는 다음의 독립 변수를 가진 wscompile 툴을 구동한다.
   wscompile -gen:client -d build -classpath build 
    config-wsdl.xml 
이 독립 변수는 wscompile이 이전에 생성된 MyHelloService.wsdl 파일을 읽도록 한다. 이 툴은 또한 WSDL 파일과 명령어 줄(command-line) 플래그에 대한 정보에 기반하는 파일들을 생성한다. 특히, “-gen” 클라이언트 플래그는 serializers와 value type과 같은 런타임 파일과 stub들을 생성하도록 wscompile에 지시한다. "-d" 플래그는 툴이 생성된 결과물을 build/staticstub 하위 디렉토리에 쓰도록 명령한다.

wscompile 툴을 구동할 때, 목표 WSDL 파일의 위치를 명시하는 구성파일도 제공해야한다. 구성파일(config-interface.xml)은 이 팁의 샘플 코드로 나와있다. 다음은 config-interface.xml 파일의 내용이다.
   <configuration 
     xmlns="http//java.sun.com/xml/ns/jax-rpc/ri/config">
     <wsdl location="http://localhost:8080/ttmay2005/hello?WSDL" 
     packageName="staticstub"/>
   </configuration>
packageName 속성은 그 생성된 stub에 대해 자바 패키지를 명시한다. WSDL 파일의 위치가 URL으로서 명시된다는 것을 알아두기 바란다. 이는 웹서비스에서 WSDL 파일을 요청하는 wscompile 명령을 야기한다. 이 때문에, 웹서비스는 반드시 올바르게 배치되고 성공을 위한 명령을 위해 구동되고 있어야한다. 웹서비스가 실행되지 않고 있거나 서비스가 배치된 포트가 구성 파일의 포트와 다르다면, 그 명령은 실패할 것이다.

클라이언트 클래스 컴파일하기

다음 단계는 클라이언트 클래스를 컴파일하는 것이다. 이번 테크팁의 예제를 컴파일하려면, 다음 명령을 입력한다.
   ant compile
ant 컴파일 태스크는 src/HelloClient.java를 컴파일하고, 그 구축 하위 디렉토리에 클래스 파일을 작성한다. 다음의 명령을 구동하는 것과 동일하다.
   javac -sourcepath src -d build staticstub.HelloClient.java
클라이언트 패키지화

클라이언트를 생성하는 과거 단계는 이전에 생성된 파일들을 jar 파일 안으로 패키지하는 것이다. 다음 명령을 입력한다.
   ant jar
ant jar 태스크는 ttmay2005.jar이란 이름의 파일을 생성한다. HelloClient.class를 제외하고, ttmay2005jar 안의 모든 파일들은 wscompile에 의해 생성되었음을 알아두기 바란다. 또한, wscompile가 그것이 응용 서버로부터 다운로드 한 MyHelloService.wsdl 화일로부터 읽은 정보에 기반한 HelloIF.class를 생성시켰다는 것도 알아두자.

클라이언트 구동

클라이언트를 실행하기 전에 해당하는 JAR 라이브러리(Java Web Services Developer Pack 1.5 download 참고)클래스 패스를 설정하기 바란다.
   jaxrpc/lib/jaxrpc-api.jar
   jaxrpc/lib/jaxrpc-spi.jar
   jaxrpc/lib/jaxrpc-impl.jar
   jwsdp-shared/lib/activation.jar
   jwsdp-shared/lib/mail.jar
   jwsdp-shared/lib/jax-qname.jar
   saaj/lib/saaj-api.jar
   saaj/lib/saaj-impl.jar
   jaxp/lib/endorsed/dom.jar
   jaxp/lib/endorsed/sax.jar
   jaxp/lib/endorsed/xalan.jar
   jaxp/lib/endorsed/xercesImpl.jar
다른 방법으로는, 다음과 같이 클라이언트를 실행 시킬 때 클래스패스를 추가 시킬 수도 있다.
   ant run
이 경우 커맨드 라인 창에 다음과 같은 내용이 보인다.
   [java] Endpoint address = http://localhost:8080/ttmay2005/hello
   [java] Hello Duke!
추가 정보

JAX-RPC에 대한 추가 정보는, J2EE 1.4 Tutorial의 Chapter 8: Building Web Services with JAX-RPC를 참고하기 바란다.

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

2005/07/26 16:22 2005/07/26 16:22

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

댓글을 달아 주세요

  1. 고진구  수정/삭제  댓글쓰기

    쉬운 예제와 설명 잘 읽었읍니다. 큰 도움이 되겠어요.

    2007/09/09 23:05
  2. 봉지연  수정/삭제  댓글쓰기

    많이 배워가겠습니다 ^^

    2007/09/12 09:27
  3. 김형국  수정/삭제  댓글쓰기

    좋은 정보 잘 보고 갑니다.
    앞으로두 좋은 정보 부탁드릴꼐요 화이팅~ ㅋㅋ

    2007/09/12 18:17
  4. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

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

◀ Prev 1  ... 499 500 501 502 503 504 505 506 507  ... 626  Next ▶