2.17 SOAPエージェントメッセージ・ハンドラー
SOAPエージェントメッセージ・ハンドラー・フレームワークはAxisメッセージ・ハンドラー・フレームワークの制限をなくすために開発されたもので、要求ハンドラーや応答ハンドラーを追加する場合にお勧めの方法です。
Apache Axisメッセージ・ハンドラー・フレームワーク用に開発されたメッセージ・ハンドラーは、SOAPエージェントメッセージ・ハンドラー・フレームワークで使用できます。
特定のSOAPエージェントサービスにメッセージ・ハンドラーを追加するには、SOAPAgentService.propertiesファイルに'service.handlers.サービス名' エントリーを追加します。
SOAPエージェントコマンドOPEN SERVICE (サービス名)が実行されると、実行するプログラムにサービス・クラスとメッセージ・ハンドラー・ファイルが割り当てられます。
service.test=com.acme.service.soap.TestService
service.handlers.test=handlers/soapagent-handlers.xml
複数のエージェント・サービス構成を1つのファイルに含めることができます。
要求ハンドラーや応答ハンドラーの追加はオプションです。
複数のハンドラー要素を含めることで簡単なメッセージ・ハンドラー・チェーンを作成できます。
要求メッセージ・ハンドラーと応答メッセージ・ハンドラーは、すべてのサービス操作または1つの特定の操作に割り当てることができます。
各ハンドラー要素はゼロ個以上のパラメータ要素で構成できます。
これらのパラメータ要素がインスタンス化され、インスタンス化されたハンドラー・クラスに渡されます。
パラメータ値の属性に中括弧で囲まれた値がある場合、その値はLANSAフィールド名と仮定され、LANSAフィールドの値がハンドラーに渡されます。LANSAフィールドをハンドラー・クラスで使用できるようにするには、CALLコマンドでSERVICE_EXCHANGE(*FIELD)キーワードを使用します。
メッセージ・ハンドラー構成
<?xml version="1.0" encoding="utf-8"?>
<services>
<!-- Testサービスのすべての操作にSOAPHeaderHandlerを割り当てる-->
<service name="test">
<request>
<handler class="com.acme.axis.handler.SOAPHeaderHandler"/>
</request>
<response>
<handler class="com.acme.axis.handler.SOAPHeaderHandler"/>
</response>
</service>
<!-- Testサービスのログイン操作にSecurityHandlerとSOAPHeaderHandlerを割り当てる-->
<service name="test" operation="login">
<request>
<handler class="com.acme.axis.handler.SecurityHandler">
<parameter name="user" value="{USER}"/>
<parameter name="acme.keyword" value="ABC"/>
</handler>
<handler class="com.acme.axis.handler.SOAPHeaderHandler"/>
</request>
</service>
</services>
メッセージ・ハンドラー・クラスの例
package com.acme.axis.handler ;
import java.io.* ;
import java.util.Vector ;
import org.apache.axis.Message ;
import org.apache.axis.SOAPPart ;
import org.apache.axis.AxisFault ;
import org.apache.axis.MessageContext ;
import org.apache.axis.utils.XMLUtils ;
import org.apache.axis.message.SOAPBody ;
import org.apache.axis.message.SOAPHeader ;
import org.apache.axis.message.SOAPEnvelope ;
import org.apache.axis.message.SOAPBodyElement ;
import org.apache.axis.message.SOAPHeaderElement ;
import org.apache.axis.message.MessageElement ;
import org.apache.axis.message.RPCParam ;
import org.apache.axis.message.RPCElement ;
import org.apache.axis.message.PrefixedQName ;
import org.apache.axis.description.ParameterDesc ;
import org.apache.axis.encoding.SerializationContext ;
import org.w3c.dom.Node ;
import org.w3c.dom.Element ;
import org.w3c.dom.Document ;
import org.w3c.dom.NodeList ;
import org.w3c.dom.ls.LSOutput ;
import org.w3c.dom.ls.LSSerializer ;
import org.w3c.dom.ls.DOMImplementationLS ;
import org.w3c.dom.bootstrap.DOMImplementationRegistry ;
import com.lansa.jsm.JSMTrace ;
import com.lansa.jsm.JSMCommand ;
import com.lansa.jsm.JSMResource ;
import com.lansa.jsm.service.ServiceHelper ;
public class MyHandler extends org.apache.axis.handlers.BasicHandler
{
private final static String EMPTY_STRING = "" ;
private final static String ENCODING_UTF8 = "UTF-8" ;
private final static String[] FORM_NAMES = { "", "FORM_STRING", "FORM_INPUTSTREAM", "FORM_SOAPENVELOPE", "FORM_BYTES", "FORM_BODYINSTREAM", "FORM_FAULT", "FORM_OPTIMIZED" } ;
private JSMTrace m_trace = null ;
private JSMResource m_serviceResource = null ;
public void init ()
{
/*
オプション - これはBasicHandlerのinitスタブをオーバーライドする
最初に、initがすべてのハンドラーに対して呼び出される
次に、invokeがすべてのハンドラーに対して呼び出される
最後に、cleanupがすべてのハンドラーに対して呼び出される
以下を使用してハンドラー間で情報を渡すことが可能
MessageContext - setProperty ( String name, Object value )
MessageContext - Object value getProperty ( String name )
*/
}
public void invoke ( org.apache.axis.MessageContext messageContext ) throws AxisFault
{
try
{
m_trace = (JSMTrace)getOption ( "jsm.handler.property.trace" ) ;
m_serviceResource = (JSMResource)getOption ( "jsm.handler.property.resource" ) ;
traceOptions () ;
modifyMessage ( messageContext ) ;
}
catch ( Exception e )
{
throw new AxisFault ( "MyHandler: exception : " + e.toString () ) ;
}
}
public void cleanup ()
{
/*
オプション - これはBasicHandlerのcleanupスタブをオーバーライドする
*/
if ( m_trace != null )
{
m_trace.println ( "MyHandler: cleanup" ) ;
}
}
private final void traceOptions ()
{
/*
以下のプロパティはハンドラー・パラメータから生じたものである
*/
String value = (String)getOption ( "acme.keyword" ) ;
/*
以下のプロパティはJSMサービスで提供される
*/
String type = (String)getOption ( "jsm.handler.property.type" ) ;
String service = (String)getOption ( "jsm.handler.property.service" ) ;
String operation = (String)getOption ( "jsm.handler.property.operation" ) ;
/*
コマンドを呼び出す
*/
JSMCommand command = (JSMCommand)getOption ( "jsm.handler.property.command" ) ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: invoke" ) ;
m_trace.println ( "MyHandler: acme.keyword : " + value ) ;
m_trace.println ( "MyHandler: jsm.handler.property.type : " + type ) ;
m_trace.println ( "MyHandler: jsm.handler.property.service : " + service ) ;
m_trace.println ( "MyHandler: jsm.handler.property.operation : " + operation ) ;
m_trace.println ( "MyHandler: jsm.handler.property.command : " + command.toString () ) ;
}
}
private final void modifyMessage ( org.apache.axis.MessageContext messageContext ) throws Exception
{
Message message = messageContext.getCurrentMessage () ;
if ( message == null )
{
throw new IllegalArgumentException ( "no message available" ) ;
}
/*
トレース・メッセージ - 出力は内部フォームによって異なる
*/
// traceMessage ( message ) ;
/*
SOAP部分
*/
SOAPPart soapPart = (SOAPPart)message.getSOAPPart () ;
int form = soapPart.getCurrentForm () ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: current message form : ", FORM_NAMES[form] ) ;
}
/*
SOAPエンベロープ - 内部フォームがSOAPEnvelopeに変換される
*/
SOAPEnvelope envelope = soapPart.getAsSOAPEnvelope () ;
// traceEnvelope ( envelope ) ;
/*
要求または応答を処理する
*/
if ( isRequest () )
{
modifyHeader ( envelope ) ;
traceBody ( envelope ) ;
// setRequestMessage1 ( soapPart ) ;
// setRequestMessage2 ( messageContext ) ;
setRequestMessage3 ( messageContext, envelope ) ;
return ;
}
if ( isResponse () )
{
setResponseMessage1 ( messageContext ) ;
return ;
}
}
private final void modifyHeader ( SOAPEnvelope envelope ) throws Exception
{
Vector vector = envelope.getHeaders () ;
int count = vector.size () ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: header count : " + count ) ;
}
for ( int i=0; i < count; i++ )
{
SOAPHeaderElement element = (SOAPHeaderElement)vector.elementAt ( i ) ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: soap header : " + element.getElementName () ) ;
}
}
if ( m_trace != null )
{
m_trace.println ( "MyHandler: add header" ) ;
}
envelope.addHeader ( createHeader () ) ;
}
private final SOAPHeaderElement createHeader () throws Exception
{
SOAPHeaderElement elementHead = new org.apache.axis.message.SOAPHeaderElement ( "namespace", "AuthHeader" ) ;
MessageElement elementSession = (MessageElement)elementHead.addChildElement ( "SessionId" ) ;
elementSession.addTextNode ( "text" ) ;
elementHead.setActor ( null ) ;
return elementHead ;
}
private final boolean isRequest ()
{
String type = (String)getOption ( "jsm.handler.property.type" ) ;
if ( type.equals ( "request" ) )
{
return true ;
}
return false ;
}
private final boolean isResponse ()
{
String type = (String)getOption ( "jsm.handler.property.type" ) ;
if ( type.equals ( "response" ) )
{
return true ;
}
return false ;
}
private final void setRequestMessage1 ( SOAPPart soapPart ) throws Exception
{
/*
これを最後のメッセージ変更にする必要がある
Message.writeTo -> SOAPPart.writeToメソッドはバイトをそのまま送信する
この方法では、byte[]内容で行われるFORM変換のリスクがある
*/
if ( m_trace != null )
{
m_trace.println ( "Set request message 1 using byte[]" ) ;
}
byte[] message = "any content sent as bytes".getBytes ( ENCODING_UTF8 ) ;
soapPart.setCurrentMessage ( message, SOAPPart.FORM_BYTES ) ;
}
private final void setRequestMessage2 ( MessageContext messageContext ) throws Exception
{
/*
この例では、ファイルのバイト内容を使用する
ただし、ドキュメントをbyte[]メモリー内にシリアライズしている
またはSringを作成し、内容の引数として使用する
など..
*/
if ( m_trace != null )
{
m_trace.println ( "Set request message 2 using byte[] message" ) ;
}
File file = new File ( "ENVELOPE_REQUEST.XML" ) ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: set resquest message from external file : " + file.getName () ) ;
}
// String content = "<?xml ...." ;
byte[] content = readFile ( file ) ;
Message requestMessage = new Message ( content ) ;
messageContext.setRequestMessage ( requestMessage ) ;
}
private final void setRequestMessage3 ( MessageContext messageContext, SOAPEnvelope envelope ) throws Exception
{
if ( m_trace != null )
{
m_trace.println ( "Set request message 3 using document" ) ;
}
Document document = envelope.getAsDocument () ;
/*
ドキュメントを変更する
*/
byte[] content = serializeDocument ( document ) ;
Message requestMessage = new Message ( content ) ;
messageContext.setRequestMessage ( requestMessage ) ;
}
private final void setResponseMessage1 ( MessageContext messageContext ) throws Exception
{
/*
この例では、ファイルのバイト内容を使用する
ただし、ドキュメントをbyte[]メモリー内にシリアライズしている
またはSringを作成し、内容の引数として使用する
など..
*/
File file = new File ( "ENVELOPE_RESPONSE.XML" ) ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: set response message from external file : " + file.getName () ) ;
}
byte[] content = readFile ( file ) ;
Message responseMessage = new Message ( content ) ;
messageContext.setResponseMessage ( responseMessage ) ;
}
private final byte[] serializeDocument ( Document document ) throws Exception
{
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance () ;
DOMImplementationLS implementation = (DOMImplementationLS)registry.getDOMImplementation ( "LS" ) ;
LSOutput output = implementation.createLSOutput () ;
LSSerializer serializer = implementation.createLSSerializer () ;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream ( 4096 ) ;
output.setEncoding ( "utf-8" ) ;
output.setByteStream ( outputStream ) ;
serializer.setNewLine ( "\n" ) ;
serializer.write ( document, output ) ;
return outputStream.toByteArray () ;
}
private final void traceMessage ( Message message )
{
if ( m_trace == null )
{
return ;
}
try
{
String fileName = "MYHANDLER_MESSAGE" + ServiceHelper.getSequenceLabel ( m_trace ) + ".XML" ;
FileOutputStream outputStream = new FileOutputStream ( m_trace.createTraceFile ( fileName ) ) ;
message.writeTo ( outputStream ) ;
outputStream.close () ;
}
catch ( Throwable t )
{
m_trace.print ( t ) ;
}
}
private final void traceEnvelope ( SOAPEnvelope envelope )
{
if ( m_trace == null )
{
return ;
}
/*
これはMessageElement - getAsDocumentを使用する
- getAsDocument
- getAsString
要素をStringに、パーサーをDocumentに変換する
*/
try
{
Document document = envelope.getAsDocument () ;
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance () ;
DOMImplementationLS implementation = (DOMImplementationLS)registry.getDOMImplementation ( "LS" ) ;
LSOutput output = implementation.createLSOutput () ;
LSSerializer serializer = implementation.createLSSerializer () ;
String fileName = "MYHANDLER_ENVELOPE" + ServiceHelper.getSequenceLabel ( m_trace ) + ".XML" ;
FileOutputStream outputStream = new FileOutputStream ( m_trace.createTraceFile ( fileName ) ) ;
output.setEncoding ( "utf-8" ) ;
output.setByteStream ( outputStream ) ;
serializer.setNewLine ( "\n" ) ;
serializer.write ( document, output ) ;
outputStream.close () ;
}
catch ( Throwable t )
{
m_trace.print ( t ) ;
}
}
private final void traceBody ( SOAPEnvelope envelope ) throws Exception
{
if ( m_trace == null )
{
return ;
}
SOAPBody body = (SOAPBody)envelope.getBody () ;
if ( body == null )
{
throw new IllegalArgumentException ( "no body available" ) ;
}
RPCElement operation = getOperation ( body ) ;
if ( operation == null )
{
throw new IllegalArgumentException ( "no operation available" ) ;
}
m_trace.println ( "MyHandler: operation name : " + operation.getElementName () ) ;
traceParameters ( operation ) ;
}
private final void traceParameters ( RPCElement operation ) throws Exception
{
if ( m_trace == null )
{
return ;
}
Vector vector = operation.getParams () ;
int count = vector.size () ;
m_trace.println ( "MyHandler: parameter count : " + count ) ;
for ( int i=0; i < count; i++ )
{
RPCParam parameter = (RPCParam)vector.get ( i ) ;
ParameterDesc parameterDesc = parameter.getParamDesc () ;
Class klazz = parameterDesc.getJavaType () ;
m_trace.println ( "MyHandler: parameter name : " + parameter.getElementName () ) ;
if ( klazz.isArray () )
{
m_trace.println ( "MyHandler: parameter type : array of " + klazz.getComponentType().getName () ) ;
}
else
{
m_trace.println ( "MyHandler: parameter type : " + klazz.getName () ) ;
}
}
}
private final RPCElement getOperation ( SOAPBody body )
{
NodeList nodeList = body.getChildNodes () ;
if ( nodeList == null )
{
return null ;
}
int count = nodeList.getLength () ;
if ( count == 0 )
{
return null ;
}
for ( int i=0; i < count; i++ )
{
Node node = nodeList.item ( i ) ;
if ( node instanceof RPCElement )
{
return(RPCElement)node ;
}
}
return null ;
}
private final MessageElement getChildMessageElement ( MessageElement element )
{
NodeList nodeList = element.getChildNodes () ;
if ( nodeList == null )
{
return null ;
}
int count = nodeList.getLength () ;
if ( count == 0 )
{
return null ;
}
for ( int i=0; i < count; i++ )
{
Node node = nodeList.item ( i ) ;
if ( node instanceof RPCElement )
{
return(MessageElement)node ;
}
if ( node instanceof SOAPBodyElement )
{
return(MessageElement)node ;
}
if ( node instanceof RPCParam )
{
return(MessageElement)node ;
}
if ( node instanceof MessageElement )
{
return(MessageElement)node ;
}
if ( node instanceof javax.xml.soap.SOAPElement )
{
/*
インターフェース
*/
}
}
return null ;
}
public final static byte[] readFile ( File file ) throws IOException
{
int length = (int)file.length () ;
byte[] content = new byte[length] ;
FileInputStream inputStream = new FileInputStream ( file ) ;
inputStream.read ( content ) ;
inputStream.close () ;
return content ;
}
}