The handler framework allows interception of a message at various points in its transmission. Handlers are simple Java bean classes that implement a handler contract and can be associated with web service endpoints and web service clients. With outgoing messages, handlers are invoked before a message is sent to the wire. With incoming messages, handlers are invoked before the receiving application receives the message. The same handler implementation is used for both incoming and outgoing messages.
JAX-WS provides two levels of handlers:
Logical handlers deal with the payload level of the message. Logical handlers can be used for building non-functional behavior, such as logging and caching, that is common across protocols.
Protocol handlers deal with protocol information, such as SOAP headers.
Logical handlers
Example below shows a logical handler skeleton. The main method is the handleMessage
method. The close
method is to clean up any resources that handler invocation might have consumed. The handleFault
method is invoked if
an error condition occurs, for example, if a response message contains a fault.
import javax.xml.ws.handler.LogicalHandler; import javax.xml.ws.handler.LogicalMessageContext; import javax.xml.ws.handler.MessageContext; public class HelloMessengerLogicalHandler implements LogicalHandler<LogicalMessageContext> { public void close(MessageContext ctx) { } public boolean handleFault(LogicalMessageContext ctx) { return false; } public boolean handleMessage(LogicalMessageContext ctx) { return false; } }
The handleMessage
method (and handleFault
) return a boolean
. Returning true
from the handleMessage
method tells the JAX-WS run time that processing should move to the next handler in the
chain. Returning false
tells the JAX-WS run time that processing of the handler chain should end.
The parameter to handleMessage
is a LogicalMessageContext
. It is an extension of
java.util.Map
and contains <key, value>
pairs of context properties. There are
properties for items such as WSDL element names and attachment information (if any). Since handlers are invoked for
both incoming and outgoing messages, a useful property is the MESSAGE_OUTBOUND_PROPERTY
defined on the
MessageContext
interface, which gives you the direction of the message:
Boolean outbound = ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
Another useful property is the message itself:
LogicalMessage message = ctx.getMessage();
You can get the payload as XML data by using the javax.xml.transform.Source
:
Source payload = message.getPayload();
Alternatively, you can get the payload as JAXB objects:
Object jaxbPayload = message.getPayload(jaxbContext);
In either case, you get the payload. In the case of SOAP, the payload is the contents of the SOAP:Body
, either in
XML form (javax.xml.transform.Source
) or in JAXB form (java.lang.Object
).
Protocol handlers
The primary reason for writing a SOAP handler is to manipulate SOAP headers. Example below shows an example of a SOAP handler skeleton:
import java.util.Set; import javax.xml.namespace.QName; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class HelloMessengerProtocolHandler implements SOAPHandler<SOAPMessageContext> { public Set<QName> getHeaders() { return null; } public void close(MessageContext ctx) { } public boolean handleFault(SOAPMessageContext ctx) { return false; } public boolean handleMessage(SOAPMessageContext ctx) { return false; } }
The SOAP handler skeleton has the familiar methods of close
, handleFault
, and handleMessage
.
The parameter to handleFault
and handleMessage
, however, is now SOAPMessageContext
instead
of LogicalMessageContext
. In addition, the getHeaders
method is a new method to implement.
The getHeaders
method returns the set of the header names that the handler understands. The JAX-WS run time
calls this method to determine whether the handler can process SOAP headers that must be understood (as indicated by the
SOAP mustUnderstand
attribute). It does not call this method to filter handler invocation. All handlers in a
chain are called for all messages.
The SOAPMessageContext
class adds a few properties to the context map that are SOAP-specific, such as roles.
The getMessage
method returns a SOAPMessage
, which is an SAAJ class. By using the
SOAPMessage
, you can programmatically examine or modify SOAP message headers.
With JAX-WS, you can declaratively specify a web service handler chain by using the
@javax.jws.HandlerChain
annotation. Example below shows how to apply a handler chain to the
HelloMessenger
web service:
import javax.jws.HandlerChain; import javax.jws.WebService; @WebService @HandlerChain(file = "handler-chain.xml") public class HelloMessenger { public String sayHello(String name) { return String.format("Hello %s", name); } }
The HelloMessenger
web service contains a class-level @HandlerChain
annotation, which
specifies that the handler configuration should be loaded from the handler-chain.xml
file that is
available in the class path. Example below shows the handler-chain.xml
file in its entirety:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <javaee:handler-chain> <javaee:handler> <javaee:handler-class>HelloMessengerProtocolHandler</javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>
The XML file tells the JAX-WS run time to use the HelloMessengerProtocolHandler
to handle incoming
and outgoing messages.
The webservices.xml
deployment descriptor file was introduced by the first version of [JSR 109] to define
the set of web services that are to be deployed in a container. However, with JAX-WS, the use of
webservices.xml
is optional since the annotations can be used to specify most of the information specified
in this deployment descriptor. When you are deploying JAX-WS web services, the only reason you should use
webservices.xml
is to override or augment the annotation member attributes — or when you do not want
to use annotations because you don't want to modify the Java source code.
One situation, where you might want to override or augment annotations, occurs when you want
to deploy a handler with a web service endpoint that has not been annotated for a handler. Alternatively, the
endpoint may have been annotated for a handler, but you wish to use a different handler. One way to deal with this
is to edit the source code to update or add the @HandlerChain
annotation. But perhaps you do not have
access or authority to modify the source code. Or perhaps you think it is a bad idea to have multiple versions of
the same source code just so you can support using the endpoint with different handlers. In such a situation, you can
deploy the endpoint with a custom webservices.xml
to specify the handler chain.
Example below shows the Hello
web service endpoint with an @HandlerChain
annotation that
specifies the myhandler.xml
handler configuration file:
@HandlerChain(file="myhandler.xml") @WebService public class Hello { @Resource WebServiceContext context; public String sayHello(String s) { String appendString = (String) context.getMessageContext().get(HelloHandler.APPEND_STRING); return "Hello: " + s + "[appended by handler: " + appendString + "]"; } }
The myhandler.xml
file is shown in below. Notice that it specifies the handler class
HelloHandler
.
<handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-class>HelloHandler</handler-class> </handler> </handler-chain> </handler-chains>
Now, suppose you would prefer to deploy this endpoint with the handler class ImprovedHelloHandler
. You
could do that by bundling the webservices.xml
file shown below in the WEB-INF
directory of
the WAR module (or, if this were an EJB endpoint, in the META-INF
directory).
The webservices.xml
overrides the @HandlerChain
annotation:
<webservices xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://www.ibm.com/webservices/xsd/javaee_web_services_1_2.xsd"> <webservice-description> <webservice-description-name>HelloService</webservice-description-name> <port-component> <port-component-name>Hello</port-component-name> <wsdl-service xmlns:ns1="http://samples/">ns1:HelloService</wsdl-service> <wsdl-port xmlns:ns1="http://samples/">ns1:HelloPort</wsdl-port> <service-impl-bean> <servlet-link>Hello</servlet-link> </service-impl-bean> <handler-chains> <handler-chain> <handler> <handler-name>myhandler</handler-name> <handler-class>ImprovedHelloHandler</handler-class> </handler> </handler-chain> </handler-chains> </port-component> </webservice-description> </webservices>
In this webservices.xml
deployment descriptor, notice the handler-chains
element in the
bottom half of the listing. Here, the handler-class
element specifies ImprovedHelloHandler
.
When using the webservice.xml
, it is important to understand how the port-component
names
match up with the annotations. In other words, port-component-name
relates to @WebService.name
;
wsdl-service
relates to @WebService.serviceName
; wsdl-port
relates to
@WebService.portName
; and service-endpoint-interface
relates to
@WebService.endpointInterface
.
![]() |
![]() ![]() |