NetBeans IDE makes it easy to develop Java EE web services and clients because it shields application developers from the underlying SOAP messages. Instead of writing code to build and parse SOAP messages, you merely implement the service methods and invoke them from remote clients. However, there might be times when you want to add functionality to web service applications without having to change the web service or client code. For example, you might want to encrypt remote calls at the SOAP message level. SOAP message handlers provide the mechanism for adding this functionality without having to change the business logic. Handlers accomplish this by intercepting the SOAP message as it makes its way between the client and service. A SOAP message handler is a stateless instance that accesses SOAP messages representing RPC requests, responses, or faults. Tied to service endpoints, handlers enable you to process SOAP messages and to extend the functionality of the service. For a given service endpoint, one or more handlers may reside on the server and client. A SOAP request is handled as follows:
A SOAP response is processed in this order:
To create a message handler in a web application in the IDE:
Figure 12-16. New Message Handler page of the New File wizardThe new Java file created contains the core code for the message handler, as shown in the code sample below. One interesting method here is handleRequest(MessageContext context), which is called before the SOAP message is dispatched to the endpoint. The generated handler class provides a default implementation of this method (as an example), which prints out the contents of the SOAP body plus some date information. Note that the MessageContext parameter provides a context for obtaining the transmitted SOAP message. You may then use the SAAJ API (SOAP with Attachments API for Java) to access and manipulate the SOAP message. Another method, handleResponse(MessageContext context), is called before the response message is sent back to the caller. This method, together with handleFault, provides only the default implementation; it is left to you to provide your own implementation. package com.acme; import javax.xml.rpc.handler.MessageContext; import javax.xml.rpc.handler.HandlerInfo; import javax.xml.rpc.handler.soap.SOAPMessageContext; import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPBody; import java.util.Date; public class NewMessageHandler extends javax.xml.rpc.handler.GenericHandler { // TODO Change and enhance the handle methods to suit individual needs. private QName[] headers; public void init(HandlerInfo config) { headers = config.getHeaders(); } public javax.xml.namespace.QName[] getHeaders() { return headers; } // Currently prints out the contents of the SOAP body plus some date information. public boolean handleRequest(MessageContext context) { try{ SOAPMessageContext smc = (SOAPMessageContext) context; SOAPMessage msg = smc.getMessage(); SOAPPart sp = msg.getSOAPPart(); SOAPEnvelope se = sp.getEnvelope(); SOAPHeader shd = se.getHeader(); SOAPBody sb = se.getBody(); java.util.Iterator childElems = sb.getChildElements(); SOAPElement child; StringBuffer message = new StringBuffer(); while (childElems.hasNext()) { child = (SOAPElement) childElems.next(); message.append(new Date().toString() + "--"); formLogMessage(child, message); } System.out.println("Log message: " + message.toString()); } catch(Exception e){ e.printStackTrace(); } return true; } public boolean handleResponse(MessageContext context) { return true; } public boolean handleFault(MessageContext context) { return true; } public void destroy() { } private void formLogMessage(SOAPElement child, StringBuffer message) { message.append(child.getElementName().getLocalName()); message.append(child.getValue() != null ? ":" + child.getValue() + " " : " "); try{ java.util.Iterator childElems = child.getChildElements(); while (childElems.hasNext()) { Object c = childElems.next(); if(c instanceof SOAPElement) formLogMessage((SOAPElement)c, message); } }catch(Exception e){ e.printStackTrace(); } } } Once this message handler is created, you need to associate it with your web service. To associate a message handler with a web service:
Following is an example of a webservices.xml file that the IDE has updated for you. (In general, you do not have to worry about this file at all. The IDE keeps it up to date for you.) <?xml version='1.0' encoding='UTF-8' ?> <webservices xmlns='http://java.sun.com/xml/ns/j2ee' xmlns:xsi='http:// www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http:// java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ j2ee_web_services_1_1.xsd' version='1.1'> <webservice-description> <webservice-description-name> NewWebService </webservice-description-name> <wsdl-file>WEB-INF/wsdl/NewWebService.wsdl</wsdl-file> <jaxrpc-mapping-file> WEB-INF/NewWebService-mapping.xml </jaxrpc-mapping-file> <port-component xmlns:wsdl-port_ns='urn:NewWebService/wsdl'> <port-component-name>NewWebService</port-component-name> <wsdl-port>wsdl-port_ns:NewWebServiceSEIPort</wsdl-port> <service-endpoint-interface>com.acme.NewWebServiceSEI </service-endpoint-interface> <service-impl-bean> <servlet-link>WSServlet_NewWebService</servlet-link> </service-impl-bean> <handler> <handler-name>com.acme.NewMessageHandler</handler-name> <handler-class>com.acme.NewMessageHandler</handler-class> </handler> </port-component> </webservice-description> </webservices> To see the effect of the message handler on the web service, perform the following steps:
You can see the handler trace in the application server log file by opening the Runtime window, expanding the Servers node, right-clicking the Sun Java System Application Server node, and choosing View Server Log. A trace that looks something like the following should be displayed: ... [#|2006-01-17T16:33:36.514-0800|INFO|sun-appserver- pe8.2|javax.enterprise.resource.webservices.rpc.server.http|_ThreadID=20 ;|JAXRPCSERVLET14: JAX-RPC servlet initializing|#] [#|2006-01-17T16:33:36.564-0800|INFO|sun-appserver- pe8.2|javax.enterprise.system.tools.admin|_ThreadID=20;|ADM1042:Status of dynamic reconfiguration event processing:[success]|#] [#|2006-01-17T16:33:46.909-0800|INFO|sun-appserver- pe8.2|javax.enterprise.system.stream.out|_ThreadID=15;|Log message: Tue Jan 17 16:33:46 PST 2006--getValidation String_1:SunCustomer |#] |