内容


Web 服务互操作性,第 2 部分

Comments

引言


在第一篇文章中,您已了解演示应用程序实现了买方-卖方方案。它由多个角色组成,这些角色都被设计成 Web 服务,服务接口由 WSDL 来定义。仅有客户角色未被实现成 Web 服务,因为它被用作该应用程序的客户机。 图 1显示了这个结构。

角色和操作
角色和操作

图 1归 XMethods 版权所有 ©,这里的使用已获授权。)

我将在本文中描述的应用程序把供应商、仓库和银行等角色实现成运行于 WebSphere 的 Web 服务。这些服务的业务逻辑由 JavaBeans 来表示。客户角色被实现成一组 Java 服务器页面(Java Server Pages(JSP))。服务实现与 JSP 被捆绑成一个 Web 模块。除了 Java 和 JSP 代码外,这个 Web 模块还包括多个配置文件和所有服务的 WSDL 服务定义。最后,这个 Web 模块被打包成 J2EE 企业归档(J2EE Enterprise Archive(EAR))文件。您可以在任何遵守 J2EE 的应用程序服务器上安装这个 EAR 文件。在阅读下文前,您应该从 演示应用程序主页下载完整的 EAR 文件,该文件包括源代码。

图 1还显示有些服务被用作其它服务的客户机。例如,供应商服务使用仓库服务以确保可以履行定单。每个服务实现使用映射文件来找出它所使用的服务可在哪里被找到。上一篇文章中描述了这一机制。(请参阅 参考资料。)

Axis/JAX-RPC 中的 Web 服务


在您开始导入并运行实际的代码前,让我来为您逐步地讲述一点点理论。这将有助于您理解应用程序软件包的内容。

该应用程序中的 Web 服务的实现符合 JAX-RPC 规范。这意味着 WSDL 文档中定义的每个 <portType> 元素被映射到 Java 接口。例如,供应商 Web 服务被映射到名为 net.xmethods.www.ISupplierSoap 的接口。接口的名称取自于 <portType> 名称(在这里是“ISupplierSoap”),包的名称取自于 WSDL 中 <portType> 元素的名称空间。但是,该规范没有约定名称空间如何映射到包的名称。 清单 1显示的是 ISupplierSoap 接口,这个接口是根据 WSDL 服务定义生成的,所用的生成工具是 Apache Axis WSDL2Java。

清单 1. ISupplierSoap 接口

package net.xmethods.www;
public interface ISupplierSoap extends java.rmi.Remote {
    public java.lang.String sendPO(net.xmethods.www.PO po)
      throws java.rmi.RemoteException;
    public void shipConfirm(java.lang.String customerID, java.lang.String poNumber) 
      throws java.rmi.RemoteException;
    public java.lang.String 
    getPOStatus(java.lang.String customerID, java.lang.String poNumber) 
      throws java.rmi.RemoteException;
    public net.xmethods.www.Invoice 
    getInvoice(java.lang.String customerID, java.lang.String poNumber) 
      throws java.rmi.RemoteException;
    public net.xmethods.www.Catalog getCatalog() throws java.rmi.RemoteException;
}

请注意 JAX-RPC 规范还规定接口中的每个方法必须抛出 java.rmi.RemoteException。

Apache Axis WSDL2Java 工具还生成多个其它的类:

  • net.xmethods.www.ISupplierSoapImpl 类包含服务的实际的实现。它实现服务接口类。
  • net.xmethods.www.ISupplierSoapStub 类也实现服务接口,但被用作实际服务的代理。它由客户机来使用。
  • net.xmethods.www.SupplierService 类表示 WSDL 文档中的 <service> 元素(它也被称为“生成的服务接口”)。它包括多个方法,这些方法使客户机可以容易地获得服务的客户端存根。它的方法使您能够在运行时定义服务的实际端点位置。
  • net.xmethods.www.SupplierServiceLocator 类实现了上面的生成的服务接口。

您将在我们的应用程序中找到所有服务的这些类。

在 WebSphere Studio Application Developer 中运行该应用程序


在接下去的几节中,我将为您演示如何在 WebSphere Studio Application Developer(Application Developer)中安装该应用程序。您可以在该工具中的 WebSphere Test Environment 中运行和调试它,也可在独立的应用程序服务器上运行和调试它,我将在本文的末尾处描述后一种运行和调试方法。

为了把该应用程序导入到 Application Developer 中,请打开该工具并使用 J2EE 透视图( 图 2)。然后选择 File -> Import 选项。

Application Developer Import
Application Developer Import

单击“Next”按钮。在下一个对话框中,请指定您下载带有应用程序的 EAR 文件的位置。输入企业应用程序项目名“WSIDEAR”,如 图 3所示。

EAR Import
EAR Import

现在,请单击“Finish”,这将启动导入过程。完成后,您将看到名为 wsidEAR 的新的企业应用程序已被创建,wsidEAR 包含一个名为 wsid.war 的 Web 模块。这个 Web 模块由名为“wsid”的 Web 项目来表示(请看 图 4)。

wsid.war
wsid.war

在您更仔细地查看这个新的 Web 项目前,您必须为解决一个编译问题而对它的构建路径属性作一下修改。您必须把 XML 解析器库添加到类路径;您将在这里使用已包括在 WebSphere 中的 Apache Xerces 库。为了作这个修改,请在 Application Developer 中打开“Web”透视图,然后选择“wsid”Web 项目。请单击鼠标右键,选择弹出菜单中的“Properties”。然后单击左边的“Java Build Path”条目,选择 Libraries 选项卡。现在,您的窗口应与 图 5相似。

Java Build Path
Java Build Path

现在,请单击“Add External JARs”按钮并添加 WebSphere Studio 安装目录下的 \plugins\org.apache.xerces 目录中的 xerces.jar 文件。当您添加完 jar 文件后,请单击项目属性窗口中的 OK。这将解决编译问题。

运行该应用程序


有些配置选项使您能够控制如何运行该应用程序,我将马上讨论它们,但是让我们先按原样运行该应用程序。为此,请在 Application Developer 中打开 Web 透视图,右键单击“wsid”Web 项目,然后选择弹出菜单中的“Run on Server”(如 图 6所示)。

Run on Server

这将把新的应用程序发布到 WebSphere Test Environment 中。接着,服务器被启动,该应用程序被激活。根据 Web 模块的定义,基础上下文的根定义是“/wsid”,这意味着您可以通过 http://localhost:8080/wsid/ 来访问它。该工具将启动浏览器窗口并装入这个 URL(导致 welcome.jsp 页面被装入,因为这是这个 Web 模块的缺省的起始页面)。结果被显示在 图 7中。

WebSphere Test Environment
WebSphere Test Environment

请不要对您在 Console 窗口中看到的几个异常消息而感到担心 - 我马上将对此作出解释。该应用程序本身应该能够象在 IBM developerWorks 服务器上那样运行(您在阅读第一篇文章时已经看到),所以我不在这里赘述。仅有的差别是您在您的机器上本地运行服务而不是在 IBM 的服务器上!

部署服务


为了使服务实现在应用程序服务器上运行,您必须使 Axis 运行时了解该服务。简而言之,这一过程涉及把有关服务、它的接口、它的标识及它的实现类的信息存储在文件中,Axis 运行时使用这一文件来把入站请求解析到正确的目标。

把服务“部署”到 Axis 的方法有两种。一种是使用基于 JSP 的管理应用程序,这一程序使您能够通过用户界面来指定所有所需的值。第二种方法是通过程序并使用 Axis 提供的 org.apache.axis.client.AdminClient 类来做相同的事。您将在该应用程序中使用第二种方法并在该应用程序第一次被使用时立刻部署服务。

作为该应用程序的一部分被装入的第一个页面是 welcome.jsp 页面,所以支持的服务的部署代码被放在这一文件中。所有所需的值以文件(扩展名为 .wsdd)的形式被传递给 Axis 运行时。换言之,每个服务都有这样一个文件。 清单 2包含显示银行服务的部署文件的示例。

清单 2. 银行服务的部署文件

<deployment
    xmlns="http://xml.apache.org/axis/wsdd/"
    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <!-- Services from bankService WSDL service -->
  <service name="bank" provider="java:RPC" style="document">
      <parameter name="wsdlTargetNamespace" value="http://www.xmethods.net/ws-demo/"/>
      <parameter name="wsdlServiceElement" value="bankService"/>
      <parameter name="wsdlServicePort" value="bank"/>
      <parameter name="className" value="net.xmethods.www.IBankSoapImpl"/>
      <parameter name="wsdlPortType" value="IBankSoap"/>
            <operation name="charge" qname="operNS:chargeRequest" 
                    xmlns:operNS="http://www.xmethods.net/ws-demo/" returnQName="retNS:chargeResponse"         
                    xmlns:retNS="http://www.xmethods.net/ws-demo/" 
                    returnType="rtns:>chargeResponse" 
                    xmlns:rtns="http://www.xmethods.net/ws-demo/" >
      <parameter qname="pns:chargeRequest" 
                    xmlns:pns="http://www.xmethods.net/ws-demo/" type="tns:>chargeRequest" 
                    xmlns:tns="http://www.xmethods.net/ws-demo/"/>
      </operation>
      <parameter name="allowedMethods" value="charge"/>
      <typeMapping
        xmlns:ns="http://www.xmethods.net/ws-demo/"
        qname="ns:>chargeResponse"
        type="java:net.xmethods.www.ChargeResponse"
        serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
        deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
        encodingStyle=""
      />
      <typeMapping
        xmlns:ns="http://www.xmethods.net/ws-demo/"
        qname="ns:>chargeRequest"
        type="java:net.xmethods.www.ChargeRequest"
        serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
        deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
        encodingStyle=""
      />
  </service>
</deployment>

通过 org.apache.axis.clientAdminClient 类来部署这些信息是相当简单的; 清单 3显示的是从 welcome.jsp 文件中抽取的代码。

清单 3. welcome.jsp 中的代码

    // auto deploy the Web services
    if (!init) {
        // deploy
        AdminClient ac = new AdminClient();
        String[] wsdds = {"warehouse.wsdd", "bank.wsdd", "supplier.wsdd", "logger.wsdd"};
        String[] args = new String[3];
        for (int i=0; i<wsdds.length; i++) {
         args[0] = "-l";
         args[1] = net.xmethods.www.Data.local + "services/AdminService";
            args[2] = getServletContext().getRealPath(wsdds[i]);
            try {
                ac.process(args); 
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        init = true;
    }

管理服务本身作为 Web 服务被部署。它被预先安装到 Axis 运行时。运行完这些代码后可在应用程序服务器上本地访问这些服务。

使用远程服务


通过对该应用程序的设置,无论是否能够访问因特网,您都可以运行该应用程序。在缺省的情况下(也就是说,在您安装了 EAR 文件后未作任何修改的情况下),该应用程序不需要任何远程资源就可以运行。但是,因为这是互操作性的演示程序,所以您想用它来测试多个远程 Web 服务。

在启动时,该应用程序从 ROLES.php 配置文件中装入有关可用的服务及其端点的信息。一般来说,该配置文件位于 XMethods Web 站点的服务器上,即 http://www.xmethods.net/wsid/online/app/ROLES.php。但是,为了使您能够修改本地的配置(您没有位于 XMethods 的文件的写入权限),代码将检查是否存在该文件的本地副本,若存在,则代码使用这个本地文件。该应用程序在 Web 模块的“/app”目录中寻找该文件,如果您安装了该应用程序的 EAR 文件,那么您可以在那里找到仅配置了本地服务的文件。这就是您不需要连接到因特网就可以运行该应用程序的原因。

在您重命名该文件、重新启动 Web 应用程序(您必须重新启动该应用程序,重新装入 welcome.jsp 是不够的)并且连接到因特网后,您将使用 XMethods 服务器上的配置文件。在运行该应用程序时,您将从该应用程序的首页上的下拉列表中的更多可用的供应商与客户的组合中察觉这一修改。那时,您使用的是远程配置文件中定义的端点。唯一的例外是“本地的”供应商与客户角色,这些角色总是使用本地的应用程序服务器。在“本地的”情况下,即使客户应用程序与服务在这种情况下运行于同一台服务器上,您仍然通过它的 Web 服务接口来访问供应商。

您还可以处理仓库与银行到某些供应商与客户的映射。从 xml\CREDITMAPS.xml 和 xml\WAREHOUSEMAPS.xml 文件中可读取这些映射。如果您重命名这些文件的本地副本并重新启动 Web 应用程序,那么您将使用位于 XMethods Web 站点的这些文件的远程副本。您可以任意地修改这些文件的内容并了解对应用程序所产生的影响(如果有的话)。

最后,本地的产品目录的内容取自于 xml\CATALOG.xml 文件。在正常的情况下,您不必修改该文件的内容,本地副本的主要的存在理由是使您能够运行该应用程序而无需连接到因特网。

调试与跟踪该应用程序


如果您想单步执行代码的某些部分,那么您可以通过设置断点并重新装入该应用程序来单步执行。请您一定要在调试方式中启动服务器。显然,您只能调试本地运行的服务。

该应用程序还把某些事件的日志写到日志文件中,您可以把日志文件用于跟踪目的。日志记录也可以通过 Web 服务(即日志记录器服务)来完成。该服务与其它服务的差别是 XMethods 服务器上仅存在一个该服务的真正的实现。它的 URL 是 http://www.xmethods.net/wsid/online/log。您在 ROLES.php 文件中找不到这个端点的配置选项,因为它被硬编码在该应用程序中。您可以查看该日志文件,它的位置是 XMethods 站点的 http://www.xmethods.net/wsid/online/log.cgi。

如果您在没有连接到因特网的情况下在本地运行应用程序,那么您不能访问该服务,故不能跟踪所出现的情况。为了在没有连接的情况下在运行时支持跟踪,该应用程序包含简单的日志服务,该服务把日志请求打印到屏幕上(有关的实现类是 net.xmethods.www.ILoggerImpl)。该日志服务与其它服务一起被部署到服务器上并作为存在于 welcome.jsp 文件中的代码的一部分。但是,有些日志请求在本地的日志服务被部署前已被该应用程序发送出去。这将导致您在第一次运行该应用程序时可能看到的异常消息。

所用的是本地日志服务还是远程日志服务取决于在 net.xmethods.www.Data 类中设置的“useLocalLogger”标志。如果被设为 true,那么访问本地记录器服务,如果您把它改为 false,那么它将访问 XMethods 记录器服务。

另一种跟踪服务之间交换的数据的方法是使用 Apache Axis 附带的“tcpmon”工具。这个工具使您能够跟踪通过 HTTP 交换的数据包。它的使用方法是把服务请求转到启动该工具所在的地址和端口,然后把请求从那里转发至实际的端点。在这里,本地的 ROLES.php 文件很有用,因为它让我们修改本地服务的端口。

为了在 Application Developer 中启动 tcpmon 工具,请找到 axis.jar 文件中的 org.apache.axis.utils.tcpmon 类(它被存储在我们的应用程序中,位于 \WEB-INF\lib 目录下)。为了把这个类作为 Java 应用程序来启动,请选择这个类并使用“Run”图标,如 图 8所示。

Application Developer 中的 tcpmon
Application Developer 中的 tcpmon

该工具启动后,请指定接收请求的新端口(例如,12345)并把它们转发至实际的服务端点,即把主机名指定为“localhost”、把 8080 指定为端口(这是 WebSphere Test Environment 的运行位置),如 图 9所示。

Application Developer 中的 tcpmon
Application Developer 中的 tcpmon

为了添加新的侦听器,请单击 Add 按钮。现在,为了使用您在 tcpmon 工具中使用的相同端口,请修改 ROLES.php 文件的端点地址(在我们这里是 12345)。现在,更新后的文件与 清单 4相似。

清单 4. ROLES.php

<roles updatecode="20021027083911" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:noNamespaceSchemaLocation="ROLES.xsd">
   <role participant="ibm">
              <type>customer</type>
              <id>ibm-customer</id>
   </role>
   <role participant="ibm">
              <type>supplier</type>
              <id>ibm-supplier</id>
              <endpoint>http://localhost:12345/wsid/services/supplier</endpoint>
    </role>
    <role participant="ibm">
              <type>bank</type>
              <id>ibm-bank</id>
              <endpoint>http://localhost:8080/wsid/services/bank</endpoint>
    </role>
    <role participant="ibm">
              <type>warehouse</type>
              <id>ibm-warehouse</id>
              <endpoint>http://localhost:8080/wsid/services/warehouse</endpoint>
    </role>
</roles>

现在,请在测试环境中启动该应用程序,您将注意到所有发向供应商服务的请求现在通过 tcpmon 工具来路由,如 图 10所示。

通过 tcpmon 来路由的请求
通过 tcpmon 来路由的请求

这样,您可以分析发向服务与发自服务的实际的 SOAP 消息。请注意,在这个示例中,您只监视供应商服务。tcpmon 工具让您设置更多的侦听器,通过在 ROLES.php 文件中配置它们,您可以分别监视该应用程序中所有的服务。

在 WebSphere Application Server V4 中安装该应用程序


至此,我已向您演示了如何在 WebSphere Studio Application Developer 的 WebSphere Test Environment 中安装、运行和调试该应用程序。如果您想在分开安装的应用程序服务器中安装和运行它,那么您需要对代码作一下修改。原因是您需要定义在哪个 URL 下可访问本地部署的服务。原先的 EAR 文件包含假定它被安装在 8080 端口(这是测试环境使用的缺省端口)的代码。如果您运行带插件的 WebSphere Application Server 并且 Web 服务器位于端口 80(这是最常见的情况),那么您需要把 net.xmethods.www.Data 类中的静态的“本地”变量改为 http://localhost:80/wsid。在您作了这个修改后,您可以在 WebSphere Studio Application Developer 中把该应用程序导出为 EAR 文件,然后直接把它安装到 WebSphere Application Server。

该应用程序已在 Application Developer V5 和 WebSphere Application Server V5 中成功地被测试和运行,所以,如果您运行的正巧是这些新版本的产品,那么您可以在新产品中放心地安装和运行它。

致谢


Sam Ruby 为位于波士顿的 Web Services One 会议开发了该应用程序的原先的 IBM 实现。IONA 的 Richard Bonneau、Amberpoint 的 David Rees 和 webMethods 的 Hoa Nguyen 拥有他们各自公司的实现,他们为测试该应用程序提供了许多帮助。最后,XMethods 的 Tony Hong 是这个活动的发起者并把演示程序的主页托管于 http://www.xmethods.net/wsid/online


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=21952
ArticleTitle=Web 服务互操作性,第 2 部分
publish-date=03012003