내용 목차
본 장에서는 JAX-RPC 웹 서비스를 구현하는 여러 가지 방식에 대한 설명한다.
JEUS JAX-RPC 웹 서비스 구현 작업은 웹 서비스를 구성하는 Back-end 구성 요소인 Java 코드를 작성 또는 컴파일하는 것을 의미한다. 기본적으로 JEUS JAX-RPC 웹 서비스는 Java 클래스, EJB와 같은 2가지 타입의 웹 서비스 Back-end 구성 요소를 지원한다.
JEUS JAX-RPC 웹 서비스를 구현하는 주요 절차는 다음과 같다.
웹 서비스를 구성하는 Back-end 구성 요소인 Java 코드를 작성한다.
SOAP 메시지의 내용을 직접 다루기를 원하거나, SOAP 메시지의 Attachment에 직접 접근하기를 원한다면 직접 SOAP 메시지 핸들러나 핸들러 체인(Chain)을 생성한다.
Java 코드를 컴파일한다.
Java 클래스 웹 서비스는 JAX-RPC 웹 서비스의 구현에서 웹 서비스를 생성하는 가장 간단한 방법이다. 간단한 예를 통해 구현하는 방법에 대해 설명한다.
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 인터페이스를 구현하고 있다. Java EE 서버 내에서 인스턴스화되어 실행되며 런타임에는 웹 서비스로 동작하게 될 것이다.
Java 클래스 Back-end로서 웹 서비스를 구현할 때 다음의 규칙들을 준수해야 한다.
SEI를 정의한다.
public 클래스를 정의한다.
파라미터 없는 디폴트 생성자를 정의한다.
웹 서비스에서 public, non-static으로 Export되는 Java 클래스의 메소드들을 정의한다.
스레드에 안전한(Thread-safety) Java 코드를 작성한다.
상호 운용성을 위해서 오버 로딩된 메소드들을 사용하지 말아야 한다.
위와 같은 조건을 만족하는 경우 다음과 같은 절차에 따라서 웹 서비스를 구현한다.
웹 서비스 메소드를 포함하고 있는 Java 클래스를 정의한다.
서비스로 명시적으로 공개할 메소드를 위한 인터페이스를 정의한다.
EJB는 Java EE 웹 서비스를 개발하는 데 있어 이전에 언급되었던 Java 클래스 웹 서비스 프로그래밍 모델보다 좀 더 복잡하지만 더 풍부한 기능을 가질 수 있게 하는 프로그래밍 모델이다. 이러한 복잡성은 트랜잭션을 자동으로 관리하게 되면서 부수적으로 발생하는 것이라고 볼 수 있다.
EJB 웹 서비스를 구현하기 위해서는 EJB에 대한 어느 정도의 이해를 필요로 한다. 만약 웹 서비스를 구현하는 데 있어 EJB를 사용하지 않아도 된다면, 본 장의 내용은 숙지하지 않아도 된다.
Stateless Session EJB 또한 웹 서비스로 Export될 수 있다. 이 경우에도 SEI가 필요하다.
다음의 Endpoint 인터페이스(HelloIF.java)는 sayHello(String) 웹 서비스 오퍼레이션을 정의하고 있다.
[예 21.1] << 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가 그 역할을 담당한다.
다음은 리모트 인터페이스의 예이다.
[예 21.2] << Hello.java >>
package helloejb; import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Hello extends EJBObject { String sayHello(String s) throws RemoteException; }
다음은 홈 인터페이스의 예이다.
[예 21.3] << 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 클래스이다.
[예 21.4] << HelloEJB >>
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() {} }
본 안내서의 대부분은 웹 서비스를 구성하는 Back-end 구성 요소인 Java 코드를 작성하는 것으로부터 시작하는 것을 가정하고 있다.
개발 환경에 따라서 WSDL로부터 서비스 인터페이스를 생성할 수 있다. 이 경우 사용자는 wsdl2java Ant Task를 수행하여 서비스 인터페이스를 얻을 수 있다. wsdl2java Ant Task는 사용자가 작성했거나 가지고 있는 WSDL 파일을 입력으로 한다.
다음은 wsdl2java Ant를 수행하기 위한 빌드 파일의 예이다.
[예 21.5] << 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
사용자는 생성된 서비스 인터페이스에 대한 서비스 구현체를 “21.2. Java 클래스 웹 서비스의 구현”과 “21.3. EJB 웹 서비스의 구현”의 구현 방식에 따라서 생성한다.
wsdl2java Task에 대한 더 자세한 설명은 “JEUS Reference Book”의 “4.10. wsdl2java” 또는 “JEUS Reference Book”의 “5.5.2. wsdl2java”를 참고한다.
통상적인 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 타입을 적절히 인코딩된 데이터의 스트림으로 변환 또는 역변환 작업을 한다. 보다 자세한 설명은 “제24장 JAX-RPC 웹 서비스 SOAP 메시지 핸들러 생성”을 참고한다.