웹 서비스 Addressing
본 장에서는 트랜스포트에 독립적인 웹 서비스 Addressing과 그에 대한 간단한 예제를 통해 사용법을 설명한다.
1. 개요
웹 서비스 Addressing은 트랜스포트(transport)에 독립적으로 웹 서비스 메시지에 주소와 같은 정보를 표기하는 방식을 의미한다. 기본적인 웹 서비스는 Stateless의 메시지들의 교환이기 때문에 웹 서비스의 Addressing을 이용하면 상태를 알 수 있는 웹 서비스의 지원이 가능해진다. 실제로 웹 서비스 Addressing은 이후 장에서 설명할 WS-RM, WS-Security, WS-secure Conversation, WS-Trust 등 상당수 "WS-*" 스펙들의 기반 기술이다.
웹 서비스 Addressing은 웹 서비스가 실행되고 있는 트랜스포트가 HTTP이든 SMTP이든 상관없이 동작하게 된다. 웹 서비스 Addressing을 설정하지 않고 애플리케이션 레벨에서 어떤 메시지에 정보를 표기하려면 메시지는 다음과 같은 모습을 나타난다.
POST /AddNumbers/addnumbers HTTP 1.1/POST Host: tmaxsoft.com SOAPAction: http://tmaxsoft.com/AddNumbers/addnumbers <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:tmax="http://tmaxsoft.com/"> <S:Header> <tmax:MessageID> uuid:e197db59-0982-4c9c-9702-4234d204f7f4 </tmax:MessageID> </S:Header> <S:Body> ... </S:Body> </S:Envelope>
위와 같이 웹 서비스 Addressing을 설정하지 않은 메시지의 모습을 통해 알 수 있듯이 우선 이 메시지에 애플리케이션 나름으로 부여한 ID는 이 애플리케이션 레벨에서 사용하기 위해 설정한 것이므로 다른 애플리케이션에서의 재사용이 어렵다. 또한 트랜스포트를 HTTP에서 SMTP와 같은 것으로 변환한다면 트랜스포트 Header에 있는 정보 또한 그에 따른 매핑 규칙에 따라 변환해야 하는 등 많은 어려움을 수반한다. 따라서 이를 위해 W3C에서는 웹 서비스 Addressing을 위해 MAP(Message Addressing Properties)을 정의해서 SOAP 메시지나 WSDL 문서로의 바인딩(binding)을 규정해 놓았다.
다음은 메시지 레벨에서 이러한 MAP의 정보가 담긴 웹 서비스 Addressing을 설정한 메시지의 예제이다.
POST /AddNumbers/addnumbers HTTP 1.1/POST Host: tmaxsoft.com SOAPAction: http://tmaxsoft.com/AddNumbers/addnumbers <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing/"> <S:Header> <wsa:MessageID> uuid:e197db59-0982-4c9c-9702-4234d204f7f4 </wsa:MessageID> <wsa:To> http://tmaxsoft.com/AddNumbers/addnumbers </wsa:To> <wsa:Action> http://tmaxsoft.com/AddNumbers/addnumbers </wsa:Action> </S:Header> <S:Body> ... </S:Body> </S:Envelope>
웹 서비스 Addressing을 설정한 메시지의 SOAP 메시지를 보면 <wsa:MessageID>, <wsa:To>, <wsa:Action> 같은 웹 서비스 Addressing에 관련된 element로 구성되어 있는 것을 알 수 있다. 이들은 MAP(Message Addressing Properties)의 SOAP 메시지로의 바인딩 형태이다.
다음은 각 element에 대한 설명이다.
element | 설명 |
---|---|
<wsa:MessageID> |
메시지를 유일하게 구분할 수 있도록 하는 절대 URI로 설정된 값이다. |
<wsa:To> |
메시지를 전달받도록 의도된 곳의 주소를 나타내기 위한 절대 URI로 설정된 값이다. |
<wsa:Action> |
메시지가 의미하는 바를 나타내기 위한 절대 URI로 설정된 값이다. |
이와 같은 웹 서비스 Addressing 메시지는 모든 정보들이 트랜스포트 또는 애플리케이션과 독립적으로 프로세싱될 수 있는 고유의 형태로 들어 있는 것을 알 수 있다. 예를 들어 이러한 메시지가 HTTP가 아닌 SMTP와 같은 다른 트랜스포트로 전달되어야 한다면 <wsa:To> Header의 값을 mailto:purchasing@example.com과 같은 값으로 변경한다.
본 절에서는 서버와 클라이언트에서 웹 서비스 Addressing을 설정하는 방법과 예제와 실행방법에 대해서 설명한다.
2. 서버 설정
서버에서 웹 서비스 Addressing 설정은 Java 클래스로부터 설정하는 방법과 WSDL로부터 설정하는 방법이 있다. 본 절에서는 각 방법에 대해서 설명한다.
2.1. Java 클래스로부터 설정
Java 클래스로부터 웹 서비스를 구성할 때 웹 서비스 Addressing을 설정하기 위해서는 다음과 같이 단순히 jakarta.jws.WebService Annotation과 더불어 jakarta.xml.ws.soap.Addressing Annotation을 추가하면 모든 웹 서비스 Addressing 설정은 완료된다.
@Addressing @WebService public class AddNumbersImpl { ... }
위와 같이 jakarta.xml.ws.soap.Addressing Annotation을 통해 웹 서비스 Addressing을 설정하면 이를 통해 서비스 Endpoint는 다음과 같은 동작을 수행하게 된다.
-
생성되는 WSDL 문서의 <wsdl:binding> element에 표준 <wsaw:UsingAddressing> element가 생성된다.
-
받아들이는 메시지의 모든 웹 서비스 Addressing Header들을 해석해서 올바른 문법인지를 검사한다.
-
올바른 문법이 아닌 경우 오류 메시지를 전달한다.
-
<wsa:Action> Header 값이 해당 오퍼레이션에 대해 기대한 값과 일치하지 않을 경우 오류 메시지를 전달한다.
-
모든 전달되는 메시지에는 웹 서비스 Addressing Header에 대한 정보를 포함하고 있다.
또한 웹 서비스 Addressing은 SEI의 메소드(WSDL 문서의 operation element)에 대해 다음과 같이 Action MAP(Message Addressing Property)을 직접 설정할 수 있다.
@Addressing @WebService public class AddNumbersImpl { @Action( input = "http://tmaxsoft.com/input", output = "http://tmaxsoft.com/output", fault = { @FaultAction(className = AddNumbersException.class, value = "http://tmaxsoft.com/fault") } ) public int addNumbers(int number1, int number2) throws AddNumbersException { ... } }
이와 같이 설정된 메소드는 WSDL로 변환될 때 다음과 같은 WSDL 문서의 operation element에 바인딩된다.
... <operation name="addNumbers"> <input wsaw:Action="http://tmaxsoft.com/input" message="tns:addNumbers"/> <output wsaw:Action="http://tmaxsoft.com/output" message="tns:addNumbersResponse"/> <fault wsaw:Action="http://tmaxsoft.com/fault" message="tns:AddNumbersException" name="AddNumbersException"/> </operation> ... <binding name="AddNumbersImplPortBinding" type="tns:AddNumbersImpl"> <wsaw:UsingAddressing /> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="addNumbers"> <soap:operation soapAction="" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="addNumbers2"> <soap:operation soapAction="" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding> ...
3. 클라이언트 설정
클라이언트의 웹 서비스 Addressing 설정은 클라이언트를 생성하기 위해 참조하는 WSDL 문서의 <wsaw:UsingAddressing>이 포함되어 있는지 여부에 따라 wsimport 툴에 의해 자동으로 결정된다.
클라이언트가 별도로 웹 서비스 Addressing 기능을 애플리케이션 레벨에서 수행하고 있는 경우 웹 서비스 Addressing이 설정된 서비스로부터 클라이언트를 구성할 때 웹 서비스 Addressing 기능을 동작시키지 않을 수 있다.
다음은 클라이언트에서 웹 서비스의 Addressing 기능을 동작시키고 싶지 않을 경우 사용할 수 있는 방법이다.
new AddNumbersImplService().getAddNumbersImplPort( new jakarta.xml.ws.AddressingFeature(false));
위와 같이 클라이언트로부터 프록시(Endpoint Interface)를 얻을 때 jakarta.xml.ws.AddressingFeature의 값을 false로 설정하면 클라이언트는 메시지를 전송할 때 서비스에서 WSDL에 규정하고 있는 웹 서비스 Addressing 기능을 동작하지 않은 상태로 메시지를 전송하게 된다.
서비스의 WSDL에 웹 서비스의 Addressing 기능을 나타내는 wsaw:UsingAddressing을 포함하고 있지 않을 때 wsimport 툴을 통해 얻은 Portable Artifact들은 순수한 웹 서비스의 기능만을 수행한다. 클라이언트에서 별도로 웹 서비스의 Addressing 기능을 동작하고 싶은 경우가 있는데 이런 경우에는 다음과 같이 jakarta.xml.ws.Service가 지원하는 메소드들을 사용하거나 jakarta.xml.ws.soap.AddressingFeature를 사용한다.
<T> Dispatch<T> createDispatch(javax.xml.namespace.QName, java.lang.Class<T>, Service.Mode, WebServiceFeature...) Dispatch<java.lang.Object> createDispatch(javax.xml.namespace.QName, jakarta.xml.bind.JAXBContext, Service.Mode, WebServiceFeature...) <T> T getPort(java.lang.Class<T>, WebServiceFeature...) <T> T getPort(javax.xml.namespace.QName, java.lang.Class<T>, WebServiceFeature...) new AddNumbersImplService().getAddNumbersImplPort( new jakarta.xml.ws.AddressingFeature());
4. 예제
다음은 예제에서 다루는 서비스 Endpoint 구현 클래스의 예이다.
@Addressing @WebService public class AddNumbersImpl { @Resource WebServiceContext wsc; @Action(input = "http://tmaxsoft.com/input", output = "http://tmaxsoft.com/output") public int addNumbers(int number1, int number2) { return number1 + number2; } public int addNumbers2(int number1, int number2) { return number1 + number2; } }
위와 같이 Addressing Annotation과 WSDL 문서의 operation element에 바인딩될 Action Annotation으로 웹 서비스 Addressing을 구성하고 있는 것을 확인할 수 있다.
5. 예제 실행
위와 같이 구성한 웹 서비스 Addressing을 설정한 Endpoint 클래스들 및 기타 파일들을 사용해서 서비스를 구성하여 JEUS 9에 deploy하는 방법은 다음과 같다.
$ ant deploy
위의 과정이 모두 실행되어 서비스가 정상적으로 deploy되면, 클라이언트를 실행한다.
클라이언트 콘솔과 서버 콘솔 화면으로부터 다음과 같이 정상적으로 메시지를 전달하는 모습을 확인할 수 있다.
$ ant run ... run: [java] ################################################ [java] ### JAX-WS Webservices examples - addressing ### [java] ################################################ [java] basic name mapping result: 20 [java] default name mapping result: 20 BUILD SUCCESSFUL ... ... ---[HTTP request]--- Host: localhost:8088 Content-length: 626 Content-type: text/xml; charset=utf-8 Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive Soapaction: "http://tmaxsoft.com/input" User-agent: JAX-WS RI 3.0 - JEUS 9 <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"> <S:Header> <wsa:To>http://localhost:8088/AddNumbers/addnumbers</wsa:To> <wsa:Action>http://tmaxsoft.com/input</wsa:Action> <wsa:ReplyTo xmlns:wsa="http://www.w3.org/2005/08/addressing"> <wsa:Address> http://www.w3.org/2005/08/addressing/anonymous </wsa:Address> </wsa:ReplyTo> <wsa:MessageID>uuid:880f3891-d07b-4ad1-bbc1-8dce8f1aedef</wsa:MessageID> </S:Header> <S:Body> <ns2:addNumbers xmlns:ns2="http://server.wsaddressing/"> <arg0>10</arg0><arg1>10</arg1> </ns2:addNumbers> </S:Body> </S:Envelope> ---[HTTP response 200]--- <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"> <S:Header> <wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To> <wsa:Action>http://tmaxsoft.com/output</wsa:Action> <wsa:MessageID>uuid:815cb296-a2f3-45df-80c5-5a2c1ca836ca</wsa:MessageID> <wsa:RelatesTo>uuid:880f3891-d07b-4ad1-bbc1-8dce8f1aedef</wsa:RelatesTo> </S:Header> <S:Body> <ns2:addNumbersResponse xmlns:ns2="http://server.wsaddressing/"> <return>20</return> </ns2:addNumbersResponse> </S:Body> </S:Envelope> -------------------- ... ---[HTTP request]--- Host: localhost:8088 Content-length: 663 Content-type: text/xml; charset=utf-8 Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive Soapaction: "http://server.wsaddressing/AddNumbersImpl/addNumbers2Request" User-agent: JAX-WS RI 3.0 - JEUS 9 <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"> <S:Header> <wsa:To>http://localhost:8088/AddNumbers/addnumbers</wsa:To> <wsa:Action> http://server.wsaddressing/AddNumbersImpl/addNumbers2Request </wsa:Action> <wsa:ReplyTo xmlns:wsa="http://www.w3.org/2005/08/addressing"> <wsa:Address> http://www.w3.org/2005/08/addressing/anonymous </wsa:Address> </wsa:ReplyTo> <wsa:MessageID>uuid:bf65c920-9129-495a-b9dc-8cb8efb9c2a6</wsa:MessageID> </S:Header> <S:Body> <ns2:addNumbers2 xmlns:ns2="http://server.wsaddressing/"> <arg0>10</arg0><arg1>10</arg1> </ns2:addNumbers2> </S:Body> </S:Envelope> ---[HTTP response 200]--- <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"> <S:Header> <wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To> <wsa:Action> http://server.wsaddressing/AddNumbersImpl/addNumbers2Response </wsa:Action> <wsa:MessageID>uuid:41975002-46e8-4219-89a6-ed6e72899fa8</wsa:MessageID> <wsa:RelatesTo>uuid:bf65c920-9129-495a-b9dc-8cb8efb9c2a6</wsa:RelatesTo> </S:Header> <S:Body> <ns2:addNumbers2Response xmlns:ns2="http://server.wsaddressing/"> <return>20</return> </ns2:addNumbers2Response> </S:Body> </S:Envelope> -------------------- ...