在 WebSphere Application Server V7 中为 WS-Addressing 提供 JAX-WS 2.1 支持

Brian T. De Pradine, 软件工程师, IBM
Katherine Sanders, 软件工程师, IBM

简介: IBM WebSphere Application Server V7 包括了对 Java API for XML-Based Web Services (JAX-WS) 2.1 规范的支持。JAX-WS 2.1 是 Java Specification Request (JSR) 224 的维护版本,通过增加新功能对 JAX-WS 2.0 规范提供的功能进行了扩展。其中最重要的新功能就是在应用程序编程接口(Application Programming Interface,API)中支持 Web Services Addressing (WS-Addressing)。在本文中,我们将了解如何使用这个新的 WS-Addressing 支持,以及如何帮助 web 服务开发人员简化有状态 web 服务的开发。

简介

Java™ API for XML-Based Web Services (JAX-WS) 接替了此前的标准 Java API for XML based RPC (JAX-RPC)。JAX-RPC 1.0 和 JAX-RPC 1.1 为支持 Remote Procedure Call (RPC) 风格的 Web 服务调用定义了 API 和约定。然而,从那时起,Web 服务开始朝更加面向文档的风格发展。JAX-WS 2.0 提供了完全不同的应用程序编程接口(API)和约定来支持更新风格的 web 服务交互。并且还特别注重简化开发人员在编写 Web 服务应用程序时的体验。参见参考资料部分,获得详细介绍 JAX-WS 和 JAX-RPC 之间差别的文章的链接。

JAX-WS 2.1 继承了从 JAX-WS 2.0 开始出现的简化趋势,使开发人员更易于编写有状态 Web 服务。这是通过向 JAX-WS API 添加明确的 Web Services Addressing (WS-Addressing) 支持实现的。在本文中,我们将给出一个示例应用程序,它展示了如何使用这些新的 API 编写有状态 Web 服务,但是首先我们将详细了解一下这些与 WS-Addressing 有关的新 API。

不过,在开始之前,我们需要指出 JAX-WS 2.1 规范只支持 WS-Addressing 1.0 Core 和 Simple Object Access Protocol (SOAP) Binding 规范。如果需要支持 WS-Addressing 规范的不同版本,那么 JAX-WS 2.1 规范还为供应商提供了扩展 API 的能力。在 IBM® WebSphere® Application Server V7 中,我们利用了这种功能,以支持较旧的 WS-Addressing Member Submission 规范(参见参考资料)。这些扩展也将在本文中加以介绍。

端点引用

JAX-WS 2.1 规范引入了端点引用(endpoint reference)的概念。端点引用封装了用于成功定位 Web 服务端点所需的所有细节。API 引入了一个新类,EndpointReference,用于表示端点引用。然而,该类并不是由开发人员直接使用,而是应当使用它的子类。

JAX-WS 2.1 API 包括了 EndpointReference 的一个子类,名为 W3CEndpointReference。它的作用是根据 WS-Addressing 1.0 Core 规范的要求表示端点引用。在 WebSphere Application Server V7 中,我们提供了另一个子类 SubmissionEndpointReference,用于根据 WS-Addressing Member Submission 规范表示端点引用。这两个类之间的关系如图 1 所示。


图 1. 端点关系
端点关系

JAX-WS 2.1 规范还定义了多种在应用程序中创建端点引用的方法。清单 1 中的代码片段使用 W3CEndpointReferenceBuilder 类显示了其中一种方法。为清晰起见,我们在下面的示例中忽略了一些细节,但是可以通过本文末尾的应用程序获得完整的示例。


清单 1. JAX-WS 2.1 示例

				
		
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();

W3CEndpointReferenceBuilder 使开发人员能够指定端点引用的任意属性。在清单 1 中,我们仅仅指定了一个地址和一个引用参数,然而,还可以指定 Web Services Description Language (WSDL) 服务名和端点(端口)名来代替地址。运行时将使用服务名和端点名的组合来识别引用所需的端点,并且返回一个填充有正确地址的 W3CEndpointReference

如果需要使用 SubmissionEndpointReference 替代 W3CEndpointReference,那么在 WebSphere Application Server V7 中,可以使用 SubmissionEndpointReferenceBuilder 类,如清单 2 中的代码片段所示。


清单 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();

如果使用的是服务名和端点名的组合,那么可以使用 W3CEndpointReferenceBuilderSubmissionEndpointReferenceBuilder 类为同一个 Java Platform, Enterprise Edition (Java EE) 应用程序中部署的任意端点创建端点引用。这表示,如果端点不在同一个应用程序中,那么必须明确指定地址。如果端点所需的仅是对其本身的引用,那么 JAX-WS 2.1 提供了一种更简单的替代方法来使用构建程序。WebServiceContext 类被扩展,以支持端点引用的创建。如清单 3 所示。


清单 3. WebServiceContext 类

				
			
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);

在集群中创建端点引用

如果应用程序被部署到集群中,那么使用构建程序或 WebServiceContext 创建的任何端点引用都不会支持对某个特定服务器或端点的相关性(affinity)。不过,简单的工作负载管理是可行的,因为使用这种端点引用通过代理发出的任何请求都将以轮循(round-robin)方式分布到集群成员中。

在使用 WebServiceContext 时,惟一可以明确指定的属性是一个引用参数。地址元素以及所有其他属性由运行时填充。如果需要一个 SubmissionEndpointReference,那么在 WebSphere Application Server V7 中,可以使用 JAX-WS 2.1 提供的扩展机制。如清单 4 的代码片段所示。


清单 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);

应用程序中创建的端点引用可以通过连接返回到客户端。客户端随后可以使用该端点引用按需调用端点。根据 WS-Addressing 规范,端点引用中包含的任何引用参数都将被作为头部(header)自动添加到要发送的 SOAP 信封。JAX-WS 2.1 还提供了一种工具,允许 Web 服务应用程序检索这些引用参数,如清单 5 所示。


清单 5. 检索引用参数

				
	
import org.w3c.dom.Element;    
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

@Resource
private WebServiceContext context;

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

该列表随后将被读取,以从中找出引用参数。然而,如果遵守 WS-Addressing Member Submission 规范编写应用程序,那么就不能使用这种机制检索引用参数。相反,必须使用 EndpointReferenceManager 类,这是 WebSphere Application Server V7 提供的专有 WS-Addressing API 的一部分。如清单 6 所示。在这种情况下,必须提供引用参数的名称才能检索它。


清单 6. EndpointReferenceManager

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

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

Feature

JAX-WS 2.1 还引入了 feature 概念。一个 feature 就是指一种允许客户端开发人员通过编程方式控制客户端具体行为的机制。所有 feature 都来自 WebServiceFeature 类。这允许客户端开发人员将不同类型的 WebServiceFeature 传递给需要它们的客户端 API。与 WS-Addressing 有关的 feature 如图 2 所示。


图 2. WS-Addressing Feature
WS-Addressing Feature

AddressingFeature 用于控制 WS-Addressing 的使用。它允许开发人员启用/禁用客户端对 WS-Addressing 的使用。如果启用了 WS-Addressing,客户端将在要发送的 SOAP 消息中包含 WS-Addressing 头。这些头将位于 WS-Addressing 1.0 Core 规范名称空间 http://www.w3.org/2005/08/addressing 中。如果禁用 WS-Addressing,那么不会发送任何 WS-Addressing 头。

在 WebSphere Application Server V7 中,我们还提供一个 SubmissionAddressingFeature 类。该类与 AddressingFeature 的工作方式相同,惟一不同之处是如果它得到启用,那么由客户端发送的任何 WS-Addressing 头都将位于 WS-Addressing Member Submission 规范名称空间 http://schemas.xmlsoap.org/ws/2004/08/addressing 中。在 WebSphere Application Server V7 中,可以使用其他机制启用客户端中的 WS-Addressing 支持,但是这不属于本文的讨论范围。请参见参考资料部分,获得介绍这些机制的相关链接。

注释

JAX-WS 2.1 大量使用了注释(annotation)来简化服务器端的应用程序开发。@Addressing 注释在服务器端起到与 AddressingFeature 相同的作用。它用于对 web 服务端点启用/禁用 WS-Addressing。如果启用了 WS-Addressing,那么运行时将处理传入请求中包含的 http://www.w3.org/2005/08/addressing 名称空间中的任何 WS-Addressing 头。此外,任何响应消息在适当时都会将 WS-Addressing 头添加到自身。如果 WS-Addressing 被禁用,那么传入请求中的任何 WS-Addressing 头部都将被忽略。

@Addressing 注释还支持一个名为 required 的属性。如果将该属性设置为 true,那么任何传入 web 服务的消息都必须包含 WS-Addressing 头,否则将向客户端返回一个错误。required 属性也出现在 AddressingFeature 中,但是根据 JAX-WS 2.1 规范,它将被客户端忽略。在 WebSphere Application Server V7 中,我们还提供了 @SubmissionAddressing 注释。它与 @Addressing 的工作方式相同,不同之处在于它与 http://schemas.xmlsoap.org/ws/2004/08/addressing 名称空间中的 WS-Addressing 头有关。这些类如图 3 所示。


图 3. Addressing 类
Addressing 类

JAX-WS 2.1 还引入了新的注释来支持 WS-Addressing 动作和 WSDL 操作的映射。这些新注释是 @Action@FaultAction@Action 注释允许将一个动作显式地关联到一个 WSDL 操作的输入和输出。@FaultAction 注释在 @Action 注释的内部使用,用于将每个错误关联到一个操作。这些类如图 4 所示。要使用 @Action@FaultAction 注释,需要用到 @Addressing 注释,否则它们将被忽略。


图 4. Fault 和 Action 类
Fault 和 Action 类 

应用程序

现在我们已经简要介绍了 JAX-WS 2.1 中引入的与 WS-Addressing 有关的新概念,接下来我们将把它们组合到一个有用的应用程序中。在下面给出的 Calculator 应用程序中,客户端向 web 服务发出一个请求,要求将两个数相加并返回结果。然而,在客户端发出请求之前,它必须首先从 web 服务获得一个票证(ticket),之后才能够发出请求来将两个数字相加。这个票证被作为端点引用内部的一个引用参数发送给客户端。客户端随后可以使用这个端点引用来发送请求,将两个数字相加。

还可以下载获得这个 Calculator 应用程序。该应用程序以 .ear 文件的形式提供,可以被导入到 IBM Rational® Application Developer V7.5.1 或安装到 WebSphere Application Server V7 上。要在 Rational Application Developer 上完整编译,必须将 com.ibm.jaxws.thinclient_7.0.0.jar 添加到创建的 CalculatorClientCalculatorService 项目的类路径。jar 文件可以在 WebSphere Application Server 安装的运行时目录中找到。

让我们首先看一下 Calculator 服务的 WSDL。WSDL 如清单 7 所示。我们可以看到其中包含 4 个操作:getTicketaddgetSubmissionTicketaddSubmission。getTicket 操作返回一个端点引用,其中包含作为引用参数提供的票证。add 操作允许我们将两个数字相加。其他两个操作执行相同的功能,但是使用的是 WS-Addressing Member Submission 规范而不是 WS-Addressing 1.0 Core 规范。


清单 7. Calculator.wsdl

				
			


    
        
            
        
    
    
        
    
    
        
    
    
        
    
    
        
    
    
        
    
    
        
    
    
        
    
    
        
    
    
        
    
    
        "getTicket">
            
            
        
        "getSubmissionTicket">
            
            
        
        "add">
            
            
            
        
        "addSubmission">
            
            
            
        
    
    
        
        
        
            
            
                
            
            
                
            
        
        
            
            
                
            
            
                
            
        
        
            
            
                
            
            
                
            
            
                
            
        
        
            
            
                
            
            
                
            
            
                
            
        
    
    
        
            
        
    


生成一个 SEI

当使用清单 7 中的 WSDL 生成 SEI 后,@Action@FaultAction 注释不会被自动添加。在清单 8 中的 SEI 中,我们手动添加了注释。

通过使用这个 WSDL 以及应用程序 ear 文件中的 Calculator_schema1.xsd 模式,我们可以生成一个 Service Endpoint Interface (SEI)。这可以通过使用 WebSphere Application Sever 安装的 bin 目录中的 wsimport 工具完成。生成的 SEI 如清单 8 所示。它包含 4 个方法:getTicket()add()getSubmissionTicket()addSubmission() getTicket() 方法返回一个 W3CEndpointReference,而 getSubmissionTicket() 方法返回一个 SubmissionEndpointReferenceadd()addSubmission() 方法返回一个 int,并且它们还使用 @Action 进行了注释。@Action 注释包含一个将 AddNumbersException 映射到动作 @FaultAction 注释。


清单 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",
            utput = "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",
            utput = "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;

}

在清单 9 中显示了我们的 web 服务的实现。它使用 @Addressing@SubmissionAddressing 进行了注释,表示通过这两种规范对应用程序启用了 WS-Addressing。注意,@Addressing@SubmissionAddressing 必须被添加到实现类而不是 SEI 中。getTicket()getSubmissionTicket() 方法各自创建了一个包含票证的端点引用。在将两个数字相加之前,add()addSubmission() 方法将检查该票证。考虑到我们的这个简单示例的意图,我们仅仅硬编码了一个字符串来充当票证。然而,在一个更加真实的场景中,我们可以想象得到这个票证实际上表示数据库中某个记录的键(举例而言)。


清单 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;
    }
}

对 WS-Addressing Member Submission 规范的支持

在使用 wsimport 工具生成客户端项目时,将自动把 WS-Addressing Core 1.0 名称空间中的端点引用映射到 W3CEndpointReference 类。然而,要将 WS-Addressing Member Submission 名称空间的端点引用映射到 SubmissionEndpointReference 类,您需要将所提供的绑定文件 SubmissionEndpointReference.xjb 指定为工具的 -b 参数。绑定文件可以在 WebSphere Application Server 安装的 util 目录中找到。

清单 10 展示的客户端演示了对 Calculator 服务的应用。它被编写为同时使用 WS-Addressing 1.0 规范和 WS-Addressing Member Submission 规范。为此,它使用 get ticket 方法调用服务来获取端点引用,后者包含作为引用参数提供的票证。随后使用端点引用向对应的 add 方法发送请求,要求将两个数字相加。使用端点引用将使所包含的引用参数被作为 SOAP 头自动包含到请求中。web 服务将首先检查这一点,然后再执行数字相加并发送结果。


清单 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();
        }
    }
}

在清单 11 中,我们看到在使用 getTicket() 方法请求票证时消息被发送。注意,使用了 WS-Addressing 的默认动作模式来确定要使用的动作,因为清单 8 中的 getTicket() 方法中没有使用 @Action 注释。默认动作模式是由 WS-Addressing 规范定义的一种方式,用于根据 WSDL 操作的属性确定操作。


清单 11. GetTicket Request

				
		    

    
        http://localhost:9080/CalculatorService/Calculator
        urn:uuid:14C1B8561B19D0B1261258998512414
        
            http://calculator.jaxws.developerworks/Calculator/getTicketRequest
        
    
    
        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"/>
    


在清单 12 中,我们看到了响应消息。注意,TicketId 包含在返回的 EndpointReferenceReferenceParameters 中,而且默认的动作模式仍在使用中。还需注意,WS-Addressing 1.0 Core 规范名称空间被用于 EndpointReference,以及使用该 EndpointReference 的后续请求和响应的 WS-Addressing 头。


清单 12. GetTicket Response

				
		    

        
            http://calculator.jaxws.developerworks/Calculator/getTicketResponse
        
        urn:uuid:14C1B8561B19D0B1261258998512414
    
    
        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">
            
                <ns3:Address>
                    http://L32H82K:9080/CalculatorService/Calculator
                
                <ns3:ReferenceParameters>
                    TicketId
                         xmlns="http://calculator.jaxws.developerworks" 
                         xmlns:wsa="http://www.w3.org/2005/08/addressing">
                        123456789
                    
                
                <ns3:Metadata>
                    
                        axis2ns5:Calculator
                    
                
            
        
   

在清单 13 中,我们看到在调用 add() 方法时消息被发送。注意 TicketId 包含在消息头中。还要注意该动作与清单 8 中 add 方法中的 @Action 注释的输入动作匹配。


清单 13. Add Request

				
		    

    wsa="http://www.w3.org/2005/08/addressing">
        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
        <wsa:To>http://L32H82K:9080/CalculatorService/Calculator
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516588
        <wsa:Action>http://calculator.jaxws.developerworks/add
    
    
        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">
            1
            2
        
    


在清单 14 中显示了最终的响应消息,其中包含预期的结果和清单 8 中设置的输出动作。


清单 14. Add Response

				
		    

    wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>http://calculator.jaxws.developerworks/addResponse
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516588
    
    
        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">
            3
        
    


在清单 15 中显示了在使用 WS-Addressing Member Submission 规范 EndpointReference 时发送的相应消息。


清单 15. WS-Addressing Member Submission 规范

				
			

    
        http://localhost:9080/CalculatorService/Calculator
        urn:uuid:14C1B8561B19D0B1261258998516636
        
        http://calculator.jaxws.developerworks/Calculator/getSubmissionTicketRequest
        
    
    
        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"/>
    



    
        
        http://calculator.jaxws.developerworks/Calculator/getSubmissionTicketResponse
        
        urn:uuid:14C1B8561B19D0B1261258998516636
    
    
        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">
            
                <ns2:Address>
                    http://L32H82K:9080/CalculatorService/Calculator
                
                <ns2:ReferenceParameters>
                    TicketId xmlns="http://calculator.jaxws.developerworks"
                         xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
                        123456789
                    
                
                <ns2:ServiceName PortName="CalculatorPort">
                    ns4:Calculator
                
            
        
    



    wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        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
        <wsa:To>http://L32H82K:9080/CalculatorService/Calculator
        <wsa:ReplyTo>
            <wsa:Address>
                http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
            
        
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516715
        <wsa:Action>http://calculator.jaxws.developerworks/addSubmission
    
    
        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">
            1
            2
        
    



    wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
        <wsa:MessageID>urn:uuid:A9C31FB6B32D8A45DD1258998519215
        <wsa:Action>
            http://calculator.jaxws.developerworks/addSubmissionResponse
        
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516715
    
    
        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">
            3
        
    


结束语

在本文中,我们介绍了 JAX-WS 2.1 规范中引入的与 WS-Addressing 有关的新概念,并展示了如何使用它们编写一个有状态 web 服务应用程序。除了支持 JAX-WS 2.1 所需的 WS-Addressing 1.0 规范外,我们还展示了如何扩展一个标准 API 来支持 WS-Addressing Member Submission 规范。

致谢

非常感谢 Esther Dovey 和 Sara Mitchell,他们为本书的撰写提供了宝贵的意见。

IBM、WebSphere 和 Rational 是 International Business Machines Corporation 在美国和/或其他国家的商标。Java 和所有基于 Java 的商标和徽标是 Sun Microsystems, Inc. 在美国和/或其他国家的商标。其他公司、产品或服务名称可能是其他公司的商标或服务标志。

原文链接:http://www.ibm.com/developerworks/cn/webservices/ws-JAXsupport/index.html

请使用浏览器的分享功能分享到微信等