Chapter 43. Writing Handlers
Abstract
JAX-WS provides a flexible plug-in framework for adding message processing modules to an application. These modules, known as handlers, are independent of the application level code and can provide low-level message processing capabilities.
43.1. Handlers: An Introduction
Overview
When a service proxy invokes an operation on a service, the operation’s parameters are passed to Apache CXF where they are built into a message and placed on the wire. When the message is received by the service, Apache CXF reads the message from the wire, reconstructs the message, and then passes the operation parameters to the application code responsible for implementing the operation. When the application code is finished processing the request, the reply message undergoes a similar chain of events on its trip to the service proxy that originated the request. This is shown in Figure 43.1, “Message Exchange Path”.
Figure 43.1. Message Exchange Path
JAX-WS defines a mechanism for manipulating the message data between the application level code and the network. For example, you might want the message data passed over the open network to be encrypted using a proprietary encryption mechanism. You could write a JAX-WS handler that encrypted and decrypted the data. Then you could insert the handler into the message processing chains of all clients and servers.
As shown in Figure 43.2, “Message Exchange Path with Handlers”, the handlers are placed in a chain that is traversed between the application level code and the transport code that places the message onto the network.
Figure 43.2. Message Exchange Path with Handlers
Handler types
The JAX-WS specification defines two basic handler types:
Logical Handler Logical handlers can process the message payload and the properties stored in the message context. For example, if the application uses pure XML messages, the logical handlers have access to the entire message. If the application uses SOAP messages, the logical handlers have access to the contents of the SOAP body. They do not have access to either the SOAP headers or any attachments unless they were placed into the message context.
Logical handlers are placed closest to the application code on the handler chain. This means that they are executed first when a message is passed from the application code to the transport. When a message is received from the network and passed back to the application code, the logical handlers are executed last.
Protocol Handler Protocol handlers can process the entire message received from the network and the properties stored in the message context. For example, if the application uses SOAP messages, the protocol handlers would have access to the contents of the SOAP body, the SOAP headers, and any attachments.
Protocol handlers are placed closest to the transport on the handler chain. This means that they are executed first when a message is received from the network. When a message is sent to the network from the application code, the protocol handlers are executed last.
NoteThe only protocol handler supported by Apache CXF is specific to SOAP.
Implementation of handlers
The differences between the two handler types are very subtle and they share a common base interface. Because of their common parentage, logical handlers and protocol handlers share a number of methods that must be implemented, including:
-
handleMessage() The
handleMessage()
method is the central method in any handler. It is the method responsible for processing normal messages. -
handleFault()
handleFault()
is the method responsible for processing fault messages. -
close()
close()
is called on all executed handlers in a handler chain when a message has reached the end of the chain. It is used to clean up any resources consumed during message processing.
The differences between the implementation of a logical handler and the implementation of a protocol handler revolve around the following:
The specific interface that is implemented
All handlers implement an interface that derives from the Handler interface. Logical handlers implement the LogicalHandler interface. Protocol handlers implement protocol specific extensions of the Handler interface. For example, SOAP handlers implement the SOAPHandler interface.
The amount of information available to the handler
Protocol handlers have access to the contents of messages and all of the protocol specific information that is packaged with the message content. Logical handlers can only access the contents of the message. Logical handlers have no knowledge of protocol details.
Adding handlers to an application
To add a handler to an application you must do the following:
- Determine whether the handler is going to be used on the service providers, the consumers, or both.
- Determine which type of handler is the most appropriate for the job.
Implement the proper interface.
To implement a logical handler see Section 43.2, “Implementing a Logical Handler”.
To implement a protocol handler see Section 43.4, “Implementing a Protocol Handler”.
- Configure your endpoint(s) to use the handlers. See Section 43.10, “Configuring Endpoints to Use Handlers”.
43.2. Implementing a Logical Handler
Overview
Logical handlers implement the javax.xml.ws.handler.LogicalHandler interface. The LogicalHandler interface, shown in Example 43.1, “LogicalHandler Synopsis” passes a LogicalMessageContext
object to the handleMessage()
method and the handleFault()
method. The context object provides access to the body of the message and to any properties set into the message exchange’s context.
Example 43.1. LogicalHandler Synopsis
public interface LogicalHandler extends Handler { boolean handleMessage(LogicalMessageContext context); boolean handleFault(LogicalMessageContext context); void close(LogicalMessageContext context); }
Procedure
To implement a logical hander you do the following:
- Implement any Section 43.6, “Initializing a Handler” logic required by the handler.
- Implement the Section 43.3, “Handling Messages in a Logical Handler” logic.
- Implement the Section 43.7, “Handling Fault Messages” logic.
- Implement the logic for Section 43.8, “Closing a Handler” the handler when it is finished.
- Implement any logic for Section 43.9, “Releasing a Handler” the handler’s resources before it is destroyed.
43.3. Handling Messages in a Logical Handler
Overview
Normal message processing is handled by the handleMessage()
method.
The handleMessage()
method receives a LogicalMessageContext
object that provides access to the message body and any properties stored in the message context.
The handleMessage()
method returns either true or false depending on how message processing is to continue. It can also throw an exception.
Getting the message data
The LogicalMessageContext object passed into logical message handlers allows access to the message body using the context’s getMessage()
method. The getMessage()
method, shown in Example 43.2, “Method for Getting the Message Payload in a Logical Handler”, returns the message payload as a LogicalMessage object.
Example 43.2. Method for Getting the Message Payload in a Logical Handler
LogicalMessage
getMessage
Once you have the LogicalMessage object, you can use it to manipulate the message body. The LogicalMessage interface, shown in Example 43.3, “Logical Message Holder”, has getters and setters for working with the actual message body.
Example 43.3. Logical Message Holder
LogicalMessage
Source
getPayload
Object
getPayload
JAXBContext
context
setPayload
Object
payload
JAXBContext
context
setPayload
Source
payload
The contents of the message payload are determined by the type of binding in use. The SOAP binding only allows access to the SOAP body of the message. The XML binding allows access to the entire message body.
Working with the message body as an XML object
One pair of getters and setters of the logical message work with the message payload as a javax.xml.transform.dom.DOMSource
object.
The getPayload()
method that has no parameters returns the message payload as a DOMSource
object. The returned object is the actual message payload. Any changes made to the returned object change the message body immediately.
You can replace the body of the message with a DOMSource
object using the setPayload()
method that takes the single Source object.
Working with the message body as a JAXB object
The other pair of getters and setters allow you to work with the message payload as a JAXB object. They use a JAXBContext
object to transform the message payload into JAXB objects.
To use the JAXB objects you do the following:
Get a
JAXBContext
object that can manage the data types in the message body.For information on creating a
JAXBContext
object see Chapter 39, Using AJAXBContext
Object.Get the message body as shown in Example 43.4, “Getting the Message Body as a JAXB Object”.
Example 43.4. Getting the Message Body as a JAXB Object
JAXBContext jaxbc = JAXBContext(myObjectFactory.class); Object body = message.getPayload(jaxbc);
- Cast the returned object to the proper type.
- Manipulate the message body as needed.
Put the updated message body back into the context as shown in Example 43.5, “Updating the Message Body Using a JAXB Object”.
Example 43.5. Updating the Message Body Using a JAXB Object
message.setPayload(body, jaxbc);
Working with context properties
The logical message context passed into a logical handler is an instance of the application’s message context and can access all of the properties stored in it. Handlers have access to properties at both the APPLICATION
scope and the HANDLER
scope.
Like the application’s message context, the logical message context is a subclass of Java Map. To access the properties stored in the context, you use the get()
method and put()
method inherited from the Map interface.
By default, any properties you set in the message context from inside a logical handler are assigned a scope of HANDLER
. If you want the application code to be able to access the property you need to use the context’s setScope()
method to explicitly set the property’s scope to APPLICATION.
For more information on working with properties in the message context see Section 42.1, “Understanding Contexts”.
Determining the direction of the message
It is often important to know the direction a message is passing through the handler chain. For example, you would want to retrieve a security token from incoming requests and attach a security token to an outgoing response.
The direction of the message is stored in the message context’s outbound message property. You retrieve the outbound message property from the message context using the MessageContext.MESSAGE_OUTBOUND_PROPERTY key as shown in Example 43.6, “Getting the Message’s Direction from the SOAP Message Context”.
Example 43.6. Getting the Message’s Direction from the SOAP Message Context
Boolean outbound; outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
The property is stored as a Boolean
object. You can use the object’s booleanValue()
method to determine the property’s value. If the property is set to true, the message is outbound. If the property is set to false the message is inbound.
Determining the return value
How the handleMessage()
method completes its message processing has a direct impact on how message processing proceeds. It can complete by doing one of the following actions:
-
Return true—Returning true signals to the Apache CXF runtime that message processing should continue normally. The next handler, if any, has its
handleMessage()
invoked. Return false—Returning false signals to the Apache CXF runtime that normal message processing must stop. How the runtime proceeds depends on the message exchange pattern in use for the current message.
For request-response message exchanges the following happens:
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message stops progressing toward the service’s implementation object. Instead, it is sent back towards the binding for return to the consumer that originated the request.
-
Any message handlers that reside along the handler chain in the new processing direction have their
handleMessage()
method invoked in the order in which they reside in the chain. When the message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
- Message processing stops.
-
All previously invoked message handlers have their
close()
method invoked. - The message is dispatched.
Throw a ProtocolException exception—Throwing a ProtocolException exception, or a subclass of this exception, signals the Apache CXF runtime that fault message processing is beginning. How the runtime proceeds depends on the message exchange pattern in use for the current message.
For request-response message exchanges the following happens:
- If the handler has not already created a fault message, the runtime wraps the message in a fault message.
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message stops progressing toward the service’s implementation object. Instead, it is sent back towards the binding for return to the consumer that originated the request.
-
Any message handlers that reside along the handler chain in the new processing direction have their
handleFault()
method invoked in the order in which they reside in the chain. When the fault message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
- If the handler has not already created a fault message, the runtime wraps the message in a fault message.
- Message processing stops.
-
All previously invoked message handlers have their
close()
method invoked. - The fault message is dispatched.
-
Throw any other runtime exception—Throwing a runtime exception other than a ProtocolException exception signals the Apache CXF runtime that message processing is to stop. All previously invoked message handlers have the
close()
method invoked and the exception is dispatched. If the message is part of a request-response message exchange, the exception is dispatched so that it is returned to the consumer that originated the request.
Example
Example 43.7, “Logical Message Handler Message Processing” shows an implementation of handleMessage()
message for a logical message handler that is used by a service consumer. It processes requests before they are sent to the service provider.
Example 43.7. Logical Message Handler Message Processing
public class SmallNumberHandler implements LogicalHandler<LogicalMessageContext> { public final boolean handleMessage(LogicalMessageContext messageContext) { try { boolean outbound = (Boolean)messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outbound) { LogicalMessage msg = messageContext.getMessage(); JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); Object payload = msg.getPayload(jaxbContext); if (payload instanceof JAXBElement) { payload = ((JAXBElement)payload).getValue(); } if (payload instanceof AddNumbers) { AddNumbers req = (AddNumbers)payload; int a = req.getArg0(); int b = req.getArg1(); int answer = a + b; if (answer < 20) { AddNumbersResponse resp = new AddNumbersResponse(); resp.setReturn(answer); msg.setPayload(new ObjectFactory().createAddNumbersResponse(resp), jaxbContext); return false; } } else { throw new WebServiceException("Bad Request"); } } return true; } catch (JAXBException ex) { throw new ProtocolException(ex); } } ... }
The code in Example 43.7, “Logical Message Handler Message Processing” does the following:
Checks if the message is an outbound request.
If the message is an outbound request, the handler does additional message processing.
Gets the LogicalMessage representation of the message payload from the message context.
Gets the actual message payload as a JAXB object.
Checks to make sure the request is of the correct type.
If it is, the handler continues processing the message.
Checks the value of the sum.
If it is less than the threshold of 20 then it builds a response and returns it to the client.
Builds the response.
Returns false to stop message processing and return the response to the client.
Throws a runtime exception if the message is not of the correct type.
This exception is returned to the client.
Returns true if the message is an inbound response or the sum does not meet the threshold.
Message processing continues normally.
Throws a ProtocolException if a JAXB marshalling error is encountered.
The exception is passed back to the client after it is processed by the handleFault()
method of the handlers between the current handler and the client.
43.4. Implementing a Protocol Handler
Overview
Protocol handlers are specific to the protocol in use. Apache CXF provides the SOAP protocol handler as specified by JAX-WS. A SOAP protocol handler implements the javax.xml.ws.handler.soap.SOAPHandler interface.
The SOAPHandler interface, shown in Example 43.8, “SOAPHandler Synopsis”, uses a SOAP specific message context that provides access to the message as a SOAPMessage
object. It also allows you to access the SOAP headers.
Example 43.8. SOAPHandler Synopsis
public interface SOAPHandler extends Handler
{
boolean handleMessage(SOAPMessageContext context);
boolean handleFault(SOAPMessageContext context);
void close(SOAPMessageContext context);
Set<QName> getHeaders()
}
In addition to using a SOAP specific message context, SOAP protocol handlers require that you implement an additional method called getHeaders()
. This additional method returns the QNames of the header blocks the handler can process.
Procedure
To implement a logical hander do the following:
- Implement any Section 43.6, “Initializing a Handler” logic required by the handler.
- Implement the Section 43.5, “Handling Messages in a SOAP Handler” logic.
- Implement the Section 43.7, “Handling Fault Messages” logic.
-
Implement the
getHeaders()
method. - Implement the logic for Section 43.8, “Closing a Handler” the handler when it is finished.
- Implement any logic for Section 43.9, “Releasing a Handler” the handler’s resources before it is destroyed.
Implementing the getHeaders() method
The getHeaders()
, shown in Example 43.9, “The SOAPHander.getHeaders()
Method”, method informs the Apache CXF runtime what SOAP headers the handler is responsible for processing. It returns the QNames of the outer element of each SOAP header the handler understands.
Example 43.9. The SOAPHander.getHeaders()
Method
Set<QName>
getHeaders
For many cases simply returning null is sufficient. However, if the application uses the mustUnderstand
attribute of any of the SOAP headers, then it is important to specify the headers understood by the application’s SOAP handlers. The runtime checks the set of SOAP headers that all of the registered handlers understand against the list of headers with the mustUnderstand
attribute set to true
. If any of the flagged headers are not in the list of understood headers, the runtime rejects the message and throws a SOAP must understand exception.
43.5. Handling Messages in a SOAP Handler
Overview
Normal message processing is handled by the handleMessage()
method.
The handleMessage()
method receives a SOAPMessageContext
object that provides access to the message body as a SOAPMessage
object and the SOAP headers associated with the message. In addition, the context provides access to any properties stored in the message context.
The handleMessage()
method returns either true or false depending on how message processing is to continue. It can also throw an exception.
Working with the message body
You can get the SOAP message using the SOAP message context’s getMessage()
method. It returns the message as a live SOAPMessage
object. Any changes to the message in the handler are automatically reflected in the message stored in the context.
If you wish to replace the existing message with a new one, you can use the context’s setMessage()
method. The setMessage()
method takes a SOAPMessage
object.
Getting the SOAP headers
You can access the SOAP message’s headers using the SOAPMessage
object’s getHeader()
method. This will return the SOAP header as a SOAPHeader
object that you will need to inspect to find the header elements you wish to process.
The SOAP message context provides a getHeaders()
method, shown in Example 43.10, “The SOAPMessageContext.getHeaders()
Method”, that will return an array containing JAXB objects for the specified SOAP headers.
Example 43.10. The SOAPMessageContext.getHeaders()
Method
Ojbect[]
getHeaders
QName
header
JAXBContext
context
boolean
allRoles
You specify the headers using the QName of their element. You can further limit the headers that are returned by setting the allRoles
parameter to false. That instructs the runtime to only return the SOAP headers that are applicable to the active SOAP roles.
If no headers are found, the method returns an empty array.
For more information about instantiating a JAXBContext
object see Chapter 39, Using A JAXBContext
Object.
Working with context properties
The SOAP message context passed into a logical handler is an instance of the application’s message context and can access all of the properties stored in it. Handlers have access to properties at both the APPLICATION
scope and the Handler
scope.
Like the application’s message context, the SOAP message context is a subclass of Java Map. To access the properties stored in the context, you use the get()
method and put()
method inherited from the Map interface.
By default, any properties you set in the context from inside a logical handler will be assigned a scope of HANDLER
. If you want the application code to be able to access the property you need to use the context’s setScope()
method to explicitly set the property’s scope to APPLICATION.
For more information on working with properties in the message context see Section 42.1, “Understanding Contexts”.
Determining the direction of the message
It is often important to know the direction a message is passing through the handler chain. For example, you would want to add headers to an outgoing message and strip headers from an incoming message.
The direction of the message is stored in the message context’s outbound message property. You retrieve the outbound message property from the message context using the MessageContext.MESSAGE_OUTBOUND_PROPERTY key as shown in Example 43.11, “Getting the Message’s Direction from the SOAP Message Context”.
Example 43.11. Getting the Message’s Direction from the SOAP Message Context
Boolean outbound; outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
The property is stored as a Boolean
object. You can use the object’s booleanValue()
method to determine the property’s value. If the property is set to true, the message is outbound. If the property is set to false the message is inbound.
Determining the return value
How the handleMessage()
method completes its message processing has a direct impact on how message processing proceeds. It can complete by doing one of the following actions:
-
return true—Returning true signals to the Apache CXF runtime that message processing should continue normally. The next handler, if any, has its
handleMessage()
invoked. return false—Returning false signals to the Apache CXF runtime that normal message processing is to stop. How the runtime proceeds depends on the message exchange pattern in use for the current message.
For request-response message exchanges the following happens:
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message will stop progressing toward the service’s implementation object. It will instead be sent back towards the binding for return to the consumer that originated the request.
-
Any message handlers that reside along the handler chain in the new processing direction have their
handleMessage()
method invoked in the order in which they reside in the chain. When the message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
- Message processing stops.
-
All previously invoked message handlers have their
close()
method invoked. - The message is dispatched.
throw a ProtocolException exception—Throwing a ProtocolException exception, or a subclass of this exception, signals the Apache CXF runtime that fault message processing is to start. How the runtime proceeds depends on the message exchange pattern in use for the current message.
For request-response message exchanges the following happens:
- If the handler has not already created a fault message, the runtime wraps the message in a fault message.
The direction of message processing is reversed.
For example, if a request is being processed by a service provider, the message will stop progressing toward the service’s implementation object. It will be sent back towards the binding for return to the consumer that originated the request.
-
Any message handlers that reside along the handler chain in the new processing direction have their
handleFault()
method invoked in the order in which they reside in the chain. When the fault message reaches the end of the handler chain it is dispatched.
For one-way message exchanges the following happens:
- If the handler has not already created a fault message, the runtime wraps the message in a fault message.
- Message processing stops.
-
All previously invoked message handlers have their
close()
method invoked. - The fault message is dispatched.
-
throw any other runtime exception—Throwing a runtime exception other than a ProtocolException exception signals the Apache CXF runtime that message processing is to stop. All previously invoked message handlers have the
close()
method invoked and the exception is dispatched. If the message is part of a request-response message exchange the exception is dispatched so that it is returned to the consumer that originated the request.
Example
Example 43.12, “Handling a Message in a SOAP Handler” shows a handleMessage()
implementation that prints the SOAP message to the screen.
Example 43.12. Handling a Message in a SOAP Handler
public boolean handleMessage(SOAPMessageContext smc) { PrintStream out; Boolean outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outbound.booleanValue()) { out.println("\nOutbound message:"); } else { out.println("\nInbound message:"); } SOAPMessage message = smc.getMessage(); message.writeTo(out); out.println(); return true; }
The code in Example 43.12, “Handling a Message in a SOAP Handler” does the following:
Retrieves the outbound property from the message context.
Tests the messages direction and prints the appropriate message.
Retrieves the SOAP message from the context.
Prints the message to the console.
43.6. Initializing a Handler
Overview
When the runtime creates an instance of a handler, it creates all of the resources the hander needs to process messages. While you can place all of the logic for doing this in the handler’s constructor, it may not be the most appropriate place. The handler framework performs a number of optional steps when it instantiates a handler. You can add resource injection and other initialization logic that will be executed during the optional steps.
You do not have to provide any initialization methods for a handler.
Order of initialization
The Apache CXF runtime initializes a handler in the following manner:
- The handler’s constructor is called.
-
Any resources that are specified by the
@Resource
annotation are injected. The method decorated with
@PostConstruct
annotation, if it is present, is called.NoteMethods decorated with the
@PostConstruct
annotation must have avoid
return type and have no parameters.-
The handler is place in the
Ready
state.
43.7. Handling Fault Messages
Overview
Handlers use the handleFault()
method for processing fault messages when a ProtocolException exception is thrown during message processing.
The handleFault()
method receives either a LogicalMessageContext
object or SOAPMessageContext
object depending on the type of handler. The received context gives the handler’s implementation access to the message payload.
The handleFault()
method returns either true or false, depending on how fault message processing is to proceed. It can also throw an exception.
Getting the message payload
The context object received by the handleFault()
method is similar to the one received by the handleMessage()
method. You use the context’s getMessage()
method to access the message payload in the same way. The only difference is the payload contained in the context.
For more information on working with a LogicalMessageContext
see Section 43.3, “Handling Messages in a Logical Handler”.
For more information on working with a SOAPMessageContext
see Section 43.5, “Handling Messages in a SOAP Handler”.
Determining the return value
How the handleFault()
method completes its message processing has a direct impact on how message processing proceeds. It completes by performing one of the following actions:
- Return true
-
Returning true signals that fault processing should continue normally. The
handleFault()
method of the next handler in the chain will be invoked. - Return false
-
Returning false signals that fault processing stops. The
close()
method of the handlers that were invoked in processing the current message are invoked and the fault message is dispatched. - Throw an exception
-
Throwing an exception stops fault message processing. The
close()
method of the handlers that were invoked in processing the current message are invoked and the exception is dispatched.
Example
Example 43.13, “Handling a Fault in a Message Handler” shows an implementation of handleFault()
that prints the message body to the screen.
Example 43.13. Handling a Fault in a Message Handler
public final boolean handleFault(LogicalMessageContext messageContext) { System.out.println("handleFault() called with message:"); LogicalMessage msg=messageContext.getMessage(); System.out.println(msg.getPayload()); return true; }
43.8. Closing a Handler
When a handler chain is finished processing a message, the runtime calls each executed handler’s close()
method. This is the appropriate place to clean up any resources that were used by the handler during message processing or resetting any properties to a default state.
If a resource needs to persist beyond a single message exchange, you should not clean it up during in the handler’s close()
method.
43.9. Releasing a Handler
Overview
The runtime releases a handler when the service or service proxy to which the handler is bound is shutdown. The runtime will invoke an optional release method before invoking the handler’s destructor. This optional release method can be used to release any resources used by the handler or perform other actions that would not be appropriate in the handler’s destructor.
You do not have to provide any clean-up methods for a handler.
Order of release
The following happens when the handler is released:
- The handler finishes processing any active messages.
The runtime invokes the method decorated with the
@PreDestroy
annotation.This method should clean up any resources used by the handler.
- The handler’s destructor is called.
43.10. Configuring Endpoints to Use Handlers
43.10.1. Programmatic Configuration
43.10.1.1. Adding a Handler Chain to a Consumer
Overview
Adding a handler chain to a consumer involves explicitly building the chain of handlers. Then you set the handler chain directly on the service proxy’s Binding
object.
Any handler chains configured using the Spring configuration override the handler chains configured programmaticaly.
Procedure
To add a handler chain to a consumer you do the following:
-
Create a
List<Handler>
object to hold the handler chain. - Create an instance of each handler that will be added to the chain.
- Add each of the instantiated handler objects to the list in the order they are to be invoked by the runtime.
Get the Binding object from the service proxy.
Apache CXF provides an implementation of the Binding interface called
org.apache.cxf.jaxws.binding.DefaultBindingImpl
.-
Set the handler chain on the proxy using the Binding object’s
setHandlerChain()
method.
Example
Example 43.14, “Adding a Handler Chain to a Consumer” shows code for adding a handler chain to a consumer.
Example 43.14. Adding a Handler Chain to a Consumer
import javax.xml.ws.BindingProvider; import javax.xml.ws.handler.Handler; import java.util.ArrayList; import java.util.List; import org.apache.cxf.jaxws.binding.DefaultBindingImpl; ... SmallNumberHandler sh = new SmallNumberHandler(); List<Handler> handlerChain = new ArrayList<Handler>(); handlerChain.add(sh); DefaultBindingImpl binding = ((BindingProvider)proxy).getBinding(); binding.getBinding().setHandlerChain(handlerChain);
The code in Example 43.14, “Adding a Handler Chain to a Consumer” does the following:
Instantiates a handler.
Creates a List
object to hold the chain.
Adds the handler to the chain.
Gets the Binding object from the proxy as a DefaultBindingImpl
object.
Assigns the handler chain to the proxy’s binding.
43.10.1.2. Adding a Handler Chain to a Service Provider
Overview
You add a handler chain to a service provider by decorating either the SEI or the implementation class with the @HandlerChain
annotation. The annotation points to a meta-data file defining the handler chain used by the service provider.
Procedure
To add handler chain to a service provider you do the following:
-
Decorate the provider’s implementation class with the
@HandlerChain
annotation. - Create a handler configuration file that defines the handler chain.
The @HandlerChain annotation
The javax.jws.HandlerChain
annotation decorates service provider’s implementation class. It instructs the runtime to load the handler chain configuration file specified by its file
property.
The annotation’s file
property supports two methods for identifying the handler configuration file to load:
- a URL
- a relative path name
Example 43.15, “Service Implementation that Loads a Handler Chain” shows a service provider implementation that will use the handler chain defined in a file called handlers.xml
. handlers.xml
must be located in the directory from which the service provider is run.
Example 43.15. Service Implementation that Loads a Handler Chain
import javax.jws.HandlerChain;
import javax.jws.WebService;
...
@WebService(name = "AddNumbers",
targetNamespace = "http://apache.org/handlers",
portName = "AddNumbersPort",
endpointInterface = "org.apache.handlers.AddNumbers",
serviceName = "AddNumbersService")
@HandlerChain(file = "handlers.xml")
public class AddNumbersImpl implements AddNumbers
{
...
}
Handler configuration file
The handler configuration file defines a handler chain using the XML grammar that accompanies JSR 109 (Web Services for Java EE, Version 1.2). This grammar is defined in the http://java.sun.com/xml/ns/javaee
.
The root element of the handler configuration file is the handler-chains
element. The handler-chains
element has one or more handler-chain
elements.
The handler-chain
element define a handler chain. Table 43.1, “Elements Used to Define a Server-Side Handler Chain” describes the handler-chain
element’s children.
Element | Description |
---|---|
Contains the elements that describe a handler. | |
Specifies the QName of the WSDL | |
Specifies the QName of the WSDL | |
Specifies the message binding for which the handler chain is used. The binding is specified as a URI or using one of the following aliases: For more information about message binding URIs see Chapter 23, Apache CXF Binding IDs. |
The handler-chain
element is only required to have a single handler
element as a child. It can, however, support as many handler
elements as needed to define the complete handler chain. The handlers in the chain are executed in the order they specified in the handler chain definition.
The final order of execution will be determined by sorting the specified handlers into logical handlers and protocol handlers. Within the groupings, the order specified in the configuration will be used.
The other children, such as protocol-binding
, are used to limit the scope of the defined handler chain. For example, if you use the service-name-pattern
element, the handler chain will only be attached to service providers whose WSDL port
element is a child of the specified WSDL service
element. You can only use one of these limiting children in a handler
element.
The handler
element defines an individual handler in a handler chain. Its handler-class
child element specifies the fully qualified name of the class implementing the handler. The handler
element can also have an optional handler-name
element that specifies a unique name for the handler.
Example 43.16, “Handler Configuration File” shows a handler configuration file that defines a single handler chain. The chain is made up of two handlers.
Example 43.16. Handler Configuration File
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-name>LoggingHandler</handler-name> <handler-class>demo.handlers.common.LoggingHandler</handler-class> </handler> <handler> <handler-name>AddHeaderHandler</handler-name> <handler-class>demo.handlers.common.AddHeaderHandler</handler-class> </handler> </handler-chain> </handler-chains>
43.10.2. Spring Configuration
Overview
The easiest way to configure an endpoint to use a handler chain is to define the chain in the endpoint’s configuration. This is done by adding a jaxwxs:handlers
child to the element configuring the endpoint.
A handler chain added through the configuration file takes precedence over a handler chain configured programatically.
Procedure
To configure an endpoint to load a handler chain you do the following:
If the endpoint does not already have a configuration element, add one.
For more information on configuring Apache CXF endpoints see Chapter 17, Configuring JAX-WS Endpoints.
-
Add a
jaxws:handlers
child element to the endpoint’s configuration element. For each handler in the chain, add a
bean
element specifying the class that implements the handler.If your handler implementation is used in more than one place you can reference a
bean
element using theref
element.
The handlers element
The jaxws:handlers
element defines a handler chain in an endpoint’s configuration. It can appear as a child to all of the JAX-WS endpoint configuration elements. These are:
-
jaxws:endpoint
configures a service provider. -
jaxws:server
also configures a service provider. -
jaxws:client
configures a service consumer.
You add handlers to the handler chain in one of two ways:
-
add a
bean
element defining the implementation class -
use a
ref
element to refer to a namedbean
element from elsewhere in the configuration file
The order in which the handlers are defined in the configuration is the order in which they will be executed. The order may be modified if you mix logical handlers and protocol handlers. The run time will sort them into the proper order while maintaining the basic order specified in the configuration.
Example
Example 43.17, “Configuring an Endpoint to Use a Handler Chain In Spring” shows the configuration for a service provider that loads a handler chain.
Example 43.17. Configuring an Endpoint to Use a Handler Chain In Spring
<beans ... xmlns:jaxws="http://cxf.apache.org/jaxws" ... schemaLocation="... http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd ..."> <jaxws:endpoint id="HandlerExample" implementor="org.apache.cxf.example.DemoImpl" address="http://localhost:8080/demo"> <jaxws:handlers> <bean class="demo.handlers.common.LoggingHandler" /> <bean class="demo.handlers.common.AddHeaderHandler" /> </jaxws:handlers> </jaws:endpoint> </beans>