内容


如何在 Web 服务中使用 Service Data Objects 2.1 的动态数据 API

Comments

引言

Service Data Objects (SDO) 2.1 是一种数据编程体系结构和 API,可提供对异类数据源的统一数据访问。Apache Tuscany 开源项目(请参见参考资料)正在开发 2.1 规范的实现,该实现也打包在 IBM WebSphere Application Server Version 6.1 Feature Pack for SOA 的 Beta1 版中(请参见参考资料)。此规范对 WebSphere Application Server 6.1 的功能进行了扩展。IBM 提供了可供免费下载的 WebSphere Application Server 6.1 试用版

服务数据对象通常用于将数据从一个应用程序传输到另一个应用程序。此用法模型可以方便地集成在 Web 服务环境中;在此环境中,客户机通常调用其他方提供的服务,需要将数据从 Web 服务提供者传输到使用者。SDO 2.1 规范描述了使用静态或动态数据 API 创建 SDO 的两种方法。在两种情况下,表示 SDO 的对象都必须实现 commonj.sdo.DataObject 接口,通过该接口可与规范定义的其他 SDO API 进行交互。

本文将描述 SDO 的静态与动态数据 API 间的差异,列出构建使用动态数据 API 的 Web 服务应用程序所需的步骤,并提供了可安装在 IBM WebSphere Application Server Version 6.1 Feature Pack for SOA 的 Beta1 版本上的可部署应用程序,用以说明如何在 Web 服务环境中使用 SDO 的动态数据 API。

图 1 说明了静态和动态数据 API 的生成位置以及如何使用其实例化服务数据对象,以供稍后用于操作底层的业务数据。

图 1. 静态和动态数据 API 的用法
静态和动态数据 API 的用法
静态和动态数据 API 的用法

SDO 的静态数据 API

静态数据 API 是基于输入数据模型生成的。不同的数据模型将得到不同的静态数据 API。也就是说,静态数据 API 只是数据模型的另一个表示形式。Apache Tuscany 项目包括了一个数据 API 生成工具,该工具接受数据模型(通常用 XML 模式文档(XLM Schema Document,XSD)或 Web 服务描述语言(Web Service Descripiton Language,WSDL))作为输入。该工具将随后以 Java™ 类的形式输出静态数据 API。所生成的 Java 类通常包括用于创建和操作数据模型的实例的工厂、接口和实现代码。

为了说明如何使用静态数据 API,让我们以使用 XSD 中定义的复杂类型表示的数据模型为例,如清单 1 中所示。

清单 1. 表示类型 Person 的 XSD 代码片段
<complexType name="Person">
    <sequence>
      <element name=”firstName” type="string"/>
      <element name=”lastName” type="string"/>
        <element name=”greeting” type=”string”/>
               <element name=”id” type=”int”/>
                   </sequence>
</complexType>

如果将此类型传入数据 API 生成工具,输出将为 Person 的类型接口(一个工厂接口,可利用其创建类型 Person 的实例)和实现 Personcommonj.sdo.DataObject 的实现类(用于获取和设置属性,如 getFirstName()setFirstName())。在这里,由于 Person 类实现 commonj.sdo.DataObject,此生成类可以在规范定义的接受 commonj.sdo.DataObject 作为参数的所有 SDO API 中使用。

清单 2 中所示的代码可帮助说明如何使用静态数据 API。

清单 2. 演示静态数据 API 的代码片段
// Register and initialize the SDO types defined in the generated
// PersonFactory class
SDOUtil.registerStaticTypes(PersonFactory.class);
    
// Create an instance of Person using the Factory class  
Person person = PersonFactory.INSTANCE.createPerson();

// Set properties of the newly created Person object
person.setFirstName("John");
person.setLastName("Doe");

// Example of how to pass a Person object to XMLHelper.save() method for
// void XMLHelper.save(DataObject dataObject, String rootElementURI,
// String rootElementName, OutputStream outputStream)
XMLHelper.INSTANCE.save((DataObject)person, "http://www.example.com/person", 
"person", System.out);

SDO 的动态数据 API

动态 API 场景并不要求为数据模型中的对象生成类型接口、工厂类或实现类。相反,可以选择使用规范中定义的标准 SDO API 来创建数据模型的实例,以将数据传输到其他应用程序。为此,必须首先注册您的数据模型。直接将 XSD 文档传入 XSDHelper.define() 方法。注册了数据模型后,就可以使用 DataFactory 类来创建数据模型的实例。此实例与静态数据 API 创建的实例的主要区别在于,该实例类型为 commonj.sdo.DataObject 而不是表示数据对象的类型接口。这意味着,用户可以仅使用 DataObject 接口中定义的方法类获取和设置数据对象的属性,而无需使用静态 API 场景中生成的 API。

表 1 显示了如何使用静态和动态数据 API 设置和检索清单 1 中定义的 Person 类型的属性。

表 1. 静态与动态 SDO 在检索和设置属性方面的区别
Person 的属性静态数据 API动态数据 API
firstNamePerson.getFirstName() Person.setFirstName(String fname)DataObject.getString(“firstName”) DataObject.setString(“firstName”, fname)
IdPerson.getId() Person.setId(int id)DataObject.getInt(“id”) DataObject.setInt(“id”, id);

使用 SDO 的动态数据 API 的 Web 服务应用程序

接下来,本文将说明如何实现使用 SDO 的动态数据 API 来传输数据的 Web 服务应用程序。对于此应用程序,创建向 Web 服务提供者发送请求的客户机,该 Web 服务提供者将随后使用 commonj.sdo.DataObject 格式的通用数据对象进行响应。客户机将随后记录数据对象中的数据,然后将此信息输出到用户。图 2 显示了此应用程序中的客户机和服务交互的简要视图。

图 2. 使用动态数据 API 的 Web 服务应用程序
使用动态数据 API 的 Web 服务应用程序
使用动态数据 API 的 Web 服务应用程序

Helloworld Web 服务——Web 服务提供者

以下是使用服务组件体系结构(Service Component Architecture,SCA)术语的 Web 服务提供者的情况(即“此 SCA 组合的情况”)。在 Tuscany 中,此工作是使用清单 3 中所示的 default.scdl 文件完成的。此处的 default.scdl 文件描述使用哪个数据绑定技术来支持数据传输、提供哪个服务以及定义了哪个组件。有关 SCA 组合、服务和组件的定义的更多信息,请参考 SCA 规范(请参见参考资料)。

在清单 3 中,以下代码行是 default.scdl 中与 SDO 相关的 XML 元素,作为 SCA 数据绑定技术使用:

<dbsdo:import.sdo  location="wsdl/helloworld.wsdl"/>

此代码使 SCA 运行时在 SDO 运行时中注册 helloworld.wsdl 中描述的数据模型,以便稍后在服务实现中使用 SDO 的动态数据 API,而不用担心数据模型注册的事情。

清单 3. default.scdl:描述 SCA 组合的文件
<?xml version="1.0" encoding="UTF-8"?>
 <composite xmlns="http://www.osoa.org/xmlns/sca/1.0"  
	  xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance" 
      xmlns:dbsdo="http://incubator.apache.org/tuscany/xmlns/
        databinding/sdo/1.0-incubator-M2"
  name="helloworldDSDOservice">

   <dbsdo:import.sdo  location="wsdl/helloworld.wsdl"/>


    <service name="HelloWorldWebServiceDSDO">
        <interface.wsdl interface="http://helloworld#wsdl.interface(HelloWorld)" 
        wsdli:wsdlLocation="http://helloworld wsdl/helloworld.wsdl" />
        <!--<interface.java interface="helloworld.HelloWorldService"/>-->
        
    <binding.ws endpoint="http://helloworld#wsdl.endpoint(HelloWorldService/
        HelloWorldSoapPort)" 
        location="wsdl/helloworld.wsdl" uri="HWWSSDO"/>
          
        <reference>HelloWorldServiceDSDOComponent</reference>
    </service>

    <component name="HelloWorldServiceDSDOComponent">
        <implementation.java class="helloworld.HelloWorldImpl"/>
    </component>
</composite>

接下来定义 Web 服务提供者。通常,WSDL 文件用于定义所提供的服务、输入和输出消息,以及传递到这些消息中的数据所对应的类型。清单 4 提供了代表示例服务的简单 helloworld WSDL 文件。

清单 4. helloworld.wsdl:描述服务的 WSDL 文件
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://helloworld" xmlns:tns="http://helloworld" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:xsd=http://www.w3.org/2001/XMLSchema name="helloworld"> 

    <wsdl:types>         
          <schema elementFormDefault="qualified" 
targetNamespace="http://helloworld" 
xmlns="http://www.w3.org/2001/XMLSchema"> 

            <complexType name="Person">
                <sequence>
                    <element name="firstName" type="string"/>
                    <element name="lastName" type="string"/>
                    <element name="greeting" type="string"/>
                </sequence>
            </complexType>
            
            <element name="getGreetings">                 
                 <complexType>                     
                      <sequence>                         
                           <element name="name" 
type="xsd:string"/>                     
                                  </sequence>                 
                            </complexType>             
                     </element> 
                     
                     <element name="getGreetingsResponse">                 
                           <complexType>                     
                                 <sequence>                         
                                       <element name="getGreetingsReturn" 
type="xsd:anyType"/>                     
                                   </sequence>                 
                              </complexType>             
                       </element>         
                  </schema>     
             </wsdl:types> 
             
             <wsdl:message name="getGreetingsRequest">         
                   <wsdl:part element="tns:getGreetings" name="parameters"/>     
             </wsdl:message> 
             
             <wsdl:message name="getGreetingsResponse">         
                  <wsdl:part element="tns:getGreetingsResponse" 
name="parameters"/>     
             </wsdl:message> 


               <wsdl:portType name="HelloWorldService">         
                  <wsdl:operation name="getGreetings">             
                       <wsdl:input message="tns:getGreetingsRequest" 
name="getGreetingsRequest"/>
                       <wsdl:output message="tns:getGreetingsResponse" 
name="getGreetingsResponse"/>
                   </wsdl:operation>
              </wsdl:portType>
              

              <wsdl:binding name="HelloWorldSoapBinding" 
type="tns:HelloWorldService">
                <wsdlsoap:binding style="document" 
transport="http://schemas.xmlsoap.org/soap/http"/>         
                <wsdl:operation name="getGreetings">             
                     <wsdlsoap:operation soapAction=""/>             
                     <wsdl:input name="getGreetingsRequest">
                           <wsdlsoap:body use="literal"/>             
                     </wsdl:input>             
                     <wsdl:output name="getGreetingsResponse">
                           <wsdlsoap:body use="literal"/>             
                     </wsdl:output>        
                 </wsdl:operation>     
              </wsdl:binding> 
              
              <wsdl:service name="HelloWorldService">         
                 <wsdl:port binding="tns:HelloWorldSoapBinding" 
name="HelloWorldSoapPort">             
                           <wsdlsoap:address location=""/>         
                  </wsdl:port>     
               </wsdl:service> 
               
</wsdl:definitions>

在清单 4 中,使用 WSDL 1.1 portType <wsdl:portType> 定义了名为 HelloWorldService 的服务接口。此服务接口包含一个名为 getGreetings 的操作。为了调用此操作,客户机将传递消息 getGreetingsRequest 并接收消息 getGreetingsResponse。消息 getGreetingsRequest 的类型定义为 xsd:string,而消息 getGreetingsResponse 的类型定义为 xsd:anyType。根据 SDO 2.1 规范中的规定,xsd:string 映射到 SDO String 类型,而 xsd:anyType 映射到 SDO DataObject 类型。表 2 表示 XSD 类型、SDO 类型和 Java 实例类之间的映射。

表 2. XSD 类型、SDO 类型和 Java 实例类之间的映射
XSD 类型SDO 类型Java 实例类
xsd:stringStringjava.lang.String
xsd:anyTypeDataObjectcommonj.sdo.DataObject

清单 5 中所示的 Java 接口描述服务所提供的操作以及输入和输出,这些内容与清单 4 中的 WSDL 文档描述的 <wsdl:PortType:> 定义对应。可以使用 Apache Tuscany 的服务组件体系结构实现提供的工具由 Apache Axis 2.0 或手动生成此 Java 接口。

清单 5. helloworld.wsdl——HelloWorldService.java:描述服务的 Java 接口
package helloworld;

@Service
@Remotable
@DataType(name = "commonj.sdo.DataObject")
public interface HelloWorldService {		 
    public commonj.sdo.DataObject getGreetings(
    java.lang.String param0) throws java.rmi.RemoteException;
}

清单 5 定义了名为 getGreetings 的单个远程服务操作,该操作接受字符串作为输入,并向客户机返回任何类型的 SDO。@DataType 是一个 Annotation,用于描述 Apache Tuscany 的 Java 方法或属性的输入和输出参数的数据绑定类型。

现在创建 Java 接口的实现,如清单 6 中所示。

清单 6. HelloWorldImpl.java:服务的 Java 实现
package helloworld;

import java.rmi.RemoteException;

import org.osoa.sca.annotations.Service;

import commonj.sdo.DataObject;
import commonj.sdo.helper.DataFactory;

/**
 * This class implements the HelloWorld service.
 */
@Service(HelloWorldService.class)
public class HelloWorldImpl implements HelloWorldService {

    DataFactory dataFactory = DataFactory.INSTANCE;

    public commonj.sdo.DataObject getGreetings(String name) throws RemoteException {
        DataObject person = dataFactory.create("http://helloworld", "Person");
        String[] names = name.split(" ");

        person.setString("firstName", names[0]);
        person.setString("lastName", names[1]);
        person.setString("greeting", "Hello");

        return person;
    }
}

清单 6 中的代码显示了 HelloWorldService 接口的实现,可允许服务使用者使用个人的全名调用 getGreetings 操作或方法。该代码预期接受包含该人的问候消息的 SDO。

在此 getGreetings(String) 方法中,将使用 DataFactory.create 方法并传入命名空间(在 WSDL 中定义)及类型的名称(在本例中为 Person)来创建新 SDO。这将创建 Person 类型的 SDO。然后使用 commonj.sdo.DataObject 提供的 API 来设置 Person 类型的属性。

HelloWorld Web 客户机——Web 服务使用者

在清单 7 中所示的 Web 服务应用程序的客户机部分中,HelloWorld.jsp 首先使用 HTML <Form> 标记提示用户输入名称。输入了用户全名后,JSP 会转向 Web 服务提供者 (HelloWorldService) 检索用户的问候信息并进行显示。为此,JSP 首先通过调用 CurrentCompositeContext.getContext() 来获取 SCA 组合的上下文。接下来,JSP 按照在 default.scdl 中定义的 SCA 组件名称查找 HelloWorldService。然后,JSP 调用前面部分中描述的 getGreetings 操作。将向 JSP 返回包含三个属性(firstNamelastNamegreeting)的动态 SDO,以向用户显示。

清单 7. HelloWorld.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
             pageEncoding="ISO-8859-1" session="true" autoFlush="true"
             isThreadSafe="true" isErrorPage="false"
             import="java.lang.reflect.Method"
             import="java.io.PrintWriter"
             import="java.io.StringWriter"
             import="org.osoa.sca.CurrentCompositeContext"
             import="org.osoa.sca.CompositeContext"
	     import="commonj.sdo.DataObject"
	     import="commonj.sdo.helper.XSDHelper"
	     import="helloworld.HelloWorldService"
            %>
    <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <META name="GENERATOR" content="IBM Software Development Platform">
    <TITLE>HelloWorld Dynamic SDO Web Application Sample</TITLE>
    <%
        String name = request.getParameter("name");
    %>
</HEAD>

<BODY>
<H2>HelloWorld Dynamic SDO Web Application Sample</H2>

<P>&nbsp;</P>

<FORM action="HelloWorld.jsp" method="get">Name
    please:&nbsp;&nbsp;&nbsp; <INPUT type="text" id="i1" name="name"
                                     size="40" maxlength="220"
                                     value="<%= null == name ? "John Doe" : name %>"> <BR>
    <BR>
    <INPUT type="submit" name="submit" value="Submit"></FORM>
<BR>

<%
    try {
        if (null != name) {
            CompositeContext compositeContext = CurrentCompositeContext.getContext();
            System.out.println("compositeContext is: " + compositeContext);
            
		// Locate the HelloWorld service
        HelloWorldService helloworldService = 
        (HelloWorldService)compositeContext.locateService
        (HelloWorldService.class, "HelloWorldServiceComponentDSDOClient");
        
        // Invoke the HelloWorld service
        DataObject person = 
        <HR>

<P><%=person.get("greeting")%>&nbsp;<%=person.get("firstName")%>
&nbsp;<%=person.get("lastName")%>!!!!
	<%}
	}catch(Exception e){
    	e.printStackTrace();
		StringWriter sw= new StringWriter();
		PrintWriter pw= new PrintWriter(sw);
		
		e.printStackTrace(pw);
		pw.flush();	
%>
		Whoops!<BR clear="all">
<PRE>
		Exception "<%=e.getClass().getName()%>"
		Exception message: "<%=e.getMessage()%>"
		<BR clear="all">
		<%=sw.toString() %>
</PRE>
<%
	}%>
</BODY>
</HTML>

为了从动态 SDO 检索属性,必须按照与创建数据对象时设置属性类似的方法使用 commonj.sdo.DataObject 接口提供的 API。

运行示例应用程序的步骤

随本文提供的 hwddynamicsdo-service.jarhwddynamicsdo-reference.war 示例应用程序包含 HelloWorld Web 服务及客户机应用程序的源代码和二进制文件,可以将其部署在 IBM WebSphere Application Server Version 6.1 Feature Pack for SOA 的 Beta1 版上。示例应用程序提供了本文中的概念的工作示例,遵循了图 2 中所示的关系图。下面的步骤说明了如何安装和运行这些应用程序。在此示例中,WebSphere 实例使用 9080 缺省端口作为 HTTP 端口。(请参见下面的说明。)

要安装 HelloWorld Web 服务应用程序,请执行以下步骤:

  1. 安装 WAS 6.1。
  2. 安装 IBM WebSphere Application Server Version 6.1 Feature Pack for SOA 的 Beta1 版。
  3. 将 hwddynamicsdo-service.jar 下载到 <WAS_ROOT>/installableApps 目录,如 C:/WebSphere/AppServer/installableApps
  4. 使用以下步骤安装 HelloWorld Web 服务应用程序:
    1. 运行 wsadmin –lang jython –conntype NONE,以进入 wsadmin 控制台。
    2. 运行 AdminTask.listBLAs(),以列出所有已安装的 SOA 应用程序。
    3. 运行 AdminTask.createBLA(‘-name hwdsdo –source C:/WebSphere/AppServer/installableApps/hwddynamicsdo-service.jar’),以安装应用程序。
    4. 运行 AdminConfig.save(),以保存已安装的应用程序配置。
    5. 如果需要删除已安装的 SOA 应用程序,请运行 AdminTask.deleteBLA(‘-blaID WebSphere:appName=hwdsdo’)
  5. 启动服务器。
  6. 将浏览器指向 http://localhost:9080/HWWSSDO/services。浏览器应该显示图 3 中所示的页面。这表明 HelloWorld Web 服务应用程序在正确运行。
图 3. 正在运行的 HelloWorld Web 服务
正在运行的 HelloWorld Web 服务
正在运行的 HelloWorld Web 服务

要安装 HelloWorld Web 客户机应用程序,请执行以下步骤:

  1. 将浏览器指向 http://localhost:9060/ibm/console/,以启动 WebSphere 管理控制台。
  2. 登录后,选择 Applications,然后选择 Install New Application。这将安装 <WAS_ROOT>/installableApps/hwddynamicsdo-reference.war 中的 HelloWorld Web 客户机应用程序,如图 4 中所示。接受所有安装缺省设置。
  3. 选择 Applications,然后选择 Enterprise Applications,以启动应用程序。选中 hwddynamicsdo-reference.war 旁边的复选框,然后单击页面顶部的 Start
  4. 将浏览器指向 http://localhost:9080/hwddynamicsdo。
  5. 单击 Submit。将看到图 5 中所示的页面。
图 4. HelloWorld Web 客户机应用程序安装
HelloWorld Web 客户机应用程序安装
HelloWorld Web 客户机应用程序安装
图 5. 运行 HelloWorld Web 客户机的结果
运行 HelloWorld Web 客户机的结果
运行 HelloWorld Web 客户机的结果

结束语

本文简要介绍了服务数据对象,说明了 SDO 的动态和静态数据 API 间的主要区别,并重点说明了使用动态 SDO 来将数据从 Web 服务提供者传输到客户机的应用程序的要点。另外还提供了可部署在 WebSphere Application Server Version 6.1 Feature Pack for SOA 的 Beta1 版上的一个示例应用程序,还对此技术进行了说明。


下载资源


相关主题


评论

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services, WebSphere
ArticleID=220876
ArticleTitle=如何在 Web 服务中使用 Service Data Objects 2.1 的动态数据 API
publish-date=05162007