본문 바로가기

웹서비스

AXIS2에서 SOAP Header 다루기 Part 1~3(AXIS2 Module).

출처 : http://cyberhp.egloos.com/1424917

웹서비스를 통해 통신을 수행하는 경우 간혹 SOAP Header의 정보를 읽거나 넣어야 하는 경우가 있다.

AXIS2를 사용하는 경우 어떻게 SOAP Header에 접근하고 해당 정보를 읽고 쓰는지 알아보자.

Part1은 Consumer 부분이다.
샘플로 넣을 SOAP Header는 아래와 같다고 가정하자.
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<myprefix:mykey xmlns:myprefix="http://com.egloos.cyberhp/xsd">KEY0001</myprefix:mykey>
<myprefix:myvalue xmlns:myprefix="http://com.egloos.cyberhp/xsd">VALUE002</myprefix:myvalue>
</soapenv:Header>

AXIS2를 이용하여 웹서비스 클라이언트를 만드는 경우에는 다음과 같이 SOAP Header를 다룰 수 있다.
먼저, SOAP Header에 값을 추가하는 코드이다.

RPCServiceClient client = new RPCServiceClient(); // ServiceClient를 사용해도 동일하다.
String ns = "http://com.egloos.cyberhp/xsd";
client.addStringHeader(new QName(ns, "mykey", "myprefix"), "KEY0001");
client.addStringHeader(new QName(ns, "myvalue", "myprefix"), "VALUE002");
취소한 것처럼 사용하면 동작은 정상적으로 하나 DEBUG 로그에 normal OMElement를 사용하지 말고 SOAPHeaderBlock을 사용하라고 나온다. DEBUG 로그도 깔끔하게 하고 싶다면 다음과 같이 처리한다.

SOAPFactory factory = OMAbstractFactory.getSOAP11Factory();
OMNamespace namespace = factory.createOMNamespace(ns, "myprefix");
SOAPHeaderBlock myKeyBlock = factory.createSOAPHeaderBlock("mykey", namespace);
myKeyBlock.setText("KEY0001");
client.addHeader(myKeyBlock);
SOAPHeaderBlock myValueBlock = factory.createSOAPHeaderBlock("myvalue", namespace);
myValueBlock.setText("VALUE002");
client.addHeader(rmyValueBlock);

위와 같이 기술하고 전송하면 Provider에서 SOAP Header에 추가된 것을 볼 수 있다.
반대로, Provider에서 SOAP Header에 위의 값을 넣어서 보내준 것을 추출해 내는 코드는 다음과 같다.

MessageContext mc = client.getLastOperationContext().getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
SOAPEnvelope soap = mc.getEnvelope();
SOAPHeader header = soap.getHeader();

header까지 얻어내었으므로 해당 하는 값을 XPath를 사용하든, 직접 Child API를 호출하여 사용하여 얻어낼 수 있다.

다음 Part 2에서는 Provider쪽에서 SOAP Header의 값을 얻어내거나 쓰는 방법에 대해 기술한다.

AXIS2에서 SOAP Header를 다루는 두번째 글이다.

첫번째에서는 Consumer 단에서 어떻게 SOAP Header를 얻어내고 넣고 하는지를 알아봤다. 이제는 Provider 쪽이다.
Consumer에서 보낸 SOAP Header는 Provider에서 다음과 같이 얻어낼 수 있다.

MessageContext mc = MessageContext.getCurrentMessageContext();
SOAPEnvelope soap = mc.getEnvelope();

SOAPHeader header = soap.getHeader();


위와 같이 사용하면 Provider에서는 어느 곳에서든 SOAP Header를 얻어낼 수 있다.

쉽지 않은가??


위의 경우는 Consumer에서 보낸 SOAP Header를 얻어내는 방법이고, 반대로 Provider에서 SOAP Header를 넣는 방법을 알아보자. 다들 알다시피 AXIS2를 이용해서 WebService를 개발하면 직접적으로 SOAP Message를 만들거나 하지 않는다. Engine 단에서 처리를 해 주기 때문이다. Consumer처럼 ServiceClient와 같은 Helper 클래스를 사용하면 또 모르겠으나, Provider에는 그러한 것이 없다.


이런 문제로 인하여 Provider 클래스에서는 SOAP Header를 넣을 수 없다.

그럼 어떻게 해야 하는가? AXIS2에는 module을 작성해서 사용할 수 있도록 제공된다. 이 모듈을 작성하여, 웹서비스의 INFLOW, OUTFLOW, INFAULTFLOW, OUTFAULTFLOW 흐름에 Injunction을 시킴으로써 해결 가능하다.

AXIS2에서 SOAP Header 다루기 Part 3(AXIS2 Module).

다음에 쓰려고 했다가 그냥 오늘 쓰기로 마음을 바꿔 먹었다.

자, 이전 Part 2에서 말했듯이 WS Provider에서 SOAP Header를 넣은 방법을 알아보자. Module을 생성해야 한다.
Axis2에서의 module은 modules 디렉터리에 deploy 된다. 웹서비스 파일이 axis2/WEB-INF/services 밑에 aar 파일로 존재하듯이 모듈 파일은 axis2/WEB-INF/modules 밑에 mar 파일로 존재한다.
mar 파일의 구조는 aar 파일의 구조와 동일하다. 단, META-INF 밑에 services.xml 대신에 module.xml이 존재한다는 차이가 있을 뿐이다.

이제 Provider에서 SOAP Header를 변경하는 MySoapHeader라는 module을 작성하도록 해 보자.

모듈을 개발하기 위해서는 최소한 2개의 클래스와 1개의 xxx-module.xml파일이 필요하다.
먼저 모듈 클래스를 생성한다. 클래스명은 어떤 것을 사용하더라도 무방하나 가급적이면 역할을 표현할 수 있도록 하기 위하여 Module이라는 이름을 넣은 MySoapHeaderModule.java로 만들겠다. MySoapHeaderModule 클래스는 Module 인터페이스를 구현해야 한다.

package com.egloos.hops;

import org.apache.axis2.modules.Module;

public class MySoapHeaderModule implements Module {

Module 인터페이스를 구현하면 4개의 추상 메서드가 있다. 이들을 구현하면 되는데, 실질적으로 Module의 구현 메서드는 별달리 코드를 넣지 않아도 된다.

public void applyPolicy(Policy policy, AxisDescription axisdescription) throws AxisFault {
// Nothing to do
}


public boolean canSupportAssertion(Assertion assertion) {
// Nothing to do
return true;
}


public void engageNotify(AxisDescription axisdescription) throws AxisFault {
// Nothing to do
}


public void init(ConfigurationContext configurationcontext, AxisModule axismodule)throws AxisFault {
// Nothing to do
}


public void shutdown(ConfigurationContext configurationcontext) throws AxisFault {
// Nothing to do
}
}

첫번째 Java 파일은 이것으로 끝이다. 실질적인 로직은 모두 Handler에 들어가게 된다. 이제 Handler 클래스를 만들어보자. Handler 클래스는 AbstractHandler를 상속받아야 한다. 여기서 클래스명은 MySoapHeaderHandler로 하겠다.

package com.egloos.hops;

import org.apache.axis2.handlers.AbstractHandler;

public class MySoapHeaderHandler extends AbstractHandler {

AbstractHandler를 상속받게 되면 추상메서드로 invoke 메서드가 존재한다. 이를 구현해 주면 된다.

public InvocationResponse invoke(MessageContext ctx) throws AxisFault {
return InvocationResponse.CONTINUE;
}
}

이 Handler의 invoke 메서드는 axis2.xml에 기술하기에 따라 다르지만, WS 메시지가 들어왔을 때, 나갈 때, 그리고 SOAP Fault 메시지가 들어오고 나갈 때마다 호출(Callback)되게 된다. 이 메시지 흐름을 구분할 수 있도록 MessageContext에서 getFlow()를 제공하고 있다. 자세하게 invoke 메서드를 살펴보자.

public InvocationResponse invoke(MessageContext ctx) throws AxisFault {
switch (ctx.getFLOW()) {
case MessageContext.IN_FAULT_FLOW:
// SOAP Fault Message를수신한 경우
break;
case MessageContext.IN_FLOW:
// SOAP 메시지를 수신한 경우
break;
case MessageContext.OUT_FAULT_FLOW:
// SOAP Fault 메시지를 송신한 경우
break;
case MessageContext.OUT_FLOW:
// SOAP 메시지를 송신한 경우
break;
return InvocationResponse.CONTINUE;

}

위 코드와 같이 각 메시지 흐름에 맞는 로직을 넣어주면 된다. 리턴은 이 코드가 실패하면 어떻게 할 것인가를 지정해 주게 된다. 샘플코드는 처리만 하고 계속 다음 지정된 모듈로 제어를 넘기게 한다. 기본적으로 AXIS2에서 제공하고 있는 모듈은 WS-Addressing, SOAP Monitor 등이 있다.

IN/OUT 메시지에서 SOAP 메시지를 뽑아내는 방법은 이전 연재에서 이미 보였듯이 MessageContext에서 getEnvelope()를 하면 된다. 즉, 위 샘플코드를 이용하자면 다음과 같이 된다.
SOAPHeader header = ctx.getEnvelope().getHeader();
이런 후에 Header를 변경하면 된다.

Java Coding은 여기까지가 전부이다. 다음은 XML파일이다. 파일명은 mysoapheader-module.xml로 하겠다. Bold로 된 부분만 수정하면 된다.

<!--msgHeaderChanger는 모듈의 이름이 된다. class에는 방금 만든Module의 구현 클래스를 준다.-->
<module name="msgHeaderChanger" class="com.egloos.hops.MySoapHeaderModule">

<!-- InFlow, OutFlow, OutFaultFlow, InFaultFlow로 구분하여 Handler를 지정할 수 있다. -->
<InFlow>
<!--name에는 Handler명을 주고, class에는 Handler의 구현 클래스를 준다 -->
<handler name="InFlowHeaderHandler" class="com.egloos.hops.MySoapHeaderHandler">
<!-- 이 핸들러가 동작할 Phase명을 준다. 임의적으로 주는 것이나 조금 후에 axis2.xml에서 다시 사용하게 된다 -->
<order phase="headerPhase" />
</handler>
</InFlow>

<OutFlow>
<handler name="OutFlowHeaderHandler" class="com.egloos.hops.MySoapHeaderHandler">
<order phase="headerPhase"/>
</handler>
</OutFlow>

<OutFaultFlow>
<handler name="FaultOutFlowHeaderHandler" class="com.egloos.hops.MySoapHeaderHandler">
<order phase="headerPhase"/>
</handler>
</OutFaultFlow>

<InFaultFlow>
<handler name="FaultInFlowHeaderHandler" class="com.egloos.hops.MySoapHeaderHandler">
<order phase="headerPhase"/>
</handler>
</InFaultFlow>
</module>

위에서 밝혔듯이 이 xml파일은 META-INF에 두고 jar.exe를 이용하여 mar파일을 생성한다. 그리고 axis2/WEB-INF/modules에 둔다. 그리고 axis2/WEB-INF/conf에 있는 axis2.xml을 수정한다.

먼저 작성한 module을 등록한다. services.xml에서 각 service마다 사용할 module을 등록할 수도 있으나 여기에서는 Global Module로 등록하도록 하겠다. axis2.xml에서 Global Modules라고 되어 있는 부분에 다음을 추가한다.

<!-- ================================================= -->
<!-- Global Modules -->
<!-- ================================================= -->
<!-- Comment this to disable Addressing -->
<module ref="addressing"/>
<module ref="msgHeaderChanger"/>

최초 AXIS2를 설치하면 addressing 모듈만 추가되어 있을 것이다. 다음 라인에 Bold 부분을 추가한다. 여기에서 msgHeaderChanger는 module.xml에 있는 Module의 name이 된다.

밑으로 더 내려가 보면 Phases라는 부분이 나타난다. Phases 부분을 살펴보면 InFlow, OutFlow, InFaultFlow, OutFaultFlow로 나누어져 있다. InFlow와 InFaultFlow는 기술된 역순대로 메시지가 들어오면서 처리되게 된다. 반대로 OutFlow와 OutFaultFlow는 기술된 순서대로 메시지가 나가면서 처리된다.
우리가 원하는 것은 AXIS2의 기능은 그대로 수행되면서 Header 부분만 변경하는 것이므로 InFlow의 경우에는 다 처리하고 나가기 바로 전에 Header를 수정하면 되므로 <phaseOrder type="InFlow">의 제일 하단에 <phase name="headerChagePhase"/>를 추가해 준다.
<phaseOrder type="InFlow">
... 중략...
<phase name="headerChangePhase"/>
</phaseOrder>
여기에서 사용된 haederChangePhase는 module.xml의 InFlow에 등록된 Handler의 이름을 주면 된다.
OutFlow의 경우는 반대로 기술한다.
<phaseOrder type="OutFlow">
<phase name="headerChangePhase"/>
... 하략 ...
</phaseOrder>

저장하고 AXIS2를 Redeploy 시킨 후에 SOAP Monitor와 같은 것으로 확인하면 동작하는 것을 살펴볼 수 있다.

'웹서비스' 카테고리의 다른 글

AXIS2에는 내장된 SOAPMonitor  (0) 2010.07.15
AXIS2 WSDL의 WSDL Port Address 자동 변경  (0) 2010.07.15
Apache AXIS를 이용한 웹서비스 강좌 - 예제포함  (0) 2010.07.13
Web Service 링크  (0) 2010.07.13
SOAP 서비스 개발  (0) 2010.07.12