Sun Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

Extending the Java EE Unified Expression Language with a Custom ELResolver, and Configuring, Packaging, and Deploying JAX-WS Handlers

 
In This Issue

Welcome to the Enterprise Java Technologies Tech Tips for August 26, 2006. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

These tips were developed using the Java EE 5 SDK. You can download the SDK from the Java EE Downloads page.

You can download the sample archive for the tip Extending the Java EE Unified Expression Language with a Custom ELResolver.

You can download the sample archive for the tip Configuring, Packaging, and Deploying JAX-WS Handlers.

Any use of this code and/or information below is subject to the license terms.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Extending the Java EE Unified Expression Language with a Custom ELResolver

by Ed Burns

The Unified Expression Language (EL), new in Java EE 5, is a powerful and flexible way to tie together the tiers of a web application without sacrificing architectural integrity. Previous Enterprise Java Technologies Tech Tips, such as Using Enterprise Beans with JSP Pages covered an earlier version of the EL, one that was included in JavaServer Pages (JSP) 2.0 technology. Unfortunately, because of differences between the JSP and JavaServer Faces technology programming model, JavaServer Faces technology users could not take advantage of that version of the EL. A different version of the EL is available with JavaServer Faces technology 1.0 and 1.1. The new unified EL aligns the JSP and JavaServer Faces technology ELs. In other words the same unified EL can now be leveraged by both JSP and JavaServer Faces technology users.

This Tech Tip shows you how to extend the capabilities of the unified EL by providing a custom ELResolver. You'll see how the ELResolver differs from its previous implementation in JavaServer Faces technology as a combination of PropertyResolver and VariableResolver.

Portions of this tip are extracted from the book JavaServer Faces: The Complete Reference by Ed Burns and Chris Schalk.

A Unified EL Example

Here is an example of a Unified EL expression:

   #{sessionScope.inventory['1353465'].unitPrice}

This expression says, "look in the current HTTP session for an entry named inventory. Treat inventory as a Map and look for an entry under key 1353465. Within that entry, look for a JavaBeans property named unitPrice." What the system does with the unitPrice property depends on the usage context. In JavaServer Faces technology, values that a user enters into user interface components are propagated to server-side objects during a process called "postback". JavaBeans set methods set the value in the server-side objects. If the value of the property is requested, JavaBeans get methods get the value. So if the value of the unitPrice property is being posted back within a JavaServer Faces technology form, the pertinent JavaBeans set method is called with the submitted value. When rendering a JSP or JavaServer Faces technology page, the pertinent JavaBeans get method is called to extract the value.

Within the Java EE web tier, there is a small set of implicit objects that have specific meaning when used as the first part of an expression. In the example of the unified EL expression, sessionScope is an implicit object. The easiest way to extend the capabilities of the unified EL is to introduce a new implicit object by providing a custom ELResolver. For example, wouldn't it be nice if you could easily look up references in the Java Naming and Directory Interface (JNDI) system using the unified EL? As it happens, the Apache Shale Project has just such a feature (see Shale JNDI Integration). Unfortunately, this feature is implemented for Java Server Faces 1.1 technology, which does not use the unified EL.

Let's examine a custom ELResolver that can be used for the JNDI lookup. However, before doing that, here is some background on the VariableResolver and PropertyResolver classes and how they are used to evaluate a unified EL example expression.

VariableResolver and PropertyResolver

The JavaServer Faces technology 1.0 and 1.1 runtimes include default singleton instances of two classes: VariableResolver and PropertyResolver. These classes provide a mechanism for resolving EL expressions. In JavaServer Faces technology 1.2, these two classes have been deprecated with the introduction of the javax.el.ELResolver class in the unified EL.

The following example illustrates the central role that VariableResolver and PropertyResolver play in JavaServer Faces technology. In this example, assume that the JavaServer Faces technology runtime maintains a reference to the VariableResolver and PropertyResolver classes using the variables myVariableResolver and myPropertyResolver, respectively. The VariableResolver class has one method resolveVariable(). The PropertyResolver class has a number of methods such as getValue(). For this example, assume a simplified version of the signatures for the resolveVariable() and getValue() methods. With those assumptions, consider the following JavaServer Faces technology EL expression:

   #{requestScope.user.firstName}

To resolve this expression and get its value, the EL implementation in JavaServer Faces technology 1.0 and 1.1 breaks down the expression into two parts: requestScope and user.firstName. The JavaServer Faces technology runtime calls myVariableResolver.resolveVariable("requestScope"). This method takes the argument string and resolves it. Here, requestScope is one of the implicit objects that have specific meaning when used as the first part of an expression. It represents a Map of request scope variables, keyed by name, that enables access to the attributes of the request scope object. (You can find out more about these implicit objects in Chapter 4, Table 7 of JavaServer Faces: The Complete Reference.) The VariableResolver instance must return a java.util.Map implementation that wraps the attribute set for the current javax.servlet.ServletRequest. Let's call the Map implementation requestMap.

With requestScope successfully resolved to requestMap, the JavaServer Faces technology runtime further breaks down the user.firstName part of the expression into its individual parts: user, and firstName. The runtime then calls myPropertyResolver.getValue(requestMap, "user"). This method looks in the Map for a value under the key user and returns it. Assume the requestMap has such a value under the key user and this value is an instance of UserBean.

The last step in the evaluation of the expression happens when myPropertyResolver.getValue(userBean, "firstName") is called. Because UserBean is a plain old JavaBean, the PropertyResolver looks for a JavaBeans property with the name firstName, which it finds. It then invokes the getFirstName() method, which returns the first name of the user.

Notice how the expression is continually broken down into parts, with the result of evaluating step n being fed into the evaluation of step n + 1.

Extending ELResolver

Now let's return to the custom ELResolver. A sample package accompanies this tip that demonstrates the custom ELResolver. The source code for the custom ELResolver is included in the package.

The first thing to know is that a custom ELResolver must extend the abstract class javax.el.ELResolver and provide a public no-argument constructor:

   public class JNDIELResolver extends javax.el.ELResolver {
       /**
       * 

   Construct a new {@link JNDIELResolver} instance.

       *
       */
      public JNDIELResolver() {
      }

The no-argument constructor is necessary because the system instantiates the ELResolver instance during application start up based on the fully qualified class name that is specified in the <el-resolver> element of the faces-config.xml file. More on that later.

The core run-time behavior of an ELResolver is specified in three methods: getValue(), setValue(), and getType(). The design-time behavior is specified in the remaining three methods: getFeatureDescriptors(), getCommonPropertyType() and isReadOnly(). Let's look at the run-time behavior first.

In Java EE 5, VariableResolver and PropertyResolver have been deprecated. However the classes are still supported for backwards compatibility. Also, in Java EE 5, PropertyResolver and VariableResolver have been merged into the unified EL class javax.el.ELResolver. Basically, an ELResolver functions as a VariableResolver if the first argument to its getValue() or setValue() method is null. Otherwise, it functions as a PropertyResolver.

Looking further at the custom ELResolver code:

   /**
    * Resolve variable names known to this resolver; 
    * otherwise, delegate to the ELResolver chain.
    *
    * @param name Variable name to be resolved
    */
   public Object getValue(ELContext elContext, Object base,
           Object property) {
       Object result = null;
       // If we have a non-null base object, 
       // function as a PropertyResolver
       if (null != base) {
           if (base instanceof Context) {
               elContext.setPropertyResolved(true);
               Context context = (Context) base;
               try {
                   if (property instanceof Name) {
                       result = context.lookup((Name) property);
                   } else {
                       if (null != property) {
                           result = context.lookup(
                               property.toString());
                       }
                   }
               } catch (NameNotFoundException e) {
               // Mimic standard JSF/JSP behavior 
               // when base is a Map by returning null
                   return null;
               } catch (NamingException e) {
                   throw new ELException(e);
               }
           }
       }
       else {
           // function as a VariableResolver
           if (null == property) {
               throw new PropertyNotFoundException(
                       "JNDIELResolver: name must " +
                       "not be null");
           }
           if (JNDI_VARIABLE_NAME.equals(property)) {
               elContext.setPropertyResolved(true);
               try {
                   InitialContext ic = new InitialContext();
                   result = (Context) ic.lookup(
                       "java:comp/env");
               } catch (NamingException e) {
                   throw new ELException(e);
               }
           }
       }
       return result;
   }

Pay special attention to the getValue() method. It is the most often called method on ELResolver. Because the JNDIELResolver simply adds JNDI capabilities to the EL, a null base argument means that it must look at the value of the property argument. If the property argument is equal to the string "jndi", JNDIELResolver sets the ELResolvers propertyResolved property to true, consults the InitialContext from JNDI, obtains its java:comp/env Context value, and returns it. A non-null base argument must be of type javax.naming.Context. In this case, JNDIELResolver sets the propertyResolved property to true, calls the lookup() method on the Context, and returns the value.

Next is the getType() method:

   public Class<?> getType(ELContext elContext, Object base,
           Object property) {
       if (null != base && base instanceof Context) {
           elContext.setPropertyResolved(true);
           return Object.class;
       }
       return null;

The getType() method is called by the implementation to determine if a subsequent call to setValue() is safe to call without causing a ClassCastException to be thrown. In this case, if the base is an instance of javax.naming.Context then any Object may be passed as the value.

The next method is setValue():

   public void setValue(ELContext elContext, Object base,
           Object property,
           Object value) {
       if (null != base && base instanceof Context) {
           Context context = (Context) base;
           elContext.setPropertyResolved(true);
           try {
               // Mimic standard JSF/JSP behavior when base is a Map
               // by calling rebind() instead of bind()
               if (property instanceof Name) {
                   context.rebind((Name) property, value);
               } else {
                   context.rebind(property.toString(), value);
               }
           } catch (NamingException e) {
               throw new ELException(e);
           }
       }
   }

The setValue() method is used to enable expressions to be assigned values, as in the "left-hand-side" of a programming language assignment statement, such as var foo = "bar";. In this case, it is only valid to set a value in an existing Context instance. So the rebind() method is called to set the value.

The remaining three methods: getFeatureDescriptors(), getCommonPropertyType() and isReadOnly() are present in the example code, but discussion of these methods is beyond the scope of this Tech Tip. A complete discussion is present in "JavaServer Faces: The Complete Reference". For now, it is sufficient to know that these methods are intended to allow ELResolvers to inform design time environments, such as IDEs, of their capabilities.

Declaring Your ELResolver

To make your ELResolver visible to the Java EE runtime, you must declare it in an application configuration resource file. The Java EE runtime follows a specified set of rules to discover and load application configuration resource files. However, this Tech Tip simply uses WEB-INF/faces-config.xml as the location. (For complete coverage of the rules for loading application configuration resource files, see "JavaServer Faces: The Complete Reference".) Simply place the following element within the <application> element of your faces-config.xml file:

   <el-resolver>
   com.sun.faces.extensions.jndi.JNDIELResolver
   </el-resolver>

Running the Sample Code

The runtime environment for this example is the Java EE 5 SDK, which you can download from the Java EE Downloads page. The example code is packaged as a NetBeans 5.5 Beta 2 Web Application project. You can open the project and run it in NetBeans 5.5 Beta 2.

You can also run the example from the command line, as follows:

  1. If you haven't already done so, download the Java EE 5 SDK and install it. Make sure to add the SDK's bin directory to your path.

  2. Download the sample package and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ttaug2006CustomELResolver, where <sample_install_dir> is the directory in which you installed the sample package. The CustomELResolver directory below ttaug2006CustomELResolver contains the source files and other support files for the sample.

  3. Change to the CustomELResolver directory and edit the build-cli.xml file. Change the javaee.home property as appropriate.

  4. Execute the following command:
          asant -f build-cli.xml 
    
    This will build the exploded and non-exploded war for the sample application in the dist directory.

  5. Start the Application Server:
          $JAVAEE_HOME/bin/asadmin start-domain domain1   
    
  6. Deploy the sample application. You can do this in various ways such as through the Application Server Administration Console or by copying the CustomELResolver.war file to the Application Server autodeploy directory.

  7. Start the application. Open your browser to http://<host>:8080/CustomELResolver/, replacing <host> with your host name (for instance, localhost). You should see the home page of the application.



  8. Click the JavaServer Faces Welcome Page link. You'll see a table containing three JNDI lookups via the Unified EL.

Here is the JSP source for the table:

 
   <h:panelGrid border="1" columns="2">
     JNDI Entry One <h:outputText value="#{jndi.TestEntryOne}" />
     JNDI Entry Two <h:outputText value="#{jndi.TestEntryTwo}" />
     JNDI Entry Three 
      <h:outputText value="#{jndi.TestEntryThree}" />
   </h:panelGrid>

The following JNDI entries are declared in the web.xml file for the application:

   <env-entry>
     <description>Look this up from JNDI</description>
     <env-entry-name>TestEntryOne</env-entry-name>
     <env-entry-type>java.lang.String</env-entry-type>
     <env-entry-value>Test Entry One</env-entry-value>
   </env-entry>
   <env-entry>
     <description>Look this up via JNDI</description>
     <env-entry-name>TestEntryTwo</env-entry-name>
     <env-entry-type>java.lang.Float</env-entry-type>
     <env-entry-value>3.1415</env-entry-value>
   </env-entry>
   <env-entry>
     <description>Look this up via JNDI.</description>
     <env-entry-name>TestEntryThree</env-entry-name>
     <env-entry-type>java.lang.String</env-entry-type>
     <env-entry-value>The Third and Final Environment Entry
     </env-entry-value>
    </env-entry>

Summary

This Tech Tip showed how to extend the unified EL with a simple class consisting of six methods, only three of which are really necessary for run-time behavior. For more information on extending the unified EL see the book JavaServer Faces: The Complete Reference by Ed Burns and Chris Schalk.

About the Author

Ed Burns is a senior staff engineer at Sun Microsystems. He has worked on a wide variety of client and server-side web technologies since 1994, including NCSA Mosaic, Mozilla, the Sun Java Plugin, Jakarta Tomcat and, most recently JavaServer Faces technology. Ed is currently the co-spec lead for JavaServer Faces 1.2 technology.

Configuring, Packaging, and Deploying JAX-WS Handlers

by Rama Pulavarthi

The June 24, 2006 Tech Tip, Writing a Handler in JAX-WS introduced JAX-WS handlers and how they can be used to pre-process or post-process messages exchanged between a server and client. This Tech Tip covers how to configure, package, and deploy handlers for a web service. This tip will be followed next month by a tip that shows different ways to configure handlers on a web service client.

JAX-WS provides a plug-in framework for handlers. It also defines the life cycle of handlers and the way handlers interact with the client and server. JAX-WS does not define a standard deployment model for handlers. Instead, the deployment metadata used to configure handlers on the server is defined by JSR-109: Implementing Enterprise Web Services.

Handler Chains

Handlers are configured according to an ordered list of handlers known as a handler chain. The syntax of a handler chain is defined by JSR-109. Within the handler chain, handlers that are applicable to a port component (that is, a particular port associated with a service) are selected to form a chain. The selected handlers are then executed in an orderly way. Logical handlers are executed before SOAP handlers, maintaining the original order in the chain. The schema for the handler chain is defined in a Java EE web services deployment descriptor (http://java.sun.com/xml/ns/javaee/javaee_web_services_1_2.xsd).

Here's an example of a simple handler chain:

   <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
     <handler-chain>
        <handler>
          <handler-name>SOAPLogicalLoggingHandler</handler-name>
          <handler-class>handlers.common.SOAPLoggingHandler
          </handler-class>
        </handler>
        <handler>
          <handler-name>LogicalLoggingHandler</handler-name>
          <handler-class>handlers.common.LogicalLoggingHandler
          </handler-class>
        </handler>
     </handler-chain>
   </handler-chains>

A handler chain configuration can be applied to any port or service. For example, you might have multiple services specified in a WSDL file and multiple ports in a service with different protocol bindings. You can apply the handler chain to any or all of the services and ports. However, you can selectively apply a handler configuration to specific ports by placing a constraint on the <handler-chain> element. You specify these constraints in <service-name-pattern>, <port-name-pattern>, or <protocol-bindings> elements, which specify whether the handlers in the handler chain apply to a service, port, or protocol binding, respectively. If none of these elements are specified within the <handler-chain element>, the handlers specified in the <handler-chain> are applied to everything.

Let's look at these constraints:

<service-name-pattern>

Use this element to apply handlers to specific services. You do this by specifying a Java EE qname-pattern in the element. Handlers identified in the associated <handler-chain> element are then applied to ports that match the qname-pattern. The qname-pattern can be an exact name or include wild cards. Here's an example that specifies a qname-pattern that's an exact name:

   <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
     <handler-chain>
       <service-name-pattern 
           xmlns:ns1="http://example.com/handlers">
           ns1:HelloService
       </service-name-pattern>
     <handler/>
     <handler/>
    </handler-chain>
   </handler-chains>

As a result of the exact name specification, handlers specified in the <handler-chain> element apply to all ports with the service name HelloService. You must declare the namespace prefix in a namespace declaration attribute in either the start tag of the element where the prefix is used or in an ancestor element (in effect, an element in whose content the prefixed markup occurs).

Here's an example of a <service-name-pattern> element that specifies a wild card pattern:

   <service-name-pattern 
       xmlns:ns1="http://example.com/handlers">
       ns1:HelloService*
   <service-name-pattern>

Here, handlers specified in the associated <handler-chain> element apply to all ports whose service names begin with HelloService, for example, HelloService1 or HelloServiceFoo.

Here's another wild card pattern:

   <service-name-pattern>*<service-name-pattern>

Handlers specified in the associated <handler-chain> element apply to ports of all service names. This is equivalent to not specifying any constraint on the <handler-chain> element.

<port-name-pattern>

Use this element to apply handlers to a specific port. For example:

   <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
    <handler-chain>
      <port-name-pattern xmlns:ns1="http://example.com/handlers">
          ns1:Hello*
      </port-name-pattern>
      <handler/>
      <handler/>
    </handler-chain>
   </handler-chains>

Here, handlers specified in the associated <handler-chain> element apply to all ports whose names begin with Hello.

<protocol-bindings>

Use this element to apply handlers to a specific set of protocol bindings. The handlers specified in the associated <handler-chain> are applied if the list contains the protocol binding of the port. In addition to specifying the URI of the protocol binding, you can specify tokens that are aliases of the standard binding types. The URIs for these pre-defined tokens are as follows:

##SOAP11_HTTP - "http://schemas.xmlsoap.org/wsdl/soap/http"
##SOAP11_HTTP_MTOM - "http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true"
##SOAP12_HTTP - "http://www.w3.org/2003/05/soap/bindings/HTTP/"
##SOAP12_HTTP_MTOM - "http://www.w3.org/2003/05/soap/bindings/HTTP/?mtom=true"
##XML_HTTP - "http://www.w3.org/2004/08/wsdl/http"

In the following example, the <protocol-bindings> element specifies that the handlers in the handler-chain are applicable if the protocol binding of the port is SOAP 1.1 or SOAP1.1 with Mtom:

   <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
     <handler-chain>
       <protocol-bindings>##SOAP11_HTTP 
           http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true
       </protocol-bindings>
       <handler/>
       <handler/>
     </handler-chain>
   </handler-chains>

Configuring Handlers in a Handler Chain

You can configure handlers in a handler chain either by using the annotation @javax.jws.HandlerChain or through JAX-WS customization.

Configuring Handlers Using the HandlerChain Annotation

JSR-181: Web Services Metadata for the Java Platform defines an annotation, @javax.jws.HandlerChain, that can be used with JAX-WS code to specify handler chains associated with a port component or service. The annotation can be declared on web service endpoints (declared with @javax.jws.WebService or @javax.xml.ws.WebServiceProvider annotations) or on web service references (declared with @javax.xml.ws.WebServiceRef) annotations. You specify the @javax.jws.HandlerChain annotation with the location of the handler chain file. The location can be an absolute URL, such as http://example.com/handlers/handlerfile1.xml, or a relative path to the source file or class file, such as bar/handlerfile1.xml.

Here's an example that uses the @javax.jws.HandlerChain annotation to associate a handler chain with a web service endpoint:

   @javax.jws.HandlerChain(file="Hello1_handler.xml")
   @javax.jws.WebService(serviceName="HelloService1", 
       targetNamespace="http://example.com/handlers")
    public class Hello1 {    
        public String sayHello(String param) {
        // implement the web service operation here
        return "Hello " + param + "!";
    }    
   }

Configuring Handlers Through JAX-WS Customization

In this approach you specify <handler-chains> elements within a <jaxws:bindings> element of a JAX-WS customization file. You use the customization file to import a WSDL file using the wsimport tool.

Here is an example of a customization file that can be used for handler configuration:

   <bindings xmlns="http://java.sun.com/xml/ns/jaxws" 
       wsdlLocation=
       "http://example.com/handler_config/Hello1?wsdl">
    <handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
      <handler-chain>
        <handler>
          <handler-class>
              example.handlers.MyHandler</handler-class>
        </handler>
      </handler-chain>
    </handler-chains>
   </bindings>

The wsimport tool generates a service endpoint interface (SEI) and a service class with the @HandlerChain annotation.

Note that if the @HandlerChain annotation is specified on the SEI (whether you specified it there or it was generated by wsimport) and on an endpoint implementation, the annotation declared on the endpoint implementation takes precedence.

Specifying Handlers in a Deployment Descriptor

You can also specify handlers in a deployment descriptor using <handler-chains> elements. The deployment descriptor on a port component or service reference overrides the @HandlerChain annotation specified in the implementation. The following example shows how handlers are specified in a Java EE deployment descriptor for a web service:

   <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>HelloService2
        </webservice-description-name>
        <wsdl-file>WEB-INF/wsdl/HelloService2.wsdl
        </wsdl-file>
        <port-component>
          <port-component-name>Hello2</port-component-name>
          <service-endpoint-interface>service2.HelloIF
          </service-endpoint-interface>
          <service-impl-bean>
            <servlet-link>Hello2</servlet-link>
          </service-impl-bean>
          <handler-chains>
            <handler-chain>
              <handler>
                <handler-name>SOAPLoggingHandler</handler-name>
                <handler-class>handlers.common.SOAPLoggingHandler
                </handler-class>
              </handler>
            </handler-chain>

            <handler-chain>
            <protocol-bindings>##SOAP12_HTTP
            </protocol-bindings>
              <handler>
                <handler-name>SOAP12Handler</handler-name>
                <handler-class>service2.handlers.SOAP12Handler
                </handler-class>
              </handler>
            </handler-chain>
          </handler-chains>
       </webservice-description>
   
     </webservices>

You might wonder, what if you specify handlers in all three ways: deployment descriptor, @HandlerChain annotation on an endpoint implementation, and @HandlerChain annotation on an SEI? The answer is that on the server, handlers are picked up in the following order of precedence: (1) deployment descriptor, (2) @HandlerChain annotation on an endpoint implementation, and (3) @HandlerChain annotation on an SEI.

Packaging and Deploying Handlers

You need to package, either by containment or reference, the handler class and its dependent classes in one module with the deployment descriptor information that references the handler classes. As discussed earlier, you can specify handlers in a deployment descriptor or through @HandlerChain annotations. If you use a @HandlerChain annotation, the handler chain file identified in the annotation needs to be packaged in the same module -- this makes it accessible as a resource in the class path. In other words, when you package the service, the handlers.xml file must be in the class path with the WAR file, either directly under WEB-INF/classes or further down the path in the same package as the service class file.

Summary

Defining handlers for Java EE web services is not difficult. It simply involves configuring handlers using a @HandlerChain annotation or through JAX-WS customization. Developer tools such as NetBeans 5.5 can make configuring handlers even easier, allowing you to simply pick and click the handlers you want.

Running the Sample Code

You can run the sample code for this tip as follows:

  1. If you haven't already done so, download the Java EE 5 SDK from the Java EE Downloads Page, and install it.

  2. Set the following environment variables:

    • JAVAEE_HOME. This should point to where you installed the Java EE 5 SDK.
    • ANT_HOME. This should point to where ant is installed. Ant is included in the Java EE 5 SDK bundle that you downloaded. (In Windows, it's in the lib\ant subdirectory.)
    • JAVA_HOME. This should point to the location of JDK 5.0 on your system. JDK is included in the Java EE 5 SDK bundle that you downloaded. (In Windows, it's in the jdk subdirectory.)

    Add $JAVA_HOME/bin, $ANT_HOME/bin, and $JAVAEE_HOME/bin to your PATH environment variable.

  3. Download the sample package and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/handler_config, where <sample_install_dir> is the directory in which you installed the sample package.

  4. Change to the handler_config directory and edit the build.properties file as appropriate. For example, if the admin host is remote, change the value of admin.host from the default (localhost) to the appropriate remote host. Also, make sure that the javaee.server.passwordfile location is correct, and modify the wsdlLocation in the config-client.xml file, if the host or port is changed.

  5. Start the Application Server by entering the following commmand:

    $JAVAEE_HOME/bin/asadmin start-domain domain1

  6. Build and deploy the sample service and webclient. From the handler_config directory enter the following command:

    ant deploy

    This builds the web service, creates a handler_config.war file, and deploys the .war file. It also creates a web client and deploys the wsclient.war file.

  7. Build the client and run the sample. From the handler_config directory enter the following command:

    ant run

    This generates the client artifacts by calling wsimport, and runs the sample. (Next month's tip will explain how to configure handlers on a web service client.)

    The sample includes five handler-related tests:

    • test1 uses handlers that are configured on a proxy using JAX-WS WSDL customization.
    • test2 uses a HandlerResolver to set handlers on a service.
    • test3 uses handlers with a Dispatch client.
    • test4 uses handlers that are set for a particular port.
    • test5 invokes a WebClient(servlet), which demonstrates the use of @HandlerChain on Web Service reference.

    Here is the output displayed by the test1 part of the sample:
      
       [java] ************ Start:test1 *************
       [java] Executing LogicalLoggingHandler
       
       [java] Outbound message:
       [java] <ns2:sayHello xmlns:ns2="http://example.com/handlers">
       [java] <arg0>Duke</arg0>
       [java] </ns2:sayHello>
       [java] Executing SOAPLoggingHandler
       
       [java] Outbound message:
       [java] <?xml version="1.0" ?><soapenv:Envelope xmlns:soapenv=
       "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http:/
       /www.w3.org/2001/XMLSchema" xmlns "http://example.com/handler
       s"><soapenv:Body><ns2:sayHello xmlns:ns2="http:/example.com/h
       andlers"><arg0>Duke</arg0></ns2:sayHello></soapenv:Body></soa
       p:Envlope>
       [java] Executing SOAP11Handler
       [java] Executing SOAP11Handler
       [java] Verifying Inbound message
       [java] Executing SOAPLoggingHandler
       
       [java] Inbound message:
       [java] <?xml version="1.0" ?><soapenv:Envelope xmlns:soapenv=
       "http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http:/
       /example.com/handlers" xmlns:xsd="http://www.w3.org/2001/XMLS
       chema"><soapenv:Body><ns1:sayHelloResponse><return>Hello  Duk
       e!</return></ns1:sayHelloResponse></soapenv:Body></soapenv:En
       velope>
       [java] Executing LogicalLoggingHandler
       
       [java] Inbound message:
       [java] <ns1:sayHelloResponse xmlns:ns1="http://example.com/ha
       ndlers">
       [java] <return>Hello Duke!</return>
       [java] </ns1:sayHelloResponse>
    
       [java] Result = Hello Duke!
    [java] ************ End:test1 ***************   
    

About the Author

Rama Pulavarthi is a Member of Technical Staff in the Java Web Services group at Sun Microsystems. He currently works on the development of the JAX-WS Reference Implementation. He previously led the Software Quality Engineering effort for JAX-RPC.