본 장에서는 JAX-RPC 웹 서비스의 표준 웹 서비스 DD 파일 작성 방법과 JAX-RPC 매핑 파일 작성 방법에 대해 설명한다.
Jakarta EE JAX-RPC 웹 서비스는 webservices.xml이라는 이름을 가진 웹 서비스 서술자를 Java 클래스 Endpoint나 EJB Endpoint를 포함하는 압축 파일(WAR나 JAR)에 포함할 것을 요구한다.
webservices.xml을 EJB Endpoint의 경우에는 EJB JAR 파일의 META-INF 디렉터리에 저장하고, 서블릿 Endpoint의 경우에는 WAR 파일의 WEB-INF 디렉터리에 위치시킨다.
다음은 FileAttachmentService라는 웹 서비스의 webservices.xml 파일이다.
[예 25.1] JAX-RPC 웹 서비스 : <webservices.xml>
<?xml version="1.0"?> <webservices version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee"> <webservice-description> <webservice-description-name> FileAttachmentService </webservice-description-name> <wsdl-file> WEB-INF/wsdl/FileAttachmentService.wsdl </wsdl-file> <jaxrpc-mapping-file> WEB-INF/FileAttachmentService-mapping.xml </jaxrpc-mapping-file> <port-component> <port-component-name>FileAttPort</port-component-name> <wsdl-port xmlns:ns2="urn:FileAttachmentService"> ns2:FileTransferIFPort </wsdl-port> <service-endpoint-interface> filetransfer.FileTransferIF </service-endpoint-interface> <service-impl-bean> <servlet-link>FileAttachmentServlet</servlet-link> </service-impl-bean> <handler> <handler-name>ServerAttachmentHandler</handler-name> <handler-class> filetransfer.ServerAttachmentHandler </handler-class> <init-param> <param-name>directory</param-name> <param-value>/temp</param-value> </init-param> </handler> </port-component> </webservice-description> </webservices>
webservices.xml 파일의 root element는 <webservices>이고, <webservice-description>을 하나 또는 그 이상을 필수 요소로 가진다.
<webservice-description>은 동일한 WSDL을 사용하는 Java 클래스나 EJB Endpoint의 집합을 서술한다. 즉, 패키징 내의 다른 WSDL 각각의 파일 들에 대해서 <webservice-description>이 하나씩 존재해야 한다. 예를 들면 2개의 다른 Java 클래스 Endpoint가 각각 WSDL을 별도로 가지고 하나의 WAR 파일 안에 존재한다면 각각의 JSE를 서술하기 위해서 <webservice-description>은 2개가 존재해야 한다.
<webservice-description>는 Jakarta EE Endpoint를 WSDL 포트 정의, DD 구현, JAX-RPC 매핑 파일 그리고 Endpoint 인터페이스로 바인딩시켜주는 역할을 하며, 본 장에서는 이들의 관계와 필요성에 대해서 설명한다.
<wsdl-file>는 WSDL 문서의 WAR나 EJB JAR 파일 내에서의 상대적인 위치를 나타내며, webservices.xml 파일은 WSDL 파일과 같은 WAR나 JAR 파일 내에 위치해야 한다.
<jaxrpc-mapping-file>는 JAX-RPC 매핑 파일의 위치를 지정한다. JAX-RPC 매핑 파일은 WSDL 파일과 Jakarta EE Endpoint 간의 매핑을 정의한다. JAX-RPC 매핑 파일에 관한 더 자세한 설명은 “25.2. 웹 서비스의 매핑 파일 작성”을 참고한다.
<port-component>는 특정한 Java 클래스나 EJB Endpoint를 WSDL 문서 내의 특정한 port element로 매핑하는 역할을 한다. Java 클래스의 경우에 WSDL port 정의와 바인딩 정의는 웹 서비스를 호스트하기 위해 필요한 서블릿을 생성하는 데 사용된다.
EJB Endpoint의 경우에는 port와 바인딩 정의는 EJB 컨테이너가 SOAP 메시지를 무상태 Bean 객체에 보내기 위해 마셜링하는 데 사용된다.
<port-component-name>는 특정한 Java 클래스나 EJB Endpoint를 지정하기 위한 이름을 제공한다. 이 이름은 webservices.xml 파일 내에서 유일해야 한다.
Java 클래스를 Back-end로 가지는 웹 서비스의 경우, SEI의 이름을 지정하는 element이다.
EJB Endpoint 웹 서비스의 경우에도 마찬가지로 이 element에서 정의하며, 추가적으로 ejb-jar.xml의 <service-endpoint>에서도 같은 이름으로 정의해야 한다.
<service-impl-bean>는 서비스 배치가 수행되는 시점에 어떤 서비스의 로직 구현 정의가 Jakarta EE Endpoint가 될 것인지를 정의한다. Java 클래스의 경우에는 web.xml의 서블릿 정의를 가리키고, EJB Endpoint의 경우에는 ejb-jar.xml의 session 정의를 가리킨다.
JSE의 경우에는 <servlet-link>에 정의되며 예는 다음과 같다.
[예 25.2] DocLitEchoService : <webservices.xml>
<?xml version="1.0"?>
<webservices …>
<webservice-description>
<webservice-description-name>
DocLitEchoService
</webservice-description-name>
<wsdl-file>WEB-INF/wsdl/DocLitEchoService.wsdl</wsdl-file>
<jaxrpc-mapping-file>
WEB-INF/DocLitEchoService-mapping.xml
</jaxrpc-mapping-file>
<port-component>
<port-component-name>EchoPort</port-component-name>
<wsdl-port xmlns:ns2="urn:DocLitService">
ns2:EchoPort
</wsdl-port>
<service-endpoint-interface>
jeustest.webservices.java2wsdl.doclit.Echo
</service-endpoint-interface>
<service-impl-bean>
<servlet-link>EchoServlet</servlet-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>
<serlvet-link>의 값은 web.xml 내의 <servlet-name>의 값과 일치해야 한다.
[예 25.3] DocLitEchoService : <web.xml>
<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<servlet>
<servlet-name>EchoServlet</servlet-name>
<servlet-class>
jeustest.webservices.java2wsdl.doclit.EchoImpl
</servlet-class>
. . .
</servlet>
</web-app>
위와 마찬가지로 EJB Endpoint 웹 서비스의 경우 <ejb-link>를 사용하여 정의한다.
[예 25.4] AddressBookService : <webservices.xml>
<?xml version="1.0"?>
<webservices …>
<webservice-description>
<webservice-description-name>
AddressBookService
</webservice-description-name>
<wsdl-file>META-INF/wsdl/AddressBookService.wsdl</wsdl-file>
<jaxrpc-mapping-file>
META-INF/AddressBookService-mapping.xml
</jaxrpc-mapping-file>
<port-component>
<port-component-name>
AddressBookIFPort
</port-component-name>
<wsdl-port xmlns:ns2="urn:AddressBookService">
ns2:AddressBookIFPort
</wsdl-port>
<service-endpoint-interface>
address.AddressBookIF
</service-endpoint-interface>
<service-impl-bean>
<ejb-link>AddressEJB</ejb-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>
<ejb-link>의 값은 ejb-jar.xml 파일 내의 <ejb-name>의 값과 일치해야 한다.
[예 25.5] AddressBookService : <web.xml>
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar …>
<display-name>AddressEJB</display-name>
<enterprise-beans>
<session>
<display-name>AddressEJB</display-name>
<ejb-name>AddressEJB</ejb-name>
<service-endpoint>
address.AddressBookIF</service-endpoint>
<ejb-class>address.AddressBookEJB</ejb-class>
. . .
</session>
</enterprise-beans>
</ejb-jar>
한 가지 유의해야 할 사항은 <servlet-link>나 <ejb-link>를 통해 연결될 대상들은 webservices.xml를 포함하는 압축 파일 안에 존재해야 한다는 것이다.
메시지 핸들러는 Jakarta EE Endpoint가 보내고 받는 메시지를 걸러서 가공하는 역할을 한다.
webservices.xml 파일 안에서 이 메시지 핸들러들을 설정하고, 처리 순서를 지정할 수 있다. 메시지 핸들러에 대한 더 자세한 설명은 “제24장 JAX-RPC 웹 서비스 SOAP 메시지 핸들러 생성”을 참고한다.
다음은 핸들러를 설정한 webservices.xml의 작성 예이다.
[예 25.6] FileAttachmentService : <webservices.xml>
<?xml version="1.0"?>
<webservices version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee">
<webservice-description>
. . .
<port-component>
<port-component-name>FileAttPort</port-component-name>
. . .
<handler>
<handler-name>ServerAttachmentHandler</handler-name>
<handler-class>
filetransfer.ServerAttachmentHandler
</handler-class>
<init-param>
<param-name>directory</param-name>
<param-value>/temp</param-value>
</init-param>
</handler>
</port-component>
</webservice-description>
</webservices>
다음은 <handler>의 하위 항목에 대한 설명이다.
항목 | 설명 |
---|---|
<handler-name> | 정의되는 값은 webservices.xml 파일 안에서 유일한 값이 되어야 하며, 설정한 핸들러에 대한 식별자 역할을 한다. |
<handler-class> | 핸들러를 구현한 클래스를 정의한다. 정의되는 핸들러 클래스는 javax.xml.rpc.handler.Handler 인터페이스를 직접 또는 간접적으로 구현해야 한다. |
<init-param> | 필수 사항은 아니며 메시지 핸들러의 생성 주기의 시작 단계에서 핸들러를 초기화하기 위해 전달될 파라미터를 정의한다. 런타임에 HandlerInfo.getHandlerConfig() 메소드를 실행해서 얻어지는 java.util.Map 객체로부터 파라미터들을 가져 올 수 있다. |
<soap-header> | 핸들러가 처리해야 하는 SOAP Header 블록의 큐 네임(Q Name : Qualified Name)을 정의하며, <handler>는 하나 이상의 <soap-header>를 포함할 수 있다. |
<soap-role> | Header 블록을 처리할 때 핸들러가 정하는 역할을 정의한다. <soap-role> 값이 <soap-header>와 짝을 이루어서 정의될 때에만 어떤 Header 블록을 핸들러가 처리하는지 정확하게 알 수 있다. SOAP 메시지는 각각의 Header 블록을 처리하기 위한 역할을 명시적으로 지정할 수 있다. actor 속성이 정의되어 있으면 지정된 역할을 수행하는 노드만이 Header 블록을 처리하고, actor 속성이 정의 되지 않은 경우에는 최종적인 메시지 수신자가 header 블록을 처리한다. |
JAX-RPC 매핑 파일은 JEUS 웹 서비스에 내장된 JAX-RPC 컴파일러가 WSDL 문서와 웹 서비스 Endpoint를 나타내는 Java 인터페이스의 관계를 이해하는 것을 도와준다. 많은 경우에 WSDL과 Java의 매핑은 매핑 파일이 없어도 큰 문제가 없지만 명시적인 정의가 필요할 때가 있으며, 그러한 필요에 의해서 JAX-RPC 매핑 파일이 도입되었다.
JAX-RPC 매핑 파일은 Jakarta EE 웹 서비스 Endpoint나 Jakarta EE 웹 서비스 클라이언트를 사용할 때마다 필요하며, WSDL 문서와 JAX-RPC 매핑 파일은 1대 1로 대응한다. 즉, 각각의 WSDL 파일에는 하나씩의 JAX-RPC 매핑 파일이 존재한다.
JAX-RPC 매핑 파일은 다음과 같은 관계에 있는 요소들의 매핑을 정의한다.
XML 복합 타입(Complex Type)과 Java Bean
Fault 메시지와 예외 클래스
WSDL의 portType 정의와 SEI(Service Endpoint Interface)
WSDL의 서비스 정의와 서비스 인터페이스
JAX-RPC 매핑 파일에 정의되지 않은 것들은 WSDL과 XML의 Java로의 표준 매핑 법칙을 따라서 매핑된다. 그리고 매핑 파일에서 정의 되는 것들은 항상 표준 매핑 법칙에 우선한다.
매핑 파일은 상당히 내용이 복잡해 보이고, 크기에 있어서도 단일 설정 파일 중에 큰 편이다.
전체적인 설정 파일의 구성은 다음과 같다.
[예 25.7] JAX-RPC 매핑 파일의 구조
<java-wsdl-mapping> <package-mapping/> <java-xml-type-mapping/> <exception-mapping/> <service-interface-mapping/> <service-endpoint-interface-mapping> <service-endpoint-method-mapping/> <service-endpoint-method-mapping/> . . . </service-endpoint-interface-mapping> <service-interface-mapping/> <service-endpoint-interface-mapping> <service-endpoint-method-mapping/> <service-endpoint-method-mapping/> . . . </service-endpoint-interface-mapping> </java-wsdl-mapping>
JAX-RPC 매핑 파일의 최상위 element이며, 다른 매핑 element들을 포함하고 있다.
JAX-RPC 컴파일러가 WSDL에 정의된 여러 가지 타입에 대해 Java 클래스와 인터페이스 정의를 생성하려고 할 경우 사용된하는 항목으로 반드시 설정되어야 한다.
<package-type>의 값은 Java 패키지의 이름이며, <namespaceURI>의 값은 지정된 Java 패키지로 매핑되어야 하는 XML 이름 공간이다.
<java-wsdl-mapping version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee"> <package-mapping> <package-type>address</package-type> <namespaceURI>urn:AddressBookService</namespaceURI> </package-mapping> . . . </java-wsdl-mapping>
XML Schema 복합 타입(Complex Type)이나 단순 타입(Simple Type)을 사용할 때 필요하며, XML Schema와 Java 타입 간의 관계를 정의한다. XML Schema에 정의된 built-in 타입이 Java로 표준적인 매핑이 된다면 이 element를 사용하지 않아도 된다.
<java-wsdl-mapping version="1.1"
xmlns="http://java.sun.com/xml/ns/j2ee">
. . .
<java-xml-type-mapping>
<java-type>address.Address</java-type>
<ns1:root-type-qname
xmlns:ns1=”http://java.sun.com/xml/ns/j2ee”
xmlns="urn:AddressBookService">
Address
</ns1:root-type-qname>
<qname-scope>complexType</qname-scope>
<variable-mapping>
<java-variable-name>addr</java-variable-name>
<xml-element-name>addr</xml-element-name>
</variable-mapping>
<variable-mapping>
<java-variable-name>street</java-variable-name>
<xml-element-name>street</xml-element-name>
</variable-mapping>
<variable-mapping>
<java-variable-name>zipcode</java-variable-name>
<xml-element-name>zipcode</xml-element-name>
</variable-mapping>
</java-xml-type-mapping>
. . .
</java-wsdl-mapping>
WSDL 결함(fault) 메시지를 Java 예외 클래스로 매핑한다.
<java-xml-mapping>
. . .
<exception-mapping>
<exception-type>CLASS_NAME</exception-type>
<wsdl-message>WSDL_MESSAGE_NAME</wsdl-message>
</exception-mapping>
. . .
</java-xml-mapping>
WSDL의 서비스 정의를 JAX-RPC 서비스 인터페이스 타입으로 매핑한다.
<service-interface>는 WSDL의 서비스 정의를 나타내는 Java 인터페이스의 클래스 이름을 정의하고, 서비스 인터페이스의 패키지 이름은 <package-mapping>에 정의된 패키지 이름과 일치해야 한다.
<port-mapping>는 서비스 인터페이스의 getPortName() 메소드의 포트 이름을 WSDL의 <port>와 대응하게 정의한다.
<java-xml-mapping…>
. . .
<service-interface-mapping>
<service-interface>
address.AddressBookService
</service-interface>
<ns3:wsdl-service-name
xmlns:ns3="http://java.sun.com/xml/ns/j2ee"
xmlns="urn:AddressBookService">
AddressBookService
</ns3:wsdl-service-name>
<port-mapping>
<port-name>AddressBookIFPort</port-name>
<java-port-name>AddressBookIFPort</java-port-name>
</port-mapping>
</service-interface-mapping>
. . .
</java-xml-mapping>
위와 같이 정의될 경우 생성되는 Java 서비스 인터페이스 정의는 다음과 같다.
[예 25.8] Java 서비스 인터페이스 정의 : <AddressBookService.java>
package address; public interface AddressBookService extends javax.xml.rpc.Service { public java.lang.String getAddressBookIFPortAddress(); public address.AddressBookIF getAddressBookIFPort() throws javax.xml.rpc.ServiceException; public address.AddressBookIF getAddressBookIFPort(java.net.URL portAddress) throws javax.xml.rpc.ServiceException; }
<service-endpoint-interface-mapping>
SEI를 WSDL의 portType과 바인딩 정의로 매핑한다. 이 element는 JAX-RPC 컴파일러가 적절한 Endpoint Stub과 Endpoint 인터페이스를 생성할 때 필요한 정보를 제공한다. 또한 WSDL의 operation과 message part 정의가 어떻게 Java Endpoint 메소드의 정의로 매핑될 것인지에 대한 상세 정보를 제공한다.
다음은 AddressBookService의 매핑 파일에 정의된 예이다.
<java-wsdl-mapping…>
. . .
<service-endpoint-interface-mapping>
<service-endpoint-interface>
address.AddressBookIF
</service-endpoint-interface>
<ns4:wsdl-port-type
xmlns:ns4="http://java.sun.com/xml/ns/j2ee"
xmlns="urn:AddressBookService">
AddressBookIF
</ns4:wsdl-port-type>
<ns5:wsdl-binding
xmlns:ns5="http://java.sun.com/xml/ns/j2ee"
xmlns="urn:AddressBookService">
AddressBookIFSoapBinding
</ns5:wsdl-binding>
<service-endpoint-method-mapping>
<java-method-name>add</java-method-name>
<wsdl-operation>add</wsdl-operation>
<wrapped-element/>
<method-param-parts-mapping>
<param-position>0</param-position>
<param-type>address.PersonInfo</param-type>
<wsdl-message-mapping>
<ns6:wsdl-message
xmlns:ns6="http://java.sun.com/xml/ns/j2ee"
xmlns="urn:AddressBookService">
addRequest
</ns6:wsdl-message>
<wsdl-message-part-name>
parameters
</wsdl-message-part-name>
<parameter-mode>IN</parameter-mode>
</wsdl-message-mapping>
</method-param-parts-mapping>
<wsdl-return-value-mapping>
<method-return-value>
address.PersonInfo[]
</method-return-value>
<ns7:wsdl-message
xmlns:ns7=”http://java.sun.com/xml/ns/j2ee“
xmlns="urn:AddressBookService">
addResponse
</ns7:wsdl-message>
<wsdl-message-part-name>
parameters
</wsdl-message-part-name>
</wsdl-return-value-mapping>
</service-endpoint-method-mapping>
. . .
</service-endpoint-interface-mapping>
. . .
</java-wsdl-mapping>