웹 서비스 트랜잭션

본 장에서는 웹 서비스 트랜잭션에 대한 개념과 설정 방법에 대해서 설명한다.

1. 개요

트랜잭션은 신뢰성있는 분산 애플리케이션을 구현할 때 기본이 되는 개념이다. 트랜잭션은 애플리케이션에 참여하는 모든 참여인들(participants)이 서로 동의한 결과를 얻을 수 있도록 하는 메커니즘이다.

전통적으로 트랜잭션은 일명 "ACID"라는 다음 속성들을 포함하고 있다.

구분 설명

원자성(Atomicity)

성공적일 경우 모든 작동이 발생하고, 실패라면 어떤 작동도 발생하지 않는다.

일관성(Consistency)

애플리케이션은 완료될 때 유효한 상태 변환을 수행한다.

고립성(Isolated)

작동 결과는 성공적으로 끝나기 전까지 트랜잭션 외부에서는 공유되지 않는다.

지속성(Durability, 영속성)

일단 트랜잭션이 성공적으로 완료되면 변경으로 실패를 다시 복구할 수 있다.

웹 서비스 환경은 애플리케이션의 작동과 결과를 제어하기 위해 전통적인 트랜잭션 메커니즘에 의해 제공되는 동일한 코디네이션 작동이 필요하다. 또한 유연한 방식으로 다중 서비스에서 산출된 결과들의 프로세싱 코디네이션을 핸들링할 기능도 필요하다. 이것에는 좀 더 자유로운 형식의 트랜잭션이 필요하다.

JEUS 21 웹 서비스에서 다음의 트랜잭션 스펙을 지원한다.

  • WS-Coordination

  • WS-AtomicTransaction

위 트랜잭션 스펙은 협동하고 있는 작동들에 대한 WSDL 정의를 제공한다.

2. 서버 설정

서버에서 웹 서비스 트랜잭션은 WSDL로부터 설정하거나 Java 클래스로부터 설정할 수 있다.

2.1. WSDL로부터 설정

웹 서비스 트랜잭션을 WSDL로부터 구현하려면 웹 서비스 Addressing의 경우와 마찬가지로 WSDL 문서에 웹 서비스 정책 설정을 하여 wsimport 툴을 사용하여 웹 서비스를 생성한다.

웹 서비스 정책 설정에 따라 WSDL 파일에 웹 서비스 트랜잭션을 알맞게 설정하려면 기본적으로 PolicyAssertion에 다음을 설정한다.

<wsat200410:ATAssertion xmlns:ns1="http://schemas.xmlsoap.org/ws/2002/12/policy" />

웹 서비스 트랜잭션 정책을 설정한 WSDL 파일은 다음과 같다.

WSDL 웹 서비스 트랜잭션 설정 : <AddNumbers.wsdl>
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="AddNumbersService" targetNamespace="http://server.fromwsdl/"
    xmlns:tns="http://server.fromwsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/
    oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
    xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <wsp:Policy xmlns:wsat200410="http://schemas.xmlsoap.org/ws/2004/10/wsat"
        wsu:Id="AddNumbersPortBinding_addNumbers_WSAT_Policy" wsp:Name="">
        <wsat200410:ATAssertion
            xmlns:ns1="http://schemas.xmlsoap.org/ws/2002/12/policy"
            wsp:Optional="true" ns1:Optional="true" />
    </wsp:Policy>
    <types>...</types>
    <message>...</message>
    <portType>...</portType>

    <binding name="AddNumbersPortBinding" type="tns:AddNumbers">
       <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
       <operation name="addNumbers">
        <wsp:PolicyReference URI="#AddNumbersPortBinding_addNumbers_WSAT_Policy" />
         <soap:operation soapAction="addNumbers" />
         <input>
           <wsp:PolicyReference URI="#AddNumbersPortBinding_addNumbers_WSAT_Policy" />
             <soap:body use="literal" />
         </input>
         <output>
           <wsp:PolicyReference URI="#AddNumbersPortBinding_addNumbers_WSAT_Policy" />
             <soap:body use="literal" />
         </output>
       </operation>
    </binding>
    <service>...</service>
<definitions>

2.2. Java 클래스로부터 설정

Java 클래스로부터 웹 서비스 트랜잭션을 설정하려면 웹 서비스 Endpoint 구현체 클래스에 다음의 Annotation을 붙인다.

@com.sun.xml.ws.api.tx.at.Transactional(version=com.sun.xml.ws.api.tx.at.Transactional.Version.WSAT10)

다음은 Java 클래스로부터 웹 서비스 트랜잭션을 설정한 예제이다.

Java 클래스 웹 서비스 트랜잭션 설정 : <AddnumbersImpl.java>
@WebService
@com.sun.xml.ws.api.tx.at.Transactional(
       version=com.sun.xml.ws.api.tx.at.Transactional.Version.WSAT10)
public class AddNumbersImpl {
    ...
}

3. 클라이언트 설정

웹 서비스 트랜잭션을 위한 클라이언트 사이드의 추가적인 설정은 필요하지 않다. JEUS 웹 서비스는 클라이언트의 런타임에 원격 웹 서비스 WSDL의 웹 서비스 트랜잭션 정책을 해석해서 자동으로 웹 서비스 트랜잭션을 위한 환경을 제공한다.

4. 코디네이터 서비스

웹 서비스 트랜잭션을 사용하기 위해서는 트랜잭션 참여자 간의 트랜잭션 액티비티를 조율하는 코디네이터 서비스를 deploy해야 한다. 코디네이터 서비스는 서버와 클라이언트에 모두 필요하다. 웹 서비스와 웹 서비스 클라이언트가 같은 서버에서 동작하면 하나의 코디네이터 서비스만 deploy한다.

코디네이터 서비스를 위한 wstx-services.ear은 다음 경로의 디렉터리에 위치한다.

JEUS_HOME/lib/systemapps

5. 웹 서비스 트랜잭션 예제

Java 클래스로부터의 구현은 @com.sun.xml.ws.api.tx.at.Transactional annotaion을 붙이는 것을 제외한 나머지 설정은 기본적인 JEUS 21 웹 서비스와 동일하다.

웹 서비스 클라이언트에서는 JTA(Java Transaction API)를 사용하여 프로그래밍한다.

웹 서비스 트랜잭션 : <AddNumbersClient.jsp>
InitialContext  ctx = new InitialContext();
UserTransaction utx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");

AddNumbersImplService service = new AddNumbersImplService();
AddNumbersImpl port = service.getAddNumbersImplPort();

utx.begin();

int result = port.addNumbers(number1, number2);

utx.commit();