![]() |
![]() |
e-docs > WebLogic Server > Programming WebLogic Web Services > Creating SOAP Message Handlers to Intercept the SOAP Message |
Programming WebLogic Web Services
|
Creating SOAP Message Handlers to Intercept the SOAP Message
The following sections discuss how to use SOAP message handlers to intercept the request and response SOAP messages when developing a WebLogic Web service:
Overview of SOAP Message Handlers and Handler Chains
A SOAP message handler intercepts the SOAP message in both the request and response of the Web service. You can create handlers in both the Web service itself and the client applications that invoke the Web service. Refer to Using SOAP Message Handlers to Intercept the SOAP Message for examples of when to use handlers.
The following table describes the main classes and interfaces of the javax.xml.rpc.handler API; later sections in this chapter describe how to use them to create handlers.
Creating SOAP Message Handlers: Main Steps
To create SOAP message handlers to intercept request and response SOAP messages when developing WebLogic Web services:
WebLogic Server includes an extension to the JAX-RPC handler API which you can use to simplify the coding of your handler class: an abstract class called weblogic.webservice.GenericHandler. See Extending the GenericHandler Abstract Class.
For information about creating client-side SOAP message handlers and handler chains, see Using SOAP Message Handlers and Handler Chains in a Client Application.
Designing the SOAP Message Handlers and Handler Chains
When designing your SOAP message handlers, you must decide:
Each handler in a handler chain has one method for handling the request SOAP message and another method for handling the response SOAP message. You specify the handlers in the web-services.xml deployment descriptor file. An ordered group of handlers is referred to as a handler chain.
When invoking a Web service, WebLogic Server executes handlers as follows:
Note: This step only occurs if a backend component has actually been defined for the Web service; it is possible to develop a Web service that consists of only a handler chain.
For example, assume that you have specified a handler chain called myChain that contains three handlers in the web-services.xml deployment descriptor, as shown in the following excerpt:
<handler-chains>
<handler-chain name="myChain">
<handler class-name="myHandlers.handlerOne" />
<handler class-name="myHandlers.handlerTwo" />
<handler class-name="myHandlers.handlerThree" />
</handler-chain>
</handler-chains>
The following graphic shows the order in which WebLogic Server executes the handleRequest() and handleResponse() methods of each handler:
Each SOAP message handler has a separate method to process the request and response SOAP message because the same type of processing typically must happen in both places. For example, you might design an Encryption handler whose handleRequest() method decrypts secure data in the SOAP request and handleResponse() method encrypts the SOAP response.
You can, however, design a handler that process only the SOAP request and does no equivalent processing of the response.
You can also choose not to invoke the next handler in the handler chain and send an immediate response to the client application at any point. The way to do this is discussed in later sections.
Finally, you can design a Web service that contains only handlers in a handler chain, and no backend component at all. In this case, when the handleRequest() method in the last handler has executed, the chain of handleResponse() methods is automatically invoked. See Updating the web-services.xml File with SOAP Message Handler Information for an example of using the web-services.xml file to specify that only a handler chain, and no backend component, implements a Web service.
Implementing the Handler Interface
Your SOAP message handler class must implement the javax.rpc.xml.handler.Handler interface, as shown in the following example. The example demonstrates a simple way to print out the SOAP request and response messages:
package examples.webservices.handler.log;
import java.util.Map;
import javax.xml.rpc.handler.Handler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import weblogic.logging.NonCatalogLogger;
/**
* @author Copyright (c) 2002 by BEA Systems. All Rights Reserved.
*/
public final class LogHandler
implements Handler
{
private NonCatalogLogger log;
private HandlerInfo handlerInfo;
public void init(HandlerInfo hi) {
log = new NonCatalogLogger("WebService-LogHandler");
handlerInfo = hi;
}
public void destroy() {}
public QName[] getHeaders() { return handlerInfo.getHeaders(); }
public boolean handleRequest(MessageContext mc) {
SOAPMessageContext messageContext = (SOAPMessageContext) mc;
System.out.println("** Request: "+messageContext.getMessage().toString());
log.info(messageContext.getMessage().toString());
return true;
}
public boolean handleResponse(MessageContext mc) {
SOAPMessageContext messageContext = (SOAPMessageContext) mc;
System.out.println("** Response: "+messageContext.getMessage().toString());
log.info(messageContext.getMessage().toString());
return true;
}
public boolean handleFault(MessageContext mc) {
SOAPMessageContext messageContext = (SOAPMessageContext) mc;
System.out.println("** Fault: "+messageContext.getMessage().toString());
log.info(messageContext.getMessage().toString());
}
}
The javax.xml.rpc.handler.Handler interface contains the following methods that you must implement:
The following sections describe how to use each method to code your implementation.
Implementing the Handler.init() Method
The Handler.init() method is called to create an instance of a Handler object and to enable the instance to initialize itself. Its signature is:
public void init(HandlerInfo config) throws JAXRPCException {}
The HandlerInfo object contains information about the SOAP message handler, in particular the initialization parameters, specified in the web-services.xml file. Use the HandlerInfo.getHandlerConfig() method to get the parameters; the method returns a Map object that contains name-value pairs.
Implement the init() method if you need to process the initialization parameters or if you have other initialization tasks to perform.
Sample uses of initialization parameters are to turn debugging on or off, specify the name of a log file to which to write messages or errors, and so on.
Implementing the Handler.destroy() Method
The Handler.destroy() method is called to destroy an instance of a Handler object. Its signature is:
public void destroy() throws JAXRPCException {}
Implement the destroy() method to release any resources acquired throughout the handler's lifecycle.
Implementing the Handler.getHeaders() Method
The Handler.getHeaders() method gets the header blocks processed by this Handler instance. Its signature is:
public QName[] getHeaders() {}
Implementing the Handler.handleRequest() Method
The Handler.handleRequest() method is called to intercept a SOAP message request before it is processed by the back-end component. Its signature is:
public boolean handleRequest(MessageContext mc) throws JAXRPCException {}
Implement this method to decrypt data in the SOAP message before it is processed by the back-end component, to make sure that the request contains the correct number of parameters, and so on.
The MessageContext object abstracts the message context processed by the SOAP message handler. The MessageContext properties allow the handlers in a handler chain to share processing state.
Use the SOAPMessageContext sub-interface of MessageContext to get at or update the contents of the SOAP message request. The SOAP message request itself is stored in a javax.xml.soap.SOAPMessage object. For detailed information on this object, see The javax.xml.soap.SOAPMessage Object.
The SOAPMessageContext class defines two methods for processing the SOAP request:
After you code all the processing of the SOAP request, do one of the following:
The next handler on the request chain is specified as the next <handler> subelement of the <handler-chain> element in the web-services.xml deployment descriptor. If there are no more handlers in the chain, the method either invokes the backend-end component, passing it the final SOAP message request, or invokes the handleResponse() method of the last handler, depending on how you have configured your Web service.
Blocking the handler request chain processing implies that the backend component does not get executed for this invoke of the Web service. You might want to do this if you have cached the results of certain invokes of the Web service, and the current invoke is on the list.
Although the handler request chain does not continue processing, WebLogic Server does invoke the handler response chain, starting at the current handler. For example, assume that a handler chain consists of two handlers: handlerA and handlerB, where the handleRequest() method of handlerA is invoked before that of handlerB. If processing is blocked in handlerA (and thus the handleRequest() method of handlerB is not invoked), the handler response chain starts at handlerA and the handleRequest() method of handlerB is not invoked either.
Implementing the Handler.handleResponse() Method
The Handler.handleResponse() method is called to intercept a SOAP message response after it has been processed by the backend component, but before it is sent back to the client application that invoked the Web service. Its signature is:
public boolean handleResponse(MessageContext mc) throws JAXRPCException {}
Implement this method to encrypt data in the SOAP message before it is sent back to the client application, to further process returned values, and so on.
The MessageContext object abstracts the message context processed by the SOAP message handler. The MessageContext properties allow the handlers in a handler chain to share processing state.
Use the SOAPMessageContext sub-interface of MessageContext to get at or update the contents of the SOAP message response. The SOAP message response itself is stored in a javax.xml.soap.SOAPMessage object. See The javax.xml.soap.SOAPMessage Object.
The SOAPMessageContext class defines two methods for processing the SOAP response:
After you code all the processing of the SOAP response, do one of the following:
The next response on the handler chain is specified as the preceding <handler> subelement of the <handler-chain> element in the web-services.xml deployment descriptor. (Remember that responses on the handler chain execute in the reverse order that they are specified in the web-services.xml file. See Designing the SOAP Message Handlers and Handler Chains for more information.)
If there are no more handlers in the chain, the method sends the final SOAP message response to the client application that invoked the Web service.
Implementing the Handler.handleFault() Method
The Handler.handleFault() method processes the SOAP faults based on the SOAP message processing model. Its signature is:
public boolean handleFault(MessageContext mc) throws JAXRPCException {}
Implement this method to handle processing of any SOAP faults generated by the handleResponse() and handleRequest() methods, as well as faults generated by the backend component.
The MessageContext object abstracts the message context processed by the SOAP message handler. The MessageContext properties allow the handlers in a handler chain to share processing state.
Use the SOAPMessageContext sub-interface of MessageContext to get at or update the contents of the SOAP message. The SOAP message itself is stored in a javax.xml.soap.SOAPMessage object. See The javax.xml.soap.SOAPMessage Object.
The SOAPMessageContext class defines the following two methods for processing the SOAP message:
After you code all the processing of the SOAP fault, do one of the following:
The javax.xml.soap.SOAPMessage Object
The javax.xml.soap.SOAPMessage abstract class is part of the Java API for XML Messaging (JAXM) specification. You use the class to manipulate request and response SOAP messages when creating SOAP message handlers. This section describes the basic structure of a SOAPMessage object and some of the methods you can use to view and update a SOAP message.
A SOAPMessage object consists of a SOAPPart object (which contains the actual SOAP XML document) and zero or more attachments.
Refer to the JAXM API Javadocs for the full description of the SOAPMessage class. For more information on JAXM, go to http://java.sun.com/xml/jaxm/index.html.
The SOAPPart object contains the XML SOAP document inside of a SOAPEnvelope object. You use this object to get the actual SOAP headers and body.
The following sample Java code shows how to retrieve the SOAP message from a MessageContext object, provided by the Handler class, and get at its parts:
SOAPMessage soapMessage = messageContext.getRequest();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPBody soapBody = soapEnvelope.getBody();
SOAPHeader soapHeader = soapEnvelope.getHeader();
The AttachmentPart object contains the optional attachments to the SOAP message. Unlike the rest of a SOAP message, an attachment is not required to be in XML format and can therefore be anything from simple text to an image file.
Use the following methods of the SOAPMessage class to manipulate the attachments:
Extending the GenericHandler Abstract Class
WebLogic Server includes an extension to the JAX-RPC handler API that you can use to simplify the Java code of your SOAP message handler class. This extension is the abstract class weblogic.webservices.GenericHandler. It implements the JAX-RPC javax.xml.rpc.handler.Handler interface.
Note: The weblogic.webservices.GenericHandler abstract class was originally developed for WebLogic Server when the JAX-RPC specification was not yet final and did not include this functionality. However, now that JAX-RPC includes its own GenericHandler class which is almost exactly the same as the WebLogic Server class, BEA highly recommends that you use the standard JAX-RPC abstract class rather than the WebLogic-specific one. The documentation in this section is provided for compatibility reasons only.
For more information about the JAX-RPC javax.xml.rpc.handler.GenericHandler abstract class, see the JAX-RPC Javadocs.
Because GenericHandler is an abstract class, you need only implement the methods that will contain actual code, rather than having to implement every method of the Handler interface even if the method does nothing. For example, if your handler does not use initialization parameters and you do not need to allocate any additional resources, you do not need to implement the init() method.
The GenericHandler class is defined as follows:
package weblogic.webservice;
import javax.xml.rpc.handler.Handler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.namespace.QName;
/**
* @author Copyright (c) 2002 by BEA Systems. All Rights Reserved.
*/
public abstract class GenericHandler
implements Handler
{
private HandlerInfo handlerInfo;
public void init(HandlerInfo handlerInfo) {
this.handlerInfo = handlerInfo;
}
protected HandlerInfo getHandlerInfo() { return handlerInfo; }
public boolean handleRequest(MessageContext msg) {
return true;
}
public boolean handleResponse(MessageContext msg) {
return true;
}
public boolean handleFault(MessageContext msg) {}
public void destroy() {}
public QName[] getHeaders() { return handlerInfo.getHeaders(); }
}
The following sample code, taken from the examples.webservices.handler.nocomponent product example, shows how to use the GenericHandler abstract class to create your own handler. The example implements only the handleRequest() and handleResponse() methods. It does not implement (and thus does not include in the code) the init(), destroy(), getHeaders(), and handleFault() methods.
package examples.webservices.handler.nocomponent;
import java.util.Map;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.*;
import weblogic.webservice.GenericHandler;
import weblogic.utils.Debug;
/**
* @author Copyright (c) 2002 by BEA Systems. All Rights Reserved.
*/
public final class EchoStringHandler
extends GenericHandler
{
private int me = System.identityHashCode(this);
public boolean handleRequest(MessageContext messageContext) {
System.err.println("** handleRequest called in: "+me);
return true;
}
public boolean handleResponse(MessageContext messageContext) {
try {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage m = messageFactory.createMessage();
SOAPEnvelope env = m.getSOAPPart().getEnvelope();
SOAPBody body = env.getBody();
SOAPElement fResponse =
body.addBodyElement(env.createName("echoResponse"));
fResponse.addAttribute(env.createName("encodingStyle"),
"http://schemas.xmlsoap.org/soap/encoding/");
SOAPElement result =
fResponse.addChildElement(env.createName("result"));
result.addTextNode("Hello World");
((SOAPMessageContext)messageContext).setMessage(m);
return true;
} catch (SOAPException e) {
e.printStackTrace();
throw new JAXRPCException(e);
}
}
}
Updating the web-services.xml File with SOAP Message Handler Information
The web-services.xml deployment descriptor file describes the SOAP message handlers and handler chains defined for a Web service and the order in which they should be executed.
To update the web-services.xml file with handler information:
The following sample excerpt shows a handler chain called myChain that contains three handlers, the first of which has an initialization parameter:
<web-services>
<handler-chains>
<handler-chain name="myChain">
<handler class-name="myHandlers.handlerOne" >
<init-params>
<init-param name="debug" value="on" />
</init-params>
</handler>
<handler class-name="myHandlers.handlerTwo" />
<handler class-name="myHandlers.handlerThree" />
</handler-chain>
</handler-chains>
...
</web-services>
In this case use the component, method, and handler-chain attributes of the <operation> element, as shown in the following partial excerpt of a web-services.xml file:
<web-service>
<components>
<stateless-ejb name="myEJB">
...
</stateless-ejb>
</components>
<operations>
<operation name="getQuote"
method="getQuote"
component="myEJB"
handler-chain="myChain" />
</operations>
</web-service>
In the example, the request chain of the myChain handler chain executes first, then the getQuote() method of the myEJB stateless session EJB component, and finally the response chain of myChain.
In this case use only the handler-chain attribute of the <operation> element and explicitly do not specify the component or method attributes, as shown in the following excerpt:
<web-service>
<operations>
<operation name="chainService"
handler-chain="myChain" />
</operations>
</web-service>
In the example, the Web service consists solely of the myChain handler chain.
Using SOAP Message Handlers and Handler Chains in a Client Application
Most of this chapter describes how to create SOAP message handlers in a handler chain that execute as part of the Web service running on WebLogic Server. You can also create handlers that execute in a client application. In the case of a client-side handler, the handler executes twice when a client application invokes a Web service:
You create a client-side handler in the same way you create a server-side handler: write a Java class that implements the javax.rpc.xml.handler.Handler interface. In many cases you can use the exact same handler class on both the Web service running on WebLogic Server and the client applications that invoke the Web service. For example, you can write a generic logging handler class that logs all sent and received SOAP messages, both for the server and for the client. For details about writing the handler Java class, see Implementing the Handler Interface.
After you have created your client-side handler class, the process for registering the handler on the client application is different from that of the server. Because client applications do not have deployment descriptors, you must register the handler programmatically using the javax.xml.rpc.handler.HandlerInfo and javax.xml.rpc.handler.HandlerRegistry classes. The following sample client application shows how to do this, with relevant sections in bold discussed after the example:
import java.util.ArrayList;
import java.io.IOException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.HandlerRegistry;
public class Main{
public static void main( String[] args ){
if( args.length == 1 ){
new Main( args[0] );
}else{
throw new IllegalArgumentException( "URL of the service not specified" );
}
}
public Main( String wsdlUrl ){
try{
HelloWorldService service = new HelloWorldService_Impl( wsdlUrl );
HelloWorldServicePort port = service.getHelloWorldServicePort();
QName portName = new QName( "http://tutorial/sample4/",
"HelloWorldServicePort");
HandlerRegistry registry = service.getHandlerRegistry();
List handlerList = new ArrayList();
handlerList.add( new HandlerInfo( ClientHandler.class, null, null ) );
registry.setHandlerChain( portName, handlerList );
System.out.println( port.helloWorld() );
}catch( IOException e ){
System.out.println( "Failed to create web service client:" + e );
}catch( ServiceException e ){
System.out.println( "Failed to create web service client:" + e );
}
}
}
The main points to notice about the example are as follows:
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.HandlerRegistry;
QName portName = new QName( "http://tutorial/sample4/",
"HelloWorldServicePort");
HandlerRegistry registry = service.getHandlerRegistry();
List handlerList = new ArrayList();
handlerList.add( new HandlerInfo( ClientHandler.class, null, null ) );
In the example, the handler chain consists of just one handler: ClientHandler.class. You can, however, create a handler chain of as many handlers as you want.
registry.setHandlerChain( portName, handlerList );
![]() |
![]() |
![]() |
![]() |
||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |