Bo's blog

Friday, March 26, 2010

WebShpere Document

 

Websphere document:

http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.wsfep.multiplatform.doc/info/ae/ae/twbs_jaxwshandler.html

Weblogic Server Documents

 

ORACLE WEBLOGIC SERVER DOCUMENTATION:

http://download.oracle.com/docs/cd/E12839_01/wls.htm

Using handlers in JAX-WS Web services

keep a copy from (http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.wsfep.multiplatform.doc/info/ae/ae/twbs_jaxwshandler.html)

Using handlers in JAX-WS Web services

Java API for XML Web Services (JAX-WS) provides you with a standard way of developing interoperable and portable Web services. Use JAX-WS handlers to customize Web services requests or response handling.

Before you begin

You need an enterprise archive (EAR) file for the applications that you want to configure. If you are running in a Thin Client for JAX-WS environment, then you are not required to begin with an EAR file. For some handler use, such as logging or tracing, only the server or client application needs to be configured. For other handler use, including sending information in SOAP headers, the client and server applications must be configured with symmetrical handlers.

The modules in the EAR file must contain the handler classes to configure. The handler classes implement thejavax.xml.ws.handler.LogicalHandler<LogicalMessageContext> interface or the javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageContext> interface.

About this task

As in the Java API for XML-based RPC (JAX-RPC) programming model, the JAX-WS programming model provides an application handler facility that enables you to manipulate a message on either an inbound or an outbound flow. You can add handlers into the JAX-WS runtime environment to perform additional processing of request and response messages. You can use handlers for a variety of purposes such as capturing and logging information and adding security or other information to a message. Because of the support for additional protocols beyond SOAP, JAX-WS provides two different classifications for handlers. One type of handler is a logical handler that is protocol independent and can obtain the message in the flow as an extensible markup language (XML) message. The logical handlers operate on message context properties and message payload. These handlers must implement the javax.xml.ws.handler.LogicalHandler interface. A logical handler receives a LogicalMessageContext object from which the handler can get the message information. Logical handlers can exist on both SOAP and XML/HTTP-based configurations.

The second type of handler is a protocol handler. The protocol handlers operate on message context properties and protocol-specific messages. Protocol handlers are limited to SOAP-based configurations and must implement the javax.xml.ws.handler.soap.SOAPHandler interface. Protocol handlers receive the message as a javax.xml.soap.SOAPMessage to read the message data.

The JAX-WS runtime makes no distinction between server-side and client-side handler classes. The runtime does not distinguish between inbound or outbound flow when a handleMessage(MessageContext) method or handleFault(MessageContext) method for a specific handler is invoked. You must configure the handlers for the server or client, and implement sufficient logic within these methods to detect the inbound or outbound direction of the current message.

To use handlers with Web services client applications, you must add the @HandlerChain annotation to the service endpoint interface or the generated service class and provide the handler chain configuration file. The @HandlerChain annotation contains a file attribute that points to a handler chain configuration file that you create. For Web services client applications, you can also configure the handler chain programmatically using the Binding API. To modify the handlerchain class programmatically, use either the default implementation or a custom implementation of the HandlerResolver method.

To use handlers with your server application, you must set the @HandlerChain annotation on either the service endpoint interface or the endpoint implementation class, and provide the associated handler chain configuration file. Handlers for the server are only configured by setting the @HandlerChain annotation on the service endpoint implementation or the implementation class. The handler classes must be included in the server application EAR file.

For both server and client implementations of handlers using the @HandlerChain annotation, you must specify the location of the handler configuration as either a relative path from the annotated file or as an absolute URL. For example:

@HandlerChain(file="../../common/handlers/myhandlers.xml")

or

@HandlerChain(file="http://foo.com/myhandlers.xml")

For more information on the schema of the handler configuration file, see the JSR 181 specification.

For more information regarding JAX-WS handlers, see chapter 9 of the JAX-WS specification.



Procedure



  1. Determine if you want to implement JAX-WS handlers on the service or the client.


  2. Configure the client handlers by setting the @HandlerChain annotation on the service instance or service endpoint interface, or you can modify the handler chain programmatically to control how the handler chain is built in the runtime. If you choose to modify the handler chain programmatically, then you must determine if you will use the default handler resolver or use a custom implementation of a handler resolver that is registered on the service instance. A service instance uses a handler resolver when creating binding providers. When the binding providers are created, the handler resolver that is registered with a service is used to create a handler chain and the handler chain is subsequently used to configure the binding provider.

    1. Use the default implementation of a handler resolver. The runtime now uses the @HandlerChain annotation and the default implementation of HandlerResolver class to build the handler chain. You can obtain the existing handler chain from the Binding, add or remove handlers, and then return the modified handler chain to the Binding object.


    2. To use a custom implementation of a handler resolver, set the custom HandlerResolver class on the Service instance. The runtime uses your custom implementation of the HandlerResolver class to build the handler chain, and the default runtime implementation is not used. In this scenario, the @HandlerChain annotation is not read when retrieving the handler chain from the binding after the custom HandlerResolver instance is registered on the Service instance. You can obtain the existing handler chain from the Binding, add or remove handlers, and then return the modified handler chain to the Binding object.




  3. Configure the server handlers by setting the @HandlerChain annotation on the service endpoint interface or implementation class. When the @HandlerChain annotation is configured on both the service endpoint interface and the implementation class, the implementation class takes priority.


  4. Create the handler chain configuration XML file. You must create a handler chain configuration XML file for the @HandlerChain to reference.


  5. Add the handler chain configuration XML file in the class path for the service endpoint interface when configuring the server or client handlers using the @HandlerChain annotation. You must also include the handler classes contained in the configuration XML file in your class path.


  6. Write your handler implementation.



Results


You have the enabled your JAX-WS Web service or Web services client to use handlers to perform additional processing of request and response message exchange.



Example


The following example illustrates the steps necessary to configure JAX-WS handlers on a service endpoint interface using the @HandlerChain annotation.



The @HandlerChain annotation has a file attribute that points to a handler chain configuration XML file that you create. The following file illustrates a typical handler configuration file. The protocol-bindings, port-name-pattern, and service-name-pattern elements are all filters that are used to restrict which services can apply the handlers.



<?xml version="1.0" encoding="UTF-8"?>

<jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee">
<!-- Note: The '*" denotes a wildcard. -->

<jws:handler-chain name="MyHandlerChain">
<jws:protocol-bindings>##SOAP11_HTTP ##ANOTHER_BINDING</jws:protocol-bindings>
<jws:port-name-pattern
xmlns:ns1="http://handlersample.samples.ibm.com/">ns1:MySampl*</jws:port-name-pattern>
<jws:service-name-pattern
xmlns:ns1="http://handlersample.samples.ibm.com/">ns1:*</jws:service-name-pattern>
<jws:handler>
<jws:handler-class>com.ibm.samples.handlersample.SampleLogicalHandler</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>com.ibm.samples.handlersample.SampleProtocolHandler2</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>com.ibm.samples.handlersample.SampleLogicalHandler</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>com.ibm.samples.handlersample.SampleProtocolHandler2</jws:handler-class>
</jws:handler>
</jws:handler-chain>

</jws:handler-chains>

</jws:handler-chains>


Make sure that you add the handler.xml file and the handler classes contained in the handler.xml file in your class path.



The following example demonstrates a handler implementation:



package com.ibm.samples.handlersample;

import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SampleProtocolHandler implements
javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageContext> {

public void close(MessageContext messagecontext) {
}

public Set<QName> getHeaders() {
return null;
}

public boolean handleFault(SOAPMessageContext messagecontext) {
return true;
}

public boolean handleMessage(SOAPMessageContext messagecontext) {
Boolean outbound = (Boolean) messagecontext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
// Include your steps for the outbound flow.
}
return true;
}

}


What to do next

Deploy your Web services application.

Thursday, March 25, 2010

Use the soap handler to intercept the request/response

here is the source code, it intercept the fault response message by adding the type for some tags:

1. add annotation @HandlerChain (file = "soaphandlerchain.xml") to the class which has @WebService annotation

2. put the soaphandlerchain.xml as the same package as the web service impl class.

3. implement the handler descripted in the soaphandlerchain.xml

Hello.java

package helloservice.endpoint;
import javax.ejb.Stateless;
import javax.jws.HandlerChain;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
@WebService (serviceName = "services", portName = "hello", targetNamespace = "http://mytest.com")
@Stateless (mappedName = "HelloEjb")
@HandlerChain (file = "soaphandlerchain.xml")
public class Hello
{
  private String message = new String ("Hello, ");
  public void Hello ()
  {
  }
  @WebMethod
  public String sayHello (String name) throws MyException
  {
    if (name == null || name.isEmpty ())
    {
      final String msg = "The name cannot be null.";
      MyExceptionBean faultBean = new MyExceptionBean ();
      faultBean.setErrorCode ("E60001");
      throw new MyException (msg, faultBean);
    }
    return message + name;
  }
}


now it is the xml file soaphandlerchain.xml, this file must be at the same package as the Hello.java


<?xml version="1.0" encoding="UTF-8"?>
<jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee">
  <jws:handler-chain>
    <jws:handler>
      <jws:handler-name>HelloSoapHandler</jws:handler-name>
      <jws:handler-class>helloservice.endpoint.HelloSoapHandler</jws:handler-class>
    </jws:handler>
  </jws:handler-chain>
</jws:handler-chains>


now it is the SOAP Handler class (changed based on http://blog.jdevelop.eu/2008/03/08/how-to-modify-jax-ws-soap-messages/)



package helloservice.endpoint;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
 * This class handles the SOAP-Requests before they reach the
 * Web Service Operation. It is possible to read and manipulate
 * the SOAP-Message.
 *
 */
public class HelloSoapHandler implements SOAPHandler<SOAPMessageContext>
{
  /**
   * Is called after constructing the handler and before executing any othe method.
   */
  @PostConstruct
  public void init ()
  {
  }
  /**
   * Returns the <code>Set</code> of supported SOAP headers
   */
  public Set<QName> getHeaders ()
  {
    return null;
  }
  /**
   * Returns the message encoding (e.g. utf-8)
   *
   * @param msg
   * @return
   * @throws javax.xml.soap.SOAPException
   */
  private String getMessageEncoding (SOAPMessage msg) throws SOAPException
  {
    String encoding = "utf-8";
    if (msg.getProperty (SOAPMessage.CHARACTER_SET_ENCODING) != null)
    {
      encoding = msg.getProperty (SOAPMessage.CHARACTER_SET_ENCODING)
          .toString ();
    }
    return encoding;
  }
  /**
   * Dump SOAP Message to console
   *
   * @param msg
   */
  private void dumpSOAPMessage (SOAPMessage msg)
  {
    if (msg == null)
    {
      System.out.println ("SOAP Message is null");
      return;
    }
    System.out.println ("");
    System.out.println ("--------------------");
    System.out.println ("DUMP OF SOAP MESSAGE");
    System.out.println ("--------------------");
    try
    {
      ByteArrayOutputStream baos = new ByteArrayOutputStream ();
      msg.writeTo (baos);
      System.out.println (baos.toString (getMessageEncoding (msg)));
      // show included values
      String values = msg.getSOAPBody ().getTextContent ();
      System.out.println ("Included values:" + values);
    }
    catch (Exception e)
    {
      e.printStackTrace ();
    }
  }
  /**
   * This method handles the incoming and outgoing SOAP-Message.
   * It's an excellent point to manipulate the SOAP.
   *
   * @param SOAPMessageContext
   * @return boolean
   */
  public boolean handleMessage (SOAPMessageContext context)
  {
    //Inquire incoming or outgoing message.
    boolean outbound = (Boolean) context
        .get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    try
    {
      if (outbound)
      {
        // OUTBOUND
        System.out.println ("Direction=outbound (handleMessage)");
        SOAPMessage msg = ((SOAPMessageContext) context).getMessage ();
        // get SOAP-Part
        SOAPPart sp = msg.getSOAPPart ();
        //edit Envelope
        SOAPEnvelope env = sp.getEnvelope ();
        // add namespaces
        env.addNamespaceDeclaration ("xsd", "http://www.w3.org/2001/XMLSchema");
        env.addNamespaceDeclaration ("xsi",
            "http://www.w3.org/2001/XMLSchema-instance");
        env.addNamespaceDeclaration ("soap",
            "http://schemas.xmlsoap.org/soap/envelope");
        // get the SOAP-Body
        SOAPBody body = env.getBody ();
        // add an additional Element to the SOAP-Body
        SOAPBodyElement bodyElement = body.addBodyElement (new QName (
            "http://http://www.comverse.com/msg", "testMessage"));
        bodyElement.addTextNode ("test message");
        // print SOAP-Message
        dumpSOAPMessage (msg);
      }
      else
      {
        // INBOUND
        System.out.println ("Direction=inbound (handleMessage)");
        SOAPMessage msg = ((SOAPMessageContext) context).getMessage ();
        dumpSOAPMessage (msg);
      }
    }
    catch (Exception e)
    {
      //All other unhandled problems.
      e.printStackTrace ();
    }
    return true;
  }
  /**
   * Handles SOAP-Errors.
   *
   * @param context
   * @return
   */
  public boolean handleFault (SOAPMessageContext context)
  {
    System.out.println ("ServerSOAPHandler.handleFault");
    boolean outbound = (Boolean) context
        .get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (outbound)
    {
      System.out.println ("Direction=outbound (handleFault)");
      SOAPMessage msg = ((SOAPMessageContext) context).getMessage ();
      // get SOAP-Part
      SOAPPart sp = msg.getSOAPPart ();
      //edit Envelope
      SOAPEnvelope env;
      try
      {
        env = sp.getEnvelope ();
        // add namespaces
        env.addNamespaceDeclaration ("xsd", "http://www.w3.org/2001/XMLSchema");
        env.addNamespaceDeclaration ("xsi",
            "http://www.w3.org/2001/XMLSchema-instance");
        env.addNamespaceDeclaration ("soap",
            "http://schemas.xmlsoap.org/soap/envelope");
        // get the SOAP-Body
        SOAPBody body = env.getBody ();
        Iterator iter1 = body.getChildElements ();
        while (iter1.hasNext ())
        {
          SOAPBodyElement bodyElement = (SOAPBodyElement) iter1.next ();
          Iterator iter2 = bodyElement.getChildElements ();
          while (iter2.hasNext ())
          {
            Object node = iter2.next ();
            correctElement (node);
          }
        }
      }
      catch (SOAPException e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace ();
      }
      // print SOAP-Message
      dumpSOAPMessage (msg);
    }
    else
    {
      System.out.println ("Direction=inbound (handleFault)");
    }
    SOAPMessage msg = ((SOAPMessageContext) context).getMessage ();
    dumpSOAPMessage (msg);
    if (!outbound)
    {
      try
      {
        if (context.getMessage ().getSOAPBody ().getFault () != null)
        {
          String detailName = null;
          try
          {
            detailName = context.getMessage ().getSOAPBody ().getFault ()
                .getDetail ().getFirstChild ().getLocalName ();
            System.out.println ("detailName=" + detailName);
          }
          catch (Exception e)
          {
          }
        }
      }
      catch (SOAPException e)
      {
        e.printStackTrace ();
      }
    }
    return true;
  }
  static Map<String, String> tagMap;
  {
    tagMap = new HashMap ();
    tagMap.put ("errorCode", "xsd:string");
    tagMap.put ("faultstring", "xsd:string");
    tagMap.put ("ns4:fault", "ns4:MyException");
  }
  private void correctElement (Object node)
  {
    System.out.println ("Node: " + node);
    SOAPElement child;
    try
    {
      child = (SOAPElement) node;
    }
    catch (Exception e)
    {
      return;
    }
    String tagName = child.getTagName ();
    if (tagMap.containsKey (tagName))
    {
      try
      {
        child.addAttribute (new QName (
            "http://www.w3.org/2001/XMLSchema-instance", "type", "xsi"),
            tagMap.get (tagName));
      }
      catch (SOAPException e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace ();
      }
    }
    Iterator iter = child.getChildElements ();
    while (iter.hasNext ())
    {
      node = iter.next ();
      correctElement (node);
    }
  }
  public void close (MessageContext messageContext)
  {
  }
  /**
   * Is executed before this handler is being destroyed -
   * means after close() has been executed.
   */
  @PreDestroy
  public void destroy ()
  {
  }
}

the exception class: MyException.java (ref: http://io.typepad.com/eben_hewitt_on_java/2009/07/using-soap-faults-and-exceptions-in-java-jaxws-web-services.html)

package helloservice.endpoint;
import java.io.Serializable;
import javax.xml.ws.WebFault;
@WebFault (name = "fault", targetNamespace = "http://myexceptions.test.com")
public class MyException extends Exception implements Serializable
{
  private static final long serialVersionUID = -4552704108896976212L;
  /**
   * Java type that goes as soapenv:Fault detail element.
   */
  private MyExceptionBean faultInfo;
  public MyException (String message, MyExceptionBean faultInfo)
  {
    super (message);
    this.faultInfo = faultInfo;
  }
  public MyException (String message, MyExceptionBean faultInfo, Throwable cause)
  {
    super (message, cause);
    this.faultInfo = faultInfo;
  }
  public MyExceptionBean getFaultInfo ()
  {
    return faultInfo;
  }
}


and the bean class: MyExceptionBean.java:



package helloservice.endpoint;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType (XmlAccessType.FIELD)
@XmlType (name = "MyException", propOrder =
{ "errorCode" })
public class MyExceptionBean
{
  private String errorCode = "654321";
  public String getErrorCode ()
  {
    return errorCode;
  }
  public void setErrorCode (String errorCode)
  {
    this.errorCode = errorCode;
  }
}

here is the pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>TestWS</groupId>
  <artifactId>testws</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxws-maven-plugin</artifactId>
        <version>1.10</version>
        <executions>
          <execution>
            <goals>
              <goal>wsgen</goal>
            </goals>
            <configuration>
              <sei>helloservice.endpoint.Hello</sei>
              <!--for demo purpose only, the webapp does not-->
              <!--need the generated wsdl files-->
              <genWsdl>true</genWsdl>
              <keep>true</keep>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <pluginRepositories>
    <pluginRepository>
      <id>maven2-repository.dev.java.net</id>
      <url>http://download.java.net/maven/2/</url>
    </pluginRepository>
  </pluginRepositories>
  <dependencies>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>6.0</version>
    </dependency>
    <dependency>
      <groupId>xalan</groupId>
      <artifactId>xalan</artifactId>
      <version>2.7.0</version>
    </dependency>
  </dependencies>
</project>