JAX-RPC 웹 서비스 구현

본 장에서는 JAX-RPC 웹 서비스를 구현하는 여러 가지 방식에 대한 설명한다.

1. 개요

JEUS JAX-RPC 웹 서비스 구현 작업은 웹 서비스를 구성하는 Back-end 구성 요소인 Java 코드를 작성 또는 컴파일하는 것을 의미한다. 기본적으로 JEUS JAX-RPC 웹 서비스는 Java 클래스, EJB와 같은 2가지 타입의 웹 서비스 Back-end 구성 요소를 지원한다.

JEUS JAX-RPC 웹 서비스를 구현하는 주요 절차는 다음과 같다.

  1. 웹 서비스를 구성하는 Back-end 구성 요소인 Java 코드를 작성한다.

  2. SOAP 메시지의 내용을 직접 다루기를 원하거나, SOAP 메시지의 Attachment에 직접 접근하기를 원한다면 직접 SOAP 메시지 핸들러나 핸들러 체인(Chain)을 생성한다.

  3. Java 코드를 컴파일한다.

2. Java 클래스 웹 서비스 구현

Java 클래스 웹 서비스는 JAX-RPC 웹 서비스의 구현에서 웹 서비스를 생성하는 가장 간단한 방법이다. 간단한 예를 통해 구현하는 방법에 대해 설명한다.

2.1. 간단한 예제

Java 클래스 웹 서비스를 생성하기 위해서는 SEI와 구현 클래스를 정의해야 한다. SEI는 Java 클래스 웹 서비스 Endpoint가 Java 메소드의 형식으로 지원할 웹 서비스 오퍼레이션들을 정의한다. 구현 클래스는 이러한 SEI들을 구현한다.

다음의 Endpoint 인터페이스는 echoString과 echoString_double이라는 웹 서비스 오퍼레이션들을 정의하고 있다.

package jeustest.webservices.java2wsdl.doclit;

public interface Echo extends java.rmi.Remote {
    public String echoString(String arg11)
        throws java.rmi.RemoteException;
    public String echoString_double(String arg1, String arg2)
        throws java.rmi.RemoteException;
}

Endpoint 인터페이스는 외부에 공개되어 접근 가능한 웹 서비스 오퍼레이션들을 정의한다. 즉, SOAP이라는 프로토콜을 사용하여 접근할 수 있는 오퍼레이션들을 정의한다. Endpoint 인터페이스는 java.rmi.Remote 인터페이스를 직접적 또는 간접적으로 확장해야 하며, 정의된 메소드들은 java.rmi.RemoteException 타입을 Exception으로 던져야 한다. 위와 같이 서비스 오퍼레이션들을 정의하고 나면 이를 구현하는 로직이 필요하다. 그 역할을 하는 것이 구현 클래스이다.

다음이 구현 클래스에 대한 예이다.

package jeustest.webservices.java2wsdl.doclit;

public class EchoImpl implements Echo {
    public String echoString(String input0)
        throws java.rmi.RemoteException {
        return input0;
    }

    public String echoString_double(String input0, String input1)
        throws java.rmi.RemoteException {
        return input0+input1;
    }
}

구현 클래스는 Endpoint 인터페이스를 구현하고 있다. Jakarta EE 서버 내에서 인스턴스화되어 실행되며 런타임에는 웹 서비스로 동작하게 될 것이다.

2.2. Java 클래스 작성 원칙

Java 클래스 Back-end로서 웹 서비스를 구현할 때 다음의 규칙들을 준수해야 한다.

  • SEI를 정의한다.

  • public 클래스를 정의한다.

  • 파라미터 없는 디폴트 생성자를 정의한다.

  • 웹 서비스에서 public, non-static으로 Export되는 Java 클래스의 메소드들을 정의한다.

  • 스레드에 안전한(Thread-safety) Java 코드를 작성한다.

  • 상호 운용성을 위해서 오버 로딩된 메소드들을 사용하지 말아야 한다.

위와 같은 조건을 만족하는 경우 다음과 같은 절차에 따라서 웹 서비스를 구현한다.

  • 웹 서비스 메소드를 포함하고 있는 Java 클래스를 정의한다.

  • 서비스로 명시적으로 공개할 메소드를 위한 인터페이스를 정의한다.

3. EJB 웹 서비스 구현

EJB는 Jakarta EE 웹 서비스를 개발하는 데 있어 이전에 언급되었던 Java 클래스 웹 서비스 프로그래밍 모델보다 좀 더 복잡하지만 더 풍부한 기능을 가질 수 있게 하는 프로그래밍 모델이다. 이러한 복잡성은 트랜잭션을 자동으로 관리하게 되면서 부수적으로 발생하는 것이라고 볼 수 있다.

EJB 웹 서비스를 구현하기 위해서는 EJB에 대한 어느 정도의 이해를 필요로 한다. 만약 웹 서비스를 구현하는 데 있어 EJB를 사용하지 않아도 된다면, 본 장의 내용은 숙지하지 않아도 된다.

3.1. 간단한 예제

Stateless Session EJB 또한 웹 서비스로 Export될 수 있다. 이 경우에도 SEI가 필요하다.

다음의 Endpoint 인터페이스(HelloIF.java)는 sayHello(String) 웹 서비스 오퍼레이션을 정의하고 있다.

EJB 웹 서비스 구현 : <HelloIF.java>
package helloejb;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface HelloIF extends Remote {
    public String sayHello(String s) throws RemoteException;
}

Endpoint 인터페이스는 외부에 공개되어 접근 가능한 웹 서비스 오퍼레이션들을 정의한다. 즉, SOAP이라는 프로토콜을 사용하여 접근할 수 있는 오퍼레이션들을 정의한다. Endpoint 인터페이스는 java.rmi.Remote 인터페이스를 직접적 또는 간접적으로 확장해야 하며, 정의된 메소드들은 java.rmi.RemoteException 타입을 Exception으로 던져야 한다. 위와 같이 서비스 오퍼레이션들을 정의한 후에는 이를 구현하는 로직이 필요하다. 여기서는 EJB가 그 역할을 담당한다.

다음은 리모트 인터페이스의 예이다.

EJB 웹 서비스 구현 : <Hello.java>
package helloejb;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Hello extends EJBObject
{
    String sayHello(String s) throws RemoteException;
}

다음은 홈 인터페이스의 예이다.

EJB 웹 서비스 구현 : <HelloHome.java>
package helloejb;

import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;

public interface HelloHome extends EJBHome
{
    Hello create() throws RemoteException, CreateException;
}

다음은 Session Bean을 구현한 EJB Endpoint Bean 클래스이다.

EJB 웹 서비스 구현 : <HelloEJB.java>
package helloejb;

import java.rmi.RemoteException;

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.lang.*;

public class HelloEJB implements SessionBean {

    public HelloEJB() {}
    public String sayHello(String s) throws RemoteException {
        try {
            Thread.currentThread().sleep(500);
        } catch (Exception ex) {
            throw new RemoteException("" + ex);
        }
        return "Hello World!" + s;
    }
    public void ejbCreate() {}
    public void ejbRemove() throws RemoteException {}
    public void setSessionContext(SessionContext sc) {}
    public void ejbActivate() {}
    public void ejbPassivate() {}
}

3.2. EJB 웹 서비스 작성 원칙

웹 서비스 오퍼레이션이 one-way로 설정되어 있으면 EJB 메소드의 Java 코드는 void 타입을 리턴해야 한다. 이 조건을 제외하면 Stateless Session EJB 웹 서비스를 위한 코딩 작업은 일반 EJB 코딩 작업과 다른 점이 없다.

이와 같은 조건을 만족하도록 다음과 같은 절차에 따라 웹 서비스를 구현한다.

  1. 웹 서비스 메소드를 포함하고 있는 EJB를 구현한다.

  2. 서비스로 명시적으로 공개할 메소드를 위한 인터페이스를 정의한다.

4. WSDL로부터 웹 서비스 구현

본 안내서의 대부분은 웹 서비스를 구성하는 Back-end 구성 요소인 Java 코드를 작성하는 것으로부터 시작하는 것을 가정하고 있다.

개발 환경에 따라서 WSDL로부터 서비스 인터페이스를 생성할 수 있다. 이 경우 사용자는 wsdl2java Ant Task를 수행하여 서비스 인터페이스를 얻을 수 있다. wsdl2java Ant Task는 사용자가 작성했거나 가지고 있는 WSDL 파일을 입력으로 한다.

다음은 wsdl2java Ant를 수행하기 위한 빌드 파일의 예이다.

WSDL로부터 웹 서비스 구현 : <build.xml>
<target name="do-package-war">

    ...

    <antcall target="wsdl2java">
        <param name="wsdl2java.option"
               value="-import:server -d ${build.war.dir}/WEB-INF/classes
               -package sample.datahandleronly.service
               -outputmapping ${build.war.dir}/WEB-INF/SubmitBookService-mapping.xml
               -compile ${src.web}/WEB-INF/wsdl/SubmitBookService.wsdl" />
    </antcall>

    ...

</target>

다음과 같은 명령을 수행하여 웹 서비스 서비스 인터페이스 소스 코드를 생성할 수 있다.

$ ant do-package-war

사용자는 생성된 서비스 인터페이스에 대한 서비스 구현체를 Java 클래스 웹 서비스 구현EJB 웹 서비스 구현의 구현 방식에 따라서 생성한다.

wsdl2java Task에 대한 더 자세한 설명은 JEUS Reference 안내서의 wsdl2java 콘솔 툴 또는 wsdl2java Ant Task를 참고한다.

5. SAAJ의 사용

통상적인 SOAP 메시지는 SOAP Body 안에 포함되지만 특정한 Java 타입을 웹 서비스 오퍼레이션을 구현하는 메소드의 파라미터나 리턴 타입으로 사용할 경우에는 SOAP Attachment 형태로 전송된다.

JEUS 웹 서비스는 SAAJ(SOAP with Attachments API for Java)의 사용을 위해 Java에서 MIME 타입으로의 형태 전환을 다음과 같이 정의한다.

Java 타입 MIME 타입

java.awt.Image

image/gif or image/jpeg

java.lang.String

text/plain

javax.mail.internet.MimeMultipart

multipart/*

javax.xml.transform.Source

text/xml or application/xml

위에 열거된 각각의 MIME 타입에 대해 JAX-RPC Endpoint Stub이 특정한 Java 타입을 적절히 인코딩된 데이터의 스트림으로 변환 또는 역변환 작업을 한다. 보다 자세한 설명은 JAX-RPC 웹 서비스 SOAP 메시지 핸들러 생성을 참고한다.