내용 목차
본 장에서는 트랜스포트에 독립적인 웹 서비스 Addressing에 대해 알아보고 간단한 예제를 통해 사용법을 설명한다.
웹 서비스 Addressing은 트랜스포트(transport)에 독립적으로 웹 서비스 메시지에 주소와 같은 정보를 표기하는 방식을 의미한다. 기본적인 웹 서비스는 무상태의 메시지들의 교환이기 때문에 웹 서비스의 Addressing을 이용하면 상태를 알 수 있는 웹 서비스의 지원이 가능해진다. 실제로 웹 서비스 Addressing은 이후 장에서 설명할 WS-RM, WS-Security, WS-secure Conversation, WS-Trust등 상당수 WS-* 스펙들의 기반 기술이다.
웹 서비스 Addressing은 웹 서비스가 실행되고 있는 트랜스포트가 HTTP이든 SMTP이든 상관없이 동작하게 된다. 이러한 웹 서비스 Addressing이 동작하는 모습을 메시지 수준에서 보면 다음과 같다. 우선 웹 서비스 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와 같은 것으로 변환한다면 트랜스포트 헤더에 있는 정보 또한 그에 따른 매핑 규칙에 따라 변환해야 하는등 많은 어려움이 뒤따른다.
따라서 이를 위해 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 메시지로의 바인딩 형태이며 다음과 같은 의미를 갖는다.
구분 | 설명 |
---|---|
wsa:MessageID | 메시지를 유일하게 구분할 수 있도록 하는 절대 URI로 설정된 값이다. |
wsa:To | 메시지를 전달받도록 의도된 곳의 주소를 나타내기 위한 절대 URI로 설정된 값이다. |
wsa:Action | 메시지가 의미하는 바를 나타내기 위한 절대 URI로 설정된 값이다. |
이와 같은 웹 서비스 Addressing 메시지는 웹 서비스 Addressing을 설정하지 않고 전달되는 메시지의 모든 정보들이 트랜스포트 혹은 애플리케이션과 독립적으로 프로세싱될 수 있는 고유의 형태로 들어 있는 것을 알 수 있다.
예를 들어 이러한 메시지가 다른 트랜스포트로 전달되어야 한다면, 예를 들어 HTTP가 아닌 SMTP와 같은 트랜스포트로 전달되어야 한다면 wsa:To 헤더의 값이 mailto:purchasing@example.com과 같은 값으로 변경하기만 하면 된다.
Java 클래스로부터 웹 서비스를 구성할 때 웹 서비스 Addressing을 설정하기 위해서는 다음과 같이 단순히 javax.jws.WebService Annotation과 더불어 javax.jws.soap.Addressing Annotation을 추가하면 모든 웹 서비스 Addressing 설정은 완료된다.
위와 같이 javax.jws.soap.Addressing Annotation을 통해 웹 서비스 Addressing을 설정하면 이를 통해 서비스 Endpoint는 다음과 같은 동작을 수행하게 된다.
생성되는 WSDL 문서의 wsdl:binding element에 표준 wsaw:UsingAddressing element가 생성된다.
받아들이는 메시지의 모든 웹 서비스 Addressing 헤더들을 해석한다.
받아들이는 메시지의 모든 웹 서비스 Addressing 헤더들에 대해 올바른 문법인지를 검사한다.
받아들이는 메시지의 모든 웹 서비스 Addressing 헤더들에 대해 올바른 문법인지를 검사하고 그렇지 않은 경우, 오류 메시지를 전달한다.
wsa:Action 헤더값이 그 오퍼레이션에 대해 기대한 값과 일치하지 않을 경우, 오류 메시지를 전달한다.
모든 전달되는 메시지에는 웹 서비스 Addressing 헤더에 대한 정보를 포함하고 있다.
또한 웹 서비스 Addressing은 서비스 Endpoint 인터페이스의 메소드(WSDL 문서의 operation element)에 대해 다음과 같이 Action MAP(Message Addressing Property)를 직접 설정할 수 있다.
[예 14.2] << AddnumbersImpl.java >>
@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에 바인딩된다.
[예 14.3] << Addnumbers.wsdl >>
... <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> ...
클라이언트 사이드의 웹 서비스 Addressing 설정은 클라이언트 사이드가 클라이언트를 생성하기 위해 참조하는 WSDL 문서의 wsaw:UsingAddressing이 포함되어 있는지 여부에 따라 자동으로 wsimport 툴에 의해 결정된다. 웹 서비스 Addressing이 설정된 서비스로부터 클라이언트를 구성할 때 이러한 웹 서비스 Addressing 기능을 동작시키고 싶지 않은 경우가 있는데, 클라이언트가 따로 이러한 웹 서비스 Addressing 기능을 애플리케이션 레벨에서 수행하고 있을 때이다.
다음은 클라이언트에서 웹 서비스의 Addressing 기능을 동작시키고 싶지 않을 경우 사용할 수 있는 방법이다.
new AddNumbersImplService().getAddNumbersImplPort( new javax.xml.ws.AddressingFeature(false));
위와 같이 클라이언트로부터 프록시(Endpoint Interface)를 얻을 때 javax.xml.ws.AddressingFeature의 값을 false로 해서 얻으면 클라이언트는 메시지를 전송할 때 서비스에서 WSDL에 규정하고 있는 웹 서비스 Addressing 기능을 동작하지 않은 상태로 메시지를 전송하게 된다.
또한 서비스의 WSDL에 웹 서비스의 Addressing 기능을 나타내는 wsaw:UsingAddressing을 포함하고 있지 않을 때 wsimport 툴을 통해 얻은 Portable Artifact들은 순수한 웹 서비스의 기능만을 수행한다. 클라이언트에서 따로 웹 서비스의 Addressing 기능을 동작하고 싶은 경우가 있는데 이런 경우에는 다음과 같이 javax.xml.ws.Service가 지원하는 메소드들을 사용하거나 javax.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, javax.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 javax.xml.ws.AddressingFeature());
다음은 예제에서 다루는 서비스 Endpoint 구현 클래스의 예이다.
[예 14.4] << AddNumbersImpl.java >>
@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을 구성하고 있음을 알 수 있다.
위와 같이 구성한 웹 서비스 Addressing을 설정한 Endpoint 클래스들 및 기타 파일들을 가지고 서비스를 구성하여 JEUS 6에 디플로이하는 방법은 다음과 같다.
C:\>ant deploy
위의 과정이 모두 실행되어 서비스가 정상적으로 디플로이되면, 클라이언트를 실행한다. 클라이언트 콘솔과 서버 콘솔 화면으로부터 다음과 같이 정상적으로 메시지를 전달하는 모습을 알 수 있다.
C:\>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: Java/1.5.0_09 <?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: Java/1.5.0_09 <?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> -------------------- ...