2.17 SOAP Agent Message Handler
The SOAP Agent message handler framework was developed to over-come limitations in the Axis Message handler framework and is the preferred way to add request and response handlers.
Message handlers developed for Apache Axis Message handler framework can be used in SOAP Agent message handler framework.
To add a message handler to a particular SOAP Agent service add a 'service.handlers.servicename' entry to the SOAPAgentService.properties file.
When the SOAP Agent command OPEN SERVICE ( servicename ) is executed the service class and message handler file are assigned to the executing program.
service.test=com.acme.service.soap.TestService
service.handlers.test=handlers/soapagent-handlers.xml
More than one agent service configuration can be included in a single file.
It is optional to add a request or response handler.
A simple message handler chain can be created, by including more than one handler element.
Request and response message handlers can be assigned to all service operations or one particular operation.
Each handler element can be configured with zero or more parameter elements.
These parameter elements are instantiated and passed to the instantiated handler class.
If the parameter value attribute contains a value within open and close curly brackets, then the value is assumed to be a LANSA field name and the value of the LANSA field is passed to the handler. Use the SERVICE_EXCHANGE(*FIELD) keyword on the CALL command to make LANSA fields available to the handler class.
Message handler configuration
<?xml version="1.0" encoding="utf-8"?>
<services>
<!-- Assign SOAPHeaderHandler to all operations in the Test service -->
<service name="test">
<request>
<handler class="com.acme.axis.handler.SOAPHeaderHandler"/>
</request>
<response>
<handler class="com.acme.axis.handler.SOAPHeaderHandler"/>
</response>
</service>
<!-- Assign SecurityHandler and SOAPHeaderHandler to the Test service login operation -->
<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>
Example Message Handler Class
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 ()
{
/*
Optional - this over-rides init stub in BasicHandler
Firstly, init is called on all handlers
Secondly, invoke is called on all handlers
Finally, cleanup is called on all handlers
You could pass information between handlers by using:
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 ()
{
/*
Optional - this over-rides cleanup stub in BasicHandler
*/
if ( m_trace != null )
{
m_trace.println ( "MyHandler: cleanup" ) ;
}
}
private final void traceOptions ()
{
/*
The following properties are from the handler parameters
*/
String value = (String)getOption ( "acme.keyword" ) ;
/*
The following properties are supplied by the JSM service
*/
String type = (String)getOption ( "jsm.handler.property.type" ) ;
String service = (String)getOption ( "jsm.handler.property.service" ) ;
String operation = (String)getOption ( "jsm.handler.property.operation" ) ;
/*
CALL command
*/
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" ) ;
}
/*
Trace message - output is dependent on internal form
*/
// traceMessage ( message ) ;
/*
SOAP Part
*/
SOAPPart soapPart = (SOAPPart)message.getSOAPPart () ;
int form = soapPart.getCurrentForm () ;
if ( m_trace != null )
{
m_trace.println ( "MyHandler: current message form : ", FORM_NAMES[form] ) ;
}
/*
SOAP Envelope - the internal form is converted to SOAPEnvelope
*/
SOAPEnvelope envelope = soapPart.getAsSOAPEnvelope () ;
// traceEnvelope ( envelope ) ;
/*
Handle request or response
*/
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
{
/*
This needs to be the last message change
Message.writeTo -> SOAPPart.writeTo methods will sent bytes as is
This approach runs the risk of a FORM conversion taking place on the byte[] content
*/
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
{
/*
With this example, I am using byte content from a file
But you could have serialized a Document to a byte[] in-memory
Or created a String and used that as the content argument
etc..
*/
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 () ;
/*
Change document
*/
byte[] content = serializeDocument ( document ) ;
Message requestMessage = new Message ( content ) ;
messageContext.setRequestMessage ( requestMessage ) ;
}
private final void setResponseMessage1 ( MessageContext messageContext ) throws Exception
{
/*
With this example, I am using byte content from a file
But you could have serialized a Document to a byte[] in-memory
Or created a String and used that as the content argument
etc..
*/
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 ;
}
/*
This uses MessageElement - getAsDocument
- getAsDocument
- getAsString
Converts element to String and parser into a 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 )
{
/*
Interface
*/
}
}
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 ;
}
}