JAX-WS 2.1 Support for WS-Addressing in WebSphere Application Server V7

IBM WebSphere Application Server V7 includes support for the Java API for XML-Based Web Services (JAX-WS) 2.1 specification. JAX-WS 2.1 is a maintenance release of Java Specification Request (JSR) 224 that extends the functionality provided by the JAX-WS 2.0 specification with new capabilities. The most significant new capability is support for Web Services Addressing (WS-Addressing) in the Application Programming Interface (API). In this article we learn how to use this new WS-Addressing support, and we see how it makes it easier for web service developers to write stateful web services.

Brian T. De Pradine, Staff Software Engineer, IBM

Brian DePradine is a Developer working for IBM Software Group in Hursley, England. He has worked at IBM for 11 years. For the past seven of those years, he has worked in WebSphere Application Server development, specifically in the areas of messaging and web services support. He has a Bachelor of Science degree in Applied Physics from Columbia University, and a Master of Science in Software Engineering from Oxford University.



Katherine Sanders, Software Engineer, IBM

Katherine Sanders is a software engineer at IBM Hursley Park in the United Kingdom. She develops and tests Web service functionality in WebSphere Application Server, with a particular focus on WS-Addressing, WS-ReliableMessaging and WS-Notification. She holds a Bachelor of Science degree in Computer Science from the University of Nottingham.



12 January 2010

Also available in Chinese Russian Japanese Portuguese

Introduction

Java™ API for XML-Based Web Services (JAX-WS) is the successor to the previous standard Java API for XML based RPC (JAX-RPC). JAX-RPC 1.0 and JAX-RPC 1.1 defined an API and conventions for supporting a Remote Procedure Call (RPC) style of Web service invocation. Since that time, however, Web services have moved towards a more document oriented style. JAX-WS 2.0 provided a completely different Application Programming Interface (API) and conventions for supporting this newer style of web services interactions. There was also a strong emphasis on simplifying the developer experience when writing Web service applications. See the Resources section for links to articles that cover the difference between JAX-WS and JAX-RPC in more detail.

JAX-WS 2.1 carries on the trend towards simplification, started in JAX-WS 2.0, by making it easier for developers to write stateful Web services. This is achieved by adding explicit support for Web Services Addressing (WS-Addressing) to the JAX-WS API. In this article, we will present an example application that shows how to use these new APIs to write a stateful Web service, but first we will examine these new WS-Addressing related APIs in detail.

Before we do that, however, we should point out that the JAX-WS 2.1 specification only provides support for the WS-Addressing 1.0 Core and Simple Object Access Protocol (SOAP) Binding specifications. If support for a different version of the WS-Addressing specifications is required then the JAX-WS 2.1 specification also provides the ability for vendors to extend the API. In IBM® WebSphere® Application Server V7, we exploit this capability in order to support the older WS-Addressing Member Submission specification (see Resources). Those extensions will also be covered in this article.


Endpoint references

The JAX-WS 2.1 specification introduces the concept of an endpoint reference. An endpoint reference encapsulates all of the details that are necessary in order to successfully target a Web service endpoint. The API introduces a new class, EndpointReference, in order to represent endpoint references. This class is not meant to be used directly by developers, however, as one of its subclasses should be used instead.

The JAX-WS 2.1 API includes one subclass of EndpointReference, called W3CEndpointReference. It is meant to represent endpoint references in accordance with the WS-Addressing 1.0 Core specification. In WebSphere Application Server V7, we provide a second subclass, SubmissionEndpointReference, to represent endpoint references in accordance with the WS-Addressing Member Submission specification. The relationship between these classes is shown in Figure 1.

Figure 1. Endpoint relationship
Endpoint relationship

The JAX-WS 2.1 specification also defines a number of ways to create endpoint references in your applications. The code snippet in Listing 1 shows one way of doing this, using the W3CEndpointReferenceBuilder class. In the examples that follow we omit some details for clarity, but see the application at the end for a complete example.

Listing 1. JAX-WS 2.1 example
import org.w3c.dom.Element;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;

String address = ...
Element referenceParameter = ...

W3CEndpointReferenceBuilder builder =
    new W3CEndpointReferenceBuilder();
builder.address(address);
builder.referenceParameter(referenceParameter);
W3CEndpointReference epr = builder.build();

The W3CEndpointReferenceBuilder allows the developer the ability to specify any of the properties of an endpoint reference. In Listing 1, we just specify an address and a reference parameter, however, it is possible to specify a Web Services Description Language (WSDL) service name and endpoint (port) name, instead of an address. The run time will use the service and endpoint name combination to identify the endpoint for which a reference is required, and it will return a W3CEndpointReference with the correct address filled in.

If a SubmissionEndpointReference is required instead of a W3CEndpointReference then, in WebSphere Application Server V7, the SubmissionEndpointReferenceBuilder class can be used. This is shown in the code snippet in Listing 2.

Listing 2. SubmissionEndpointReference
import org.w3c.dom.Element;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReferenceBuilder;

String address = ...
Element referenceParameter = ...

SubmissionEndpointReferenceBuilder builder =
    new SubmissionEndpointReferenceBuilder();
builder.address(address);
builder.referenceParameter(referenceParameter);
SubmissionEndpointReference epr = builder.build();

If the service and endpoint name combination is used, the W3CEndpointReferenceBuilder and SubmissionEndpointReferenceBuilder classes can be used to create an endpoint reference for any endpoint deployed in the same Java Platform, Enterprise Edition (Java EE) application. This means that if the endpoint is not in the same application then the address must be explicitly specified. If all that is required by an endpoint, however, is a reference to itself then JAX-WS 2.1 provides a simpler alternative to using a builder. The WebServiceContext class has been extended to support creating of an endpoint reference. This is shown in Listing 3.

Listing 3. WebServiceContext class
import org.w3c.dom.Element;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

@Resource
private WebServiceContext context;

Element referenceParameter = ...

W3CEndpointReference w3cEPR =
    (W3CEndpointReference) context.getEndpointReference(referenceParameter);

Creating endpoint references in a cluster

If an application is deployed to a cluster, any endpoint references created using either the builders or the WebServiceContext will not have any support for affinity to a particular server or endpoint. Simple workload-management will still be possible, however, as any requests made using that endpoint reference, via a proxy, will be distributed to the members of the cluster in a round-robin manner.

When using the WebServiceContext the only property that can be specified explicitly is a reference parameter. The address element is filled in by the run time, along with all of the other properties. If a SubmissionEndpointReference is required instead then, in WebSphere Application Server V7, the extension mechanism provided by JAX-WS 2.1 can be used. This is shown in code snippet in Listing 4.

Listing 4. SubmissionEndpointReference
import org.w3c.dom.Element;
import javax.xml.ws.WebServiceContext;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

@Resource
private WebServiceContext context;

Element referenceParameter = ...

SubmissionEndpointReference epr =
    context.getEndpointReference(SubmissionEndpointReference.class, referenceParameter);

Endpoint references created in an application can be returned, over the wire, to a client. The client can then use that endpoint reference to invoke the endpoint, as necessary. Any reference parameters included in the endpoint reference will be automatically be added as headers to the SOAP envelope that is sent, as per the WS-Addressing specifications. JAX-WS 2.1 also provides a facility to allow a Web service application to retrieve these reference parameters. This is shown in Listing 5.

Listing 5. Retrieving reference parameter
import org.w3c.dom.Element;    
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

@Resource
private WebServiceContext context;

List<Element> list =
   (List<Element>) context.getMessageContext().get(MessageContext.REFERENCE_PARAMETERS);

This list can then be perused in order to find the reference parameters. If the application is written to comply with the WS-Addressing Member Submission specification, however, then this mechanism cannot be used to retrieve them. Instead, the EndpointReferenceManager class, which is a part of the proprietary WS-Addressing API provided by WebSphere Application Server V7, must be used. This is shown in Listing 6. In this case, the name of the reference parameter must be provided in order to retrieve it.

Listing 6. EndpointReferenceManager
import javax.xml.namespace.QName;
import com.ibm.websphere.wsaddressing.EndpointReferenceManager;

QName name = ...
String refParam =
    EndpointReferenceManager.getReferenceParameterFromMessageContext(name);

Features

JAX-WS 2.1 also introduces the concept of features. A feature is a mechanism to allow a client developer to programmatically control a specific behavior of the client. All features are derived from the class WebServiceFeature. This allows the client developer to pass different types of WebServiceFeature to the client-side APIs that require them. The WS-Addressing related features are shown in Figure 2.

Figure 2. WS-Addressing Features
WS-Addressing Features

The AddressingFeature is used to control the use of WS-Addressing. It allows a developer to enable/disable the use of WS-Addressing by the client. If it is enabled then the client will include WS-Addressing headers in the SOAP messages that it sends. These headers will be in the WS-Addressing 1.0 Core specification namespace, http://www.w3.org/2005/08/addressing. If it is disabled, then no WS-Addressing headers will be sent.

In WebSphere Application Server V7, we also provide a SubmissionAddressingFeature class. This class works in the same way as the AddressingFeature except that if it is enabled then any WS-Addressing headers sent by the client will be in the WS-Addressing Member Submission specification namespace, http://schemas.xmlsoap.org/ws/2004/08/addressing. In WebSphere Application Server V7, other mechanisms are available to enable WS-Addressing support in the client, but they are outside the scope of this article. See the Resources section for links to further information on these alternatives.


Annotations

JAX-WS 2.1 makes heavy use of annotations in order to simplify server-side application development. The @Addressing annotation is the server-side equivalent of the AddressingFeature. It is used to enable/disable WS-Addressing for a web services endpoint. If WS-Addressing is enabled then the run time will process any WS-Addressing headers, in the http://www.w3.org/2005/08/addressing namespace, found in inbound requests. In addition, any response messages will also have WS-Addressing headers added to them, if appropriate. If WS-Addressing is disabled then any WS-Addressing headers in inbound requests will be ignored.

The @Addressing annotation also supports a property called, required. If this property is set to true then any incoming messages to the web service must include WS-Addressing headers, otherwise a fault will be returned to the client. The required property is also present on the AddressingFeature, but it is ignored by the client in accordance with the JAX-WS 2.1 specification. In WebSphere Application Server V7, we also provide a @SubmissionAddressing annotation. It works in the same manner as @Addressing except that it relates to WS-Addressing headers in the http://schemas.xmlsoap.org/ws/2004/08/addressing namespace. These classes are shown in Figure 3.

Figure 3. Addressing class
Addressing class

JAX-WS 2.1 also introduces new annotations to support the mapping of WS-Addressing actions to WSDL operations. These annotations are: @Action and @FaultAction. The @Action annotation allows an action to be explicitly associated with the input, and output of a WSDL operation. The @FaultAction annotation is used inside of an @Action annotation to associate each fault with an action. These classes are shown in Figure 4. The @Addressing annotation is required in order to use the @Action and @FaultAction annotations, otherwise they are ignored.

Figure 4. Fault and Action classes
Fault and Action classes

Application

Now that we have completed our brief introduction to the new WS-Addressing related concepts introduced in JAX-WS 2.1, we can bring them all together into a useful application. In the Calculator application presented below, a client makes a request to a web service that adds two numbers together and returns the result. Before the client can do that, however, it must first retrieve a ticket from the web service before it will be allowed to send a request to add the two numbers together. The ticket is sent to the client as a reference parameter inside of an endpoint reference. The client can then use that endpoint reference to send the request to add the two numbers.

The Calculator application is also available to download. The application is available as an .ear file that can either be imported into IBM Rational® Application Developer V7.5.1 or installed on WebSphere Application Server V7. In order to compile cleanly in Rational Application Developer, the com.ibm.jaxws.thinclient_7.0.0.jar must be added to the classpath of the CalculatorClient and CalculatorService projects that are created. This jar can be found in the runtimes directory of your WebSphere Application Server installation.

Let's start by looking at the WSDL for our Calculator service. The WSDL is presented in Listing 7. In it you will see that we have four operations: getTicket, add, getSubmissionTicket and addSubmission. The getTicket operation returns an endpoint reference which will contain our ticket as a reference parameter. The add operation allows us to add our two numbers together. The other two operations perform the same functions, but using the WS-Addressing Member Submission specification instead of the WS-Addressing 1.0 Core specification.

Listing 7. Calculator.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions targetNamespace="http://calculator.jaxws.developerworks"
             name="Calculator"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:tns="http://calculator.jaxws.developerworks"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://calculator.jaxws.developerworks"
                        schemaLocation="Calculator_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="getTicket">
        <part name="parameters" element="tns:getTicket"/>
    </message>
    <message name="getTicketResponse">
        <part name="parameters" element="tns:getTicketResponse"/>
    </message>
    <message name="add">
        <part name="parameters" element="tns:add"/>
    </message>
    <message name="addResponse">
        <part name="parameters" element="tns:addResponse"/>
    </message>
    <message name="getSubmissionTicket">
        <part name="parameters" element="tns:getSubmissionTicket"/>
    </message>
    <message name="getSubmissionTicketResponse">
        <part name="parameters" element="tns:getSubmissionTicketResponse"/>
    </message>
    <message name="addSubmission">
        <part name="parameters" element="tns:addSubmission"/>
    </message>
    <message name="addSubmissionResponse">
        <part name="parameters" element="tns:addSubmissionResponse"/>
    </message>
    <message name="AddNumbersException">
        <part name="fault" element="tns:AddNumbersException"/>
    </message>
    <portType name="Calculator">
        <operation name="getTicket">
            <input message="tns:getTicket"/>
            <output message="tns:getTicketResponse"/>
        </operation>
        <operation name="getSubmissionTicket">
            <input message="tns:getSubmissionTicket"/>
            <output message="tns:getSubmissionTicketResponse"/>
        </operation>
        <operation name="add">
            <input wsaw:Action="http://calculator.jaxws.developerworks/add" 
                   message="tns:add"/>
            <output wsaw:Action="http://calculator.jaxws.developerworks/addResponse" 
                    message="tns:addResponse"/>
            <fault message="tns:AddNumbersException" name="AddNumbersException"
                   wsaw:Action="http://calculator.jaxws.developerworks/addFault"/>
        </operation>
        <operation name="addSubmission">
            <input wsaw:Action="http://calculator.jaxws.developerworks/addSubmission"
                   message="tns:addSubmission"/>
            <output 
               wsaw:Action="http://calculator.jaxws.developerworks/addSubmissionResponse" 
                    message="tns:addSubmissionResponse"/>
            <fault message="tns:AddNumbersException" name="AddNumbersException"
                wsaw:Action="http://calculator.jaxws.developerworks/addSubmissionFault"/>
        </operation>
    </portType>
    <binding name="CalculatorPortBinding" type="tns:Calculator">
        <wsaw:UsingAddressing/>
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="getTicket">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
        <operation name="getSubmissionTicket">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
        <operation name="add">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
            <fault name="AddNumbersException">
                <soap:fault name="AddNumbersException" use="literal"/>
            </fault>
        </operation>
        <operation name="addSubmission">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
            <fault name="AddNumbersException">
                <soap:fault name="AddNumbersException" use="literal"/>
            </fault>
        </operation>
    </binding>
    <service name="Calculator">
        <port name="CalculatorPort" binding="tns:CalculatorPortBinding">
            <soap:address location="http://localhost:9080/CalculatorService/Calculator"/>
        </port>
    </service>
</definitions>

Generating an SEI

When an SEI is generated using the WSDL in Listing 7, the @Action and @FaultAction annotations are not added automatically. In the SEI in Listing 8, we have manually added the annotations.

Using this WSDL, and the schema Calculator_schema1.xsd in the application ear file, we can generate a Service Endpoint Interface (SEI). This can be done by using the wsimport tool available in the bin directory in the WebSphere Application Sever install. The generated SEI is shown in Listing 8. It includes four methods getTicket(), add(), getSubmissionTicket() and addSubmission(). The getTicket() method returns a W3CEndpointReference, whereas the getSubmissionTicket() method returns a SubmissionEndpointReference. The add() and addSubmission() methods return an int, and they are also annotated with an @Action annotation. The @Action annotation contains a @FaultAction annotation that maps the AddNumbersException to an action.

Listing 8. Calculator.java
package developerworks.jaxws.calculator;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Action;
import javax.xml.ws.FaultAction;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

@WebService(name = "Calculator", targetNamespace = 
            "http://calculator.jaxws.developerworks")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface Calculator {

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "getTicket",
                 targetNamespace = "http://calculator.jaxws.developerworks",
                 className = "developerworks.jaxws.calculator.GetTicket")
    @ResponseWrapper(localName = "getTicketResponse",
                 targetNamespace = "http://calculator.jaxws.developerworks",
                 className = "developerworks.jaxws.calculator.GetTicketResponse")
    public W3CEndpointReference getTicket();

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "getSubmissionTicket",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.GetSubmissionTicket")
    @ResponseWrapper(localName = "getSubmissionTicketResponse",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.GetSubmissionTicketResponse")
    public SubmissionEndpointReference getSubmissionTicket();

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "add",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.Add")
    @ResponseWrapper(localName = "addResponse",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.AddResponse")
    @Action(input = "http://calculator.jaxws.developerworks/add",
            output = "http://calculator.jaxws.developerworks/addResponse",
            fault = {@FaultAction(className = AddNumbersException.class,
            value = "http://calculator.jaxws.developerworks/addFault")})
    public int add(
        @WebParam(name = "arg0", targetNamespace = "")
        int arg0,
        @WebParam(name = "arg1", targetNamespace = "")
        int arg1)
        throws AddNumbersException_Exception;

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "addSubmission",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.AddSubmission")
    @ResponseWrapper(localName = "addSubmissionResponse",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.AddSubmissionResponse")
    @Action(input = "http://calculator.jaxws.developerworks/addSubmission",
            output = "http://calculator.jaxws.developerworks/addSubmissionResponse",
            fault = {@FaultAction(className = AddNumbersException.class,
            value = "http://calculator.jaxws.developerworks/addSubmissionFault")})
    public int addSubmission(
        @WebParam(name = "arg0", targetNamespace = "")
        int arg0,
        @WebParam(name = "arg1", targetNamespace = "")
        int arg1)
        throws AddNumbersException_Exception;

}

In Listing 9, we have our web services implementation. It is annotated with @Addressing and @SubmissionAddressing to indicate that WS-Addressing is enabled for this application using both specifications. Note that @Addressing and @SubmissionAddressing must be added to the implementation class and not the SEI. The getTicket() and getSubmissionTicket() methods, each create an endpoint reference containing a ticket. The add() and addSubmission()methods check for that ticket before allowing the two numbers to be added together. For the purposes of our simple example we have simply hard coded a string to act as the ticket. In a more realistic scenario, however, we can imagine that the ticket actually represents, for example, the key to a record in a database.

Listing 9. CalculatorService.java
package developerworks.jaxws.calculator.impl;

import java.util.List;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.soap.Addressing;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ibm.websphere.wsaddressing.EndpointReferenceManager;
import com.ibm.websphere.wsaddressing.ReferenceParameterCreationException;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionAddressing;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

import developerworks.jaxws.calculator.AddNumbersException;
import developerworks.jaxws.calculator.AddNumbersException_Exception;
import developerworks.jaxws.calculator.Calculator;

@Addressing
@SubmissionAddressing
@WebService(endpointInterface = "developerworks.jaxws.calculator.Calculator",
            serviceName = "Calculator",
            portName = "CalculatorPort",
            targetNamespace = "http://calculator.jaxws.developerworks")
public class CalculatorService implements Calculator {

    @Resource
    private WebServiceContext context;

    public W3CEndpointReference getTicket() {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        Element element = null;

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.newDocument();
            element = document.createElementNS(
                          "http://calculator.jaxws.developerworks",
                          "TicketId");
            element.appendChild( document.createTextNode("123456789") );
        } catch (ParserConfigurationException pce) {
            throw new WebServiceException("Unable to create ticket.", pce);
        }

        return (W3CEndpointReference) context.getEndpointReference(element);
    }

    public SubmissionEndpointReference getSubmissionTicket() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        Element element = null;

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.newDocument();
            element = document.createElementNS(
                          "http://calculator.jaxws.developerworks",
                          "TicketId");
            element.appendChild( document.createTextNode("123456789") );
        } catch (ParserConfigurationException pce) {
            throw new WebServiceException("Unable to create ticket.", pce);
        }

        return (SubmissionEndpointReference) context.getEndpointReference(
                SubmissionEndpointReference.class, element);
    }

    public int add(int value1, int value2) throws AddNumbersException_Exception {
        List<?> list = (List<?>) context.getMessageContext().get(
                MessageContext.REFERENCE_PARAMETERS);

        if (list.isEmpty())
            throw new AddNumbersException_Exception("No ticket found.",
                new AddNumbersException());

        Element element = (Element) list.get(0);

        if (!"123456789".equals(element.getTextContent()))
            throw new AddNumbersException_Exception("Invalid ticket: "
                    + element.getTextContent(), new AddNumbersException());

        return value1 + value2;
    }

    public int addSubmission(int value1, int value2)
            throws AddNumbersException_Exception {
        String refParam;
        try {
            refParam = EndpointReferenceManager
                    .getReferenceParameterFromMessageContext(new QName(
                            "http://calculator.jaxws.developerworks",
                            "TicketId"));
        } catch (ReferenceParameterCreationException e) {
            throw new AddNumbersException_Exception("No ticket found.",
                    new AddNumbersException());
        }
	    
        if (!"123456789".equals(refParam)) {
            throw new AddNumbersException_Exception("Invalid ticket: "
                    + refParam, new AddNumbersException());
        }

        return value1 + value2;
    }
}

Support for the WS-Addressing Member Submission specification

When using the wsimport tool to generate client-side artifacts, it will automatically map endpoint references in the WS-Addressing Core 1.0 namespace to the W3CEndpointReference class. However, in order to map endpoint references in the WS-Addressing Member Submission namespace to the SubmissionEndpointReference class you will need to specify the provided binding file, SubmissionEndpointReference.xjb as a -b parameter to the tool. The binding file can be found in the util directory of your WebSphere Application Server installation.

Listing 10 shows a client that demonstrates the use of our Calculator service. It is written to use both the WS-Addressing 1.0 specifications and the WS-Addressing Member Submission specification. To achieve this it invokes the service using the get ticket methods to retrieve an endpoint reference that contains a ticket as a reference parameter. It then uses that endpoint reference to send the request to the corresponding add method to add the two numbers together. Using the endpoint reference will cause the reference parameter it contains to be automatically included as a SOAP header in the request. This will then be checked by the web service before the numbers are added and the result sent.

Listing 10. CalculatorClient.java
package developerworks.jaxws.calculator.client;

import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import com.ibm.websphere.wsaddressing.jaxws21.SubmissionAddressingFeature;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

import developerworks.jaxws.calculator.Calculator;
import developerworks.jaxws.calculator.Calculator_Service;

public class CalculatorClient {
    /**
     * @param args
     */
    public static void main(String[] args) {
        try {            
            int value0 = Integer.parseInt(args[0]);
            int value1 = Integer.parseInt(args[1]);
	
            Calculator_Service service = new Calculator_Service();
            Calculator port1 = service.getCalculatorPort();

            // Retrieve W3CEndpointRefence ticket
            W3CEndpointReference epr = port1.getTicket();
            Calculator port2 = epr.getPort(Calculator.class,
                    new AddressingFeature());
	        
            // Add numbers using W3CEndpointRefence ticket
            int answer = port2.add(value0, value1);
            System.out
                    .println("The answer using a W3CEndpointRefence ticket is: "
                            + answer);
            // Retrieve SubmissionEndpointReference ticket
            SubmissionEndpointReference submissionEpr = port1
                    .getSubmissionTicket();
            port2 = submissionEpr.getPort(Calculator.class,
                    new SubmissionAddressingFeature());
	        
            // Add numbers using a SubmissionEndpointReference
            answer = port2.addSubmission(value0, value1);
            System.out
                    .println("The answer using a SubmissionEndpointReference ticket is: "
                            + answer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

In Listing 11, we see the message that is sent when we request a ticket using the getTicket() method. Note that the WS-Addressing default action patten is used to determine the action to use, since there was no @Action annotation on the getTicket() method in Listing 8. The default action pattern is the WS-Addressing specification defined way to determine the action based on properties of the WSDL operation.

Listing 11. GetTicket Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:To>http://localhost:9080/CalculatorService/Calculator</wsa:To>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998512414</wsa:MessageID>
        <wsa:Action>
            http://calculator.jaxws.developerworks/Calculator/getTicketRequest
        </wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getTicket
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks"/>
    </soapenv:Body>
</soapenv:Envelope>

In Listing 12, we see the response message. Note that the TicketId is included in the ReferenceParameters in the returned EndpointReference, and that the default action pattern is still being used. Also note that the WS-Addressing 1.0 Core specification namespace is used for the EndpointReference, as well as the WS-Addressing headers on the subsequent request and response using that EndpointReference.

Listing 12. GetTicket Response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/>
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>
            http://calculator.jaxws.developerworks/Calculator/getTicketResponse
        </wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998512414</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getTicketResponse
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing" 
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>
                <ns3:Address>
                    http://L32H82K:9080/CalculatorService/Calculator
                </ns3:Address>
                <ns3:ReferenceParameters>
                    <ns4:TicketId
                         xmlns="http://calculator.jaxws.developerworks" 
                         xmlns:wsa="http://www.w3.org/2005/08/addressing">
                        123456789
                    </ns4:TicketId>
                </ns3:ReferenceParameters>
                <ns3:Metadata>
                    <wsam:ServiceName
                         xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
                         xmlns:axis2ns5="http://calculator.jaxws.developerworks"
                         xmlns:wsa="http://www.w3.org/2005/08/addressing"
                         EndpointName="CalculatorPort">
                        axis2ns5:Calculator
                    </wsam:ServiceName>
                </ns3:Metadata>
            </return>
        </ns4:getTicketResponse>
   </soapenv:Body>

In Listing 13 we see the message that is sent when we call the add() method. Note that the TicketId is included in the message headers. Also note that the action matches the input action in the @Action annotation on the add method in Listing 8.

Listing 13. Add Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <ns4:TicketId xmlns:ns4="http://calculator.jaxws.developerworks"
             xmlns="http://calculator.jaxws.developerworks"
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             ns3:IsReferenceParameter="true">123456789</ns4:TicketId>
        <wsa:To>http://L32H82K:9080/CalculatorService/Calculator</wsa:To>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516588</wsa:MessageID>
        <wsa:Action>http://calculator.jaxws.developerworks/add</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:add xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <arg0>1</arg0>
            <arg1>2</arg1>
        </ns4:add>
    </soapenv:Body>
</soapenv:Envelope>

In Listing 14, we see the final response message with the expected result and the output action set in Listing 8.

Listing 14. Add Response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>http://calculator.jaxws.developerworks/addResponse</wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516588</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:addResponse xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>3</return>
        </ns4:addResponse>
    </soapenv:Body>
</soapenv:Envelope>

In Listing 15, we see the corresponding messages that are sent when the WS-Addressing Member Submission specification EndpointReference is used.

Listing 15. WS-Addressing Member Submission specification
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:To>http://localhost:9080/CalculatorService/Calculator</wsa:To>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516636</wsa:MessageID>
        <wsa:Action>
        http://calculator.jaxws.developerworks/Calculator/getSubmissionTicketRequest
        </wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getSubmissionTicket
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks"/>
    </soapenv:Body>
</soapenv:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>
        http://calculator.jaxws.developerworks/Calculator/getSubmissionTicketResponse
        </wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516636</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getSubmissionTicketResponse
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>
                <ns2:Address>
                    http://L32H82K:9080/CalculatorService/Calculator
                </ns2:Address>
                <ns2:ReferenceParameters>
                    <ns4:TicketId xmlns="http://calculator.jaxws.developerworks"
                         xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
                        123456789
                    </ns4:TicketId>
                </ns2:ReferenceParameters>
                <ns2:ServiceName PortName="CalculatorPort">
                    ns4:Calculator
                </ns2:ServiceName>
            </return>
        </ns4:getSubmissionTicketResponse>
    </soapenv:Body>
</soapenv:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <ns4:TicketId xmlns:ns4="http://calculator.jaxws.developerworks"
             xmlns="http://calculator.jaxws.developerworks"
             xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing">123456789</ns4:TicketId>
        <wsa:To>http://L32H82K:9080/CalculatorService/Calculator</wsa:To>
        <wsa:ReplyTo>
            <wsa:Address>
                http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
            </wsa:Address>
        </wsa:ReplyTo>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516715</wsa:MessageID>
        <wsa:Action>http://calculator.jaxws.developerworks/addSubmission</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:addSubmission xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <arg0>1</arg0>
            <arg1>2</arg1>
        </ns4:addSubmission>
    </soapenv:Body>
</soapenv:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
        <wsa:MessageID>urn:uuid:A9C31FB6B32D8A45DD1258998519215</wsa:MessageID>
        <wsa:Action>
            http://calculator.jaxws.developerworks/addSubmissionResponse
        </wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516715</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:addSubmissionResponse
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>3</return>
        </ns4:addSubmissionResponse>
    </soapenv:Body>
</soapenv:Envelope>

Summary

In this article we presented the new WS-Addressing related concepts introduced in the JAX-WS 2.1 specification, and we showed how they can be used to write a stateful web service application. We have also shown how the standard API has been extended in order to support the WS-Addressing Member Submission specification, in addition to the WS-Addressing 1.0 specifications that are required in JAX-WS 2.1.


Acknowledgements

Many thanks to the following people for their helpful comments during the development of this article: Esther Dovey, and Sara Mitchell.

IBM, WebSphere and Rational are trademarks of International Business Machines Corporation in the United States, other countries, or both. Java and all Java-based trademarks and logos are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Other company, product, or service names may be trademarks or service marks of others.


Download

DescriptionNameSize
Sample files for this articleCalculator.ear10KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services, WebSphere
ArticleID=461181
ArticleTitle=JAX-WS 2.1 Support for WS-Addressing in WebSphere Application Server V7
publish-date=01122010