JAX-RPC handlers allow you to intercept a SOAP message at various times during a service invocation. Handlers can exist on both the client and the server side. If you use JAX-RPC on the client side, you can have a handler process a SOAP request message right before it goes on the network, and you can process the response message before it is returned to the client. Similarly, you can intercept an incoming SOAP request message on the server before invoking the service implementation, as well as the outgoing response.
Several handlers can be combined into what is called a "handler chain". Each handler processes the SOAP message, which is then passed on to the next handler in the chain. The exact sequence in which this happens is configurable. We'll get back to this later.
To develop a JAX-RPC handler, you simply create a class that implements the javax.xml.rpc.handler.Handler interface. It has three methods to handle SOAP requests, responses and faults, respectively.
Handlers are defined in the JAX-RPC specification. However, the "Enterprise Web Services" (JSR109) specification describes how they are used in a J2EE environment and adds some clarification to the way handlers are managed by the application server (see Resources for more information on this specification). In this article, we will assume that your Web service runs on a J2EE application server and hence we will follow the definitions of JSR109 as well as JAX-RPC.
Handlers are shared across multiple service invocations. In other words, they can store information that is only valid for a particular client or server instance. You can compare this to the way servlets are handled. When a new instance of a handler is created, its init() method is called. That allows you to set up things that you can use for multiple invocations. Before the handler is removed, the destroy() method is called, so that you can do cleanup in there. As a rule of thumb, however, you should avoid storing any state in a handler altogether.
Handlers can be configured either programmatically or, in case you are running a J2EE application server, they are configured in the Web service deployment descriptor. Handlers and handler chains are defined on a per service basis. They can be defined in both the server and client side deployment descriptors. Listing 1 shows the deployment descriptor for our sample service, showing how a handler class called handler. PerformanceHandler is registered for the HelloWorld service:
Listing 1. Web service deployment descriptor with handler
<webservices id="WebServices_1066491732483">
<webservice-description id="WebServiceDescription_1066491732483">
<webservice-description-name>HelloWorldService</webservice-description-name>
<wsdl-file>WEB-INF/wsdl/HelloWorld.wsdl</wsdl-file>
<jaxrpc-mapping-file>WEB-INF/HelloWorld_mapping.xml</jaxrpc-mapping-file>
<port-component id="PortComponent_1066491732483">
<port-component-name>HelloWorld</port-component-name>
<wsdl-port id="WSDLPort_1066491732483">
<namespaceURI>http://pack</namespaceURI>
<localpart>HelloWorld</localpart>
</wsdl-port>
<service-endpoint-interface>pack.HelloWorld</service-endpoint-interface>
<service-impl-bean id="ServiceImplBean_1066491732483">
<servlet-link>pack_HelloWorld</servlet-link>
</service-impl-bean>
<handler id="Handler_1066493401322">
<handler-name>handler.PerformanceHandler</handler-name>
<handler-class>handler.PerformanceHandler</handler-class>
</handler>
</port-component>
</webservice-description>
</webservices>
|
Multiple handlers would be defined here to form a chain as mentioned above.
If multiple handlers that are involved in one service invocation need to share information, they can do so by adding properties to the message context as it is passed from handler to handler. This message context will be available from the request to the response. In other words, we can use it to store information on an incoming request that we can reuse when the response comes back. We will get to this in our example later.
Example: A service performance handler
Now let's look at how you can create a handler that measures the response time of your service implementation. We will assume that you have created a HelloWorld web service, which simply returns a String message. Listing 2 shows the code for the service implementation bean (you can find an EAR file with all the sources, including a test client in the Resources section):
Listing 2. Web service implementation class
public class HelloWorld {
public String helloWorld(String message) {
return "Hello "+message;
}
}
|
The handler will be configured for the server that hosts the Web service. It will be invoked on both the request and the response message, so that we can measure the elapsed time.
As mentioned earlier, each handler must implement the javax.xml.rpc.handler.Handler interface. Or, you can make your life a bit easier by simply inheriting the javac.xml.rpc.handler.GenericHandler class, which provides default implementations for all the methods. For storing performance results, we use a class called Logger, which we set up in the init() method. You can find the source for the Logger class in the Resources section. Moreover, the application server passes a javax.xml.rpc.handler.HandlerInfo object into this method, which we need to cache as well (see Listing 3):
Listing 3. Handler implementation -- init and destroy
public class PerformanceHandler extends GenericHandler {
protected HandlerInfo info = null;
protected Logger logger = null;
public void init(HandlerInfo arg) {
info = arg;
logger = Logger.getLogger("c://temp//HelloWorldServiceLog");
}
public void destroy() {
try {
logger.close();
} catch (Exception x) {}
}
|
Note that we close the Logger object when the handler instance is destroyed.
Handling requests and responses
Each handler implements the handleRequest method, which is invoked when a request message arrives, as shown in Listing 4.
Listing 4. Handler implementation -- the handleRequest method
public boolean handleRequest(MessageContext context) {
try {
Date startTime = new Date();
context.setProperty("startTime", startTime);
} catch (Exception x) {
// insert error handling here
x.printStackTrace();
}
return true;
}
|
Here you can see that we store the current time in the message context as a property called "startTime". The application server will guarantee that the same message context object is passed into the handleResponse method, so that we can measure the elapsed time there, as shown in Listing 5.
Listing 5. Handler implementation -- the handleResponse method
public boolean handleResponse(MessageContext context) {
try {
Date startTime = (Date)context.getProperty("startTime");
Date endTime = new Date();
long elapsedTime = endTime.getTime()-startTime.getTime();
logger.write("Elapsed time is "+elapsedTime+"\n");
} catch (Exception x) {
// insert error handling here
x.printStackTrace();
}
return true;
}
|
Now you can deploy your service. Make sure you have configured the handler as shown in the deployment descriptor above, and you can measure how long it takes to execute a service request.
JAX-RPC defines a mechanism with which you can manage service invocations by intercepting request and response messages without having to change the actual service consumer or provider. In J2EE, you can configure handlers in a deployment descriptor, without writing any code, providing you with a powerful way of controlling SOAP messages as they pass through your system.
| Name | Size | Download method |
|---|---|---|
| ws-tipjax2SOAPHandler.ear | HTTP |
Information about download methods
- Read the first part of this series of tips, Using SOAP headers with JAX-RPC. (developerWorks, October 2003)
- Download the SOAPHandler.ear file used in this tip.
- Find the SOAP specification describing how SOAP headers are represented at the W3C SOAP 1.1 Web site.
- The W3C WSDL 1.1 Web site contains the WSDL specification with a description of how to add headers to the SOAP binding.
- "Developer's Introduction to JAX-RPC, Part 1" and "Developer's Introduction to JAX-RPC, Part 2" (developerWorks, January 2003) offers a great introduction into the JAX-RPC standard.
- The WebSphere SDK for Web Services (WSDK) provides you with an easy entry into Web services programming.
- Check out the JSR109 specification (PDF).
Andre Tost works as a Solution Architect in the WebSphere Business Development group, where he helps IBM's Strategic Alliance partners integrate their applications with WebSphere. His special focus is on Web services technology throughout the WebSphere product family. Before his current assignment, he spent ten years in various development and architecture roles in IBM software development, most recently for the WebSphere Business Components product. Originally from Germany, he now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible.
Russell Butek is one of the developers of IBM's WebSphere Web services engine. He is also IBM's representative on the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of IBM's CORBA ORB and an IBM representative on a number of OMG task forces: the portable interceptor task force (of which he was chair), the core task force, and the interoperability task force. You can contact Russell at butek at us.ibm.com.
Comments (Undergoing maintenance)





