웹 서비스 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을 설정하기 위해서는 다음과 같이 단순히 javax.jws.WebService Annotation과 더불어 javax.xml.ws.soap.Addressing Annotation을 추가하면 모든 웹 서비스 Addressing 설정은 완료된다.

서버 웹 서비스 Addressing 설정 (1) : <AddnumbersImpl.java>
@Addressing
@WebService
public class AddNumbersImpl {
    ...
}

위와 같이 javax.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 설정 (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에 바인딩된다.

서버 웹 서비스 Addressing 설정 (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>
...

2.2. WSDL로부터 설정

WSDL로부터 웹 서비스를 구성할 때는 위의 Java 클래스로부터 WSDL을 생성했을 때와 마찬가지로 표준 확장 element인 <wsaw:UsingAddressing>을 이용한다. 이렇게 구성된 웹 서비스는 JEUS에서 제공하는 wsimport 툴을 사용하여 간단히 Addressing을 지원하는 웹 서비스를 생성할 수 있다.

3. 클라이언트 설정

클라이언트의 웹 서비스 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());

4. 예제

다음은 예제에서 다루는 서비스 Endpoint 구현 클래스의 예이다.

웹 서비스 Addressing : <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을 구성하고 있는 것을 확인할 수 있다.

5. 예제 실행

위와 같이 구성한 웹 서비스 Addressing을 설정한 Endpoint 클래스들 및 기타 파일들을 사용해서 서비스를 구성하여 JEUS 21에 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 2.2 - JEUS 21
<?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 2.2 - JEUS 21
<?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>
--------------------
...