利用Sybase EAServer和开发工具快速开发Web Service


(转载自Sybase中国网站,http://www.sybase.com.cn/)

什么是Web Service
 
  Web Service是指由企业发布的完成其特别商务需求的在线应用服务,其他公司、合作伙伴的应用软件能够通过Internet来动态访问并使用这些在线服务。它为未来全球的电子商务发展提供了新的标准和架构。
Web Service的运行模式
 

  Web Service是独立的、模块化的应用,能够通过因特网来描述、发布、定位以及调用。在Web Service的体系架构中包括三个角色:服务提供者(Service Provider)、服务请求者(Service Requestor)、服务注册器(Service Registry)。角色间主要有三个操作:发布(Publish)、查找(Find)、绑定(Bind)。

如下图:

  WebService中涉及两个部分:服务本身和对服务的描述。典型的应用过程是:服务提供者开发一个通过网络可以被访问的服务,然后将服务的描述注册到服务注册器或者发送给服务请求者;服务请求者通过查找动作在本地或服务注册器中检索服务描述,找到后,通过绑定就可以使用该项服务。
 
Web Service的整体架构
 
  上图是从分层的角度来描述Web Service的整体架构。和网络的分层结构相同,上一层需要下一层的支持。而安全性、可管理性、服务质量则需要在各个层次都有所体现。Web Service设计到一些新的规范,如:UDDI(统一描述、发现和集成)、WSDL(Web Service描述语言)、WSFL(Web Service Flow Language)、SOAP(简单对象访问协议)等。通过这样一个层次分明的架构,Web Service希望达到一个目标,就是:实现动态的应用集成,将电子商务推向智能、和更加实用的阶段。
 
Web Service的特点
 
Web Service 是下一代分布式系统的核心,它具有如下特点:
 
  • 完好的封装性: Web服务既然是一种部署在Web上的对象,自然具备对象的良好封装性,对于使用者而言,他仅能看到该服务的描述。
  •  
  • 松散耦合: 这一特征也是源于对象/组件技术,当一个Web服务的实现发生变更的时候,调用者是不会感到这一点的,对于调用者来说,只要Web服务的调用接口不变,Web服务的实现任何变更对他们来说都是透明的,甚至是当Web服务的实现平台从J2EE迁移到了.NET或者是相反的迁移流程,用户都可以对此一无所知。对于松散耦合而言,尤其是在Internet环境下的Web服务而言,需要有一种适合Internet环境的消息交换协议。而XML/SOAP正是目前最为适合的消息交换协议。
  •  
  • 使用协约的规范性: 这一特征从对象而来,但相比一般对象其界面规范更加规范化和易于机器理解。首先,作为Web服务,对象界面所提供的功能应当使用标准的描述语言来描述(比如WSDL);其次,由标准描述语言描述的服务界面应当是能够被发现的,因此这一描述文档需要被存储在私有的或公共的注册库里面。同时,使用标准描述语言描述的使用协约将不仅仅是服务界面,它将被延伸到Web服务的聚合、跨Web服务的事务、工作流等,而这些又都需要服务质量(QoS)的保障。其次,我们知道安全机制对于松散耦合的对象环境的重要性,因此我们需要对诸如授权认证、数据完整性(比如签名机制)、消息源认证以及事务的不可否认性等运用规范的方法来描述、传输和交换。最后,在所有层次的处理都应当是可管理的,因此需要对管理协约运用同样的机制。
  •  
  • 使用标准协议规范: 作为Web服务,其所有公共的协约完全需要使用开放的标准协议进行描述、传输和交换。这些标准协议具有完全免费的规范,以便由任意方进行实现。一般而言,绝大多数规范将最终有W3C或OASIS作为最终版本的发布方和维护方。
  •  
  • 高度可集成能力: 由于Web服务采取简单的、易理解的标准Web协议作为组件界面描述和协同描述规范,完全屏蔽了不同软件平台的差异,无论是CORBA、DCOM还是EJB都可以通过这一种标准的协议进行互操作,实现了在当前环境下最高的可集成性。
  •  
  • 开放性: Web Service可以与其他Web Service进行交互。它具有语言和平台无关性。支持CORBA、EJB、DCOM 等多种组件标准。支持各种通讯媒体如:HTTP、SMTP、MQ、FTP、RMI over IIOP等。
  •  
    简单对象访问协议SOAP
     
      SOAP是一种基于XML的不依赖传输协议的表示层协议,用来在应用程序之间方便地以对象的形式交换数据。在SOAP的下层,可以是HTTP/HTTP,也可以是SMTP/POP3,还可以是为一些应用而专门设计的特殊的通信协议。
     
      SOAP以XML形式提供了一个简单、轻量的用于在分散或分布环境中交换结构化和类型信息的机制。SOAP本身并没有定义任何应用程序语义,如编程模型或特定语义的实现;实际上,它通过提供一个有标准组件的包模型和在模块中进行数据编码的机制,定义了一个简单的表示应用程序语义的机制,这使SOAP能够用于从消息传递到RPC的各种系统。
     
    SOAP包括三个部分:
     
  • SOAP封装结构:定义了一个整体框架,以表示消息中包含什么内容,谁来处理这些内容以及这些内容是可选的或是必需的。
  •  
  • SOAP编码规则:定义了用以交换应用程序定义的数据类型的实例的一系列机制。
  •  
  • SOAP RPC表示:定义了一个用来表示远程过程调用和应答的协定。
  •  
      在SOAP封装、SOAP编码规则和SOAP RPC协定之外,这个规范还定义了两个协议的绑定,描述了在有或没有HTTP扩展框架的情况下,SOAP消息如何包含在HTTP消息中被传送。
     
    统一描述、发现和集成协议UDDI
     
      UDDI是一套基于Web的、分布式的、为Web Service提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。
     
      UDDI的核心组件是UDDI商业注册,它使用一个XML文档来描述企业及其提供的Web Service。从概念上来说,UDDI商业注册所提供的信息包含三个部分:
     
  • 白页(White Page): 包括了地址、联系方法和已知的企业标识。
  •  
  • 黄页(Yellow page):包括了基于标准分类法的行业类别。
  •  
  • 绿页(Green Page):包括了关于该企业所提供的Web Service的技术信息,其形式可能是一些指向文件或URL的指针,而这些文件或URL是为服务发现机制服务的。
  •  
      有的UDDI商业注册信息都存储在UDDI商业注册中心。通过使用UDDI的发现服务,企业可以单独注册那些希望被别的企业发现的自身提供的Web Service。企业可以通过UDDI商业注册中心的Web界面,或使用实现了"UDDI Programmer's API标准所描述的编程接口的工具,将信息加入到UDDI的商业注册中心。UDDI商业注册中心在逻辑上是集中的,在物理上是分布式的,由多个根节点组成,相互之间按一定规则进行数据同步。当一个企业在UDDI商业注册中心的一个实例中实施注册后,其注册信息会被自动复制到其他UDDI 根节点,于是就能被任何希望发现这些Web Service的人所发现。
     
    Web服务描述语言WSDL
     
      随着通信协议和消息格式在Web中的标准化,以某种格式化的方法描述通信变得越来越重要,其实现的可能性也越来越大。用WSDL定义的一套XML语法描述的网络服务方式满足了这种需求。WSDL把网络服务定义成一个能交换消息的通信端点集。WSDL服务为分布式系统提供了帮助文档,同时该服务也可作为自动实现应用间通信的解决方案。
     
      一个WSDL文档将服务定义为一个网络端点的集合,或者端口的集合。在WSDL里,端点及消息的抽象定义与它们具体的网络实现和数据格式绑定是分离的。这样就可以重用这些抽象定义:消息,需要交换的数据的抽象描述;端口类型,操作的抽象集合。针对一个特定端口类型的具体协议和数据格式规范构成一个可重用的绑定。一个端口定义成网络地址和可重用的绑定的联接,端口的集合定义为服务。因此,一个WSDL文档在定义网络服务时使用如下的元素:
     
    类型:使用某种类型系统(如XSD)定义数据类型。
     
    消息:通信数据抽象的有类型的定义 。
     
    操作:服务支持的动作的抽象描述。
     
    端口类型:一个操作的抽象集合,该操作由一个或多个端点支持。
     
    绑定:针对一个特定端口类型的具体的协议规范和数据格式规范。
     
    端口:一个单一的端点,定义成一个绑定和一个网络地址的联接。
     
    服务:相关的端点的集合。
     
    利用Sybase应用服务器和PowerBuilder、PowerJ开发SOAP应用
     
    安装 SOAP
     
    从Apache 站点下载SOAP:
    http://xml.apache.org/dist/soap/version-2.2/soap-bin-2.2.zip
    将soap-bin-2.2.zip解压缩到c:\soap目录。
    www.Sybase.com上有一篇文章可以帮助一步一步的帮助你如何将Apache SOAP 2.2安装到Sybase EAServer 3.6.1 或4.0。
    http://my.sybase.com/detail?id=1013352
     
    用PowerBuilder制作服务器端组件
     
    建立一个目录,如C:\soap,我们可以把PowerBuilder和PowerJ的工程文件(WorkSpace)放到这个目录中。
    运行应用服务器EAServer 4。
    打开PowerBuilder 8,建立一个新的工程文件,取名为soap(File-New->workspace)。
    建立一个新的EAServer Component目标(Target) (File _ New -> Target),如下图:
    按照向导的提示一步一步向下走,把下面规定的内容添到相应的项中。其余的用默认值既可。
     
    Application Name: soapapp
    EAServer Component Name: soapapp
    Package Name: soap
    Specify transaction support: check Auto Demarcation/Deactivation
    Project: p_deploy
    开PB组件n_soapapp,建立一个新的函数,getmessage(),返回值为String类型,内容为“Hello world”
    打开p_deploy项目,将组件提交到应用服务器上。只需点击下图中箭头所指的图标。
    打开Jaguar Manager,用jagadmin 连接并进入。找到Soap 包(package), 你可以看到刚才做的组件soap。如图:
    编辑组件的属性:
    com.sybase.jaguar.component.home = soap::soapappHome
    生成 EJB Stubs and Skeletons:
    Generate Stubs: checked
    Generate Java Stubs: checked
    Generate Java Files: check radio button
    Compile Java Stubs: checked
    Generate Skeletons: checked
    用PowerJ设计SOAP 的客户端软件
     
    在PowerJ中, 建立一个新的工作区,取名为soap (File - New Workspace),将它保存到 C:\soap中.
    建立一个新的Java Classes Target (File _ New… from within Workspace View).
    按照向导的顺序一步一步做,将下面的内容添到相应的位置:(没有规定的用默认值)
    Target name: soapClasses
     
    建立一个新的Standard Class
    按照向导的顺序一步一步做,将下面的内容添到相应的位置:(没有规定的用默认值)
    Class Name: PBClient
     
    在Classpath中增加一个路径 C:\soap-2_2\lib\soap.jar 如下图:
    以下为 PBClient.java 的代码:
     
    The Client (PBClient.java)
    import java.net.*;
    import org.apache.soap.*;
    import org.apache.soap.rpc.*;
     
    public class PBClient {
     
        public static void main (String[] args) throws Exception {
            if (args.length != 1 ) {
                 System.err.println ("Usage: java " + + PBClient.class.getName () +"              SOAP-router-URL);
                 System.exit (1);
            }
     
            // Process the arguments.
            URL url = new URL (args[0]);
            // Build the call.
            Call call = new Call ();
            Call.setTargetObjectURI ("urn:testprovider);
            Call.setMethodName ("getmessage);
            // make the call: note that the action URI is empty because the
            // XML-SOAP rpc router does not need this. This may change in the
            // future.
            Response resp = call.invoke (/* router URL */ url, /* actionURI */ "");
     
            // Check the response.
            if (resp.generatedFault ()) {
                Fault fault = resp.getFault ();
                System.out.println ("Ouch, the call failed: );
                System.out.println (" Fault Code = + fault.getFaultCode ());
                System.out.println (" Fault String = + fault.getFaultString ());
            } else {
                Parameter result = resp.getReturnValue ();
                System.out.println ( "Done: + result.getValue());
            }
        }
    }
     
     
    配置SOAP服务器方服务:
    我们需要将已经做好的PB组件(我们已经生成了EJB的Stub和Skeleton)注册到SOAP上,该组件运行在EAServer上。
     
    我们建立如下一个XML文件:
    Deployment descriptor (DeploymentDescriptor.xml):
    <?xml version="1.0"?>
    isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment
        id="urn:testprovider">
        isd:provider type="org.apache.soap.providers.StatelessEJBProvider"
           scope="Application"
           methods="create">
        isd:java class="soap/soapapp"/>
        <isd:option key="FullHomeInterfaceName" value="soap.soapappHome" />
        <isd:option key="ContextProviderURL" value="iiop://localhost:9000" />
        <isd:option key="FullContextFactoryName" value="com.sybase.ejb.InitialContextFactory"     />
        </isd:provider>
        <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
    </isd:service>
     
    我们可以用这个文件将该组件提交给SOAP。
     
    Deploy.cmd:
    set CLASSPATH=.; C:\soap-2_2\lib\soap.jar
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\java\lib\easj2ee.jar
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\java\classes\crimson.jar
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\java\classes\xalan.jar
    echo This test assumes a server URL of http://localhost:8080/soap/servlet/rpcrouter
    echo Deploying the service...
    java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter deploy
    DeploymentDescriptor.xml
    echo .
    echo Verify that it's there
    java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter list
    这个文件可以用来提交任何正确的DeploymentDescriptor.xml到运行在LocalHost:8080的EAServer SOAP上。
     
    运行结果如下:
    你可以看到urn:testprovider被提交到SOAP,还有一个urn:stringservice被同时提交。
     
    测试Web Service
    我们用如下的Run.bat来测试该Web Service。
    run.bat:
    @echo off
    cls
    set CLASSPATH=.;C:\soap-2_2\lib\soap.jar
    19
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\java\lib\easj2ee.jar
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\java\classes\crimson.jar
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\java\classes\xalan.jar
    set CLASSPATH=%CLASSPATH%;%JAGUAR%\html\classes
    cd debug
    @echo on
    java -classpath "%CLASSPATH%; PBClient http://localhost:8090/soap/servlet/rpcrouter
    @echo off
    cd..
     
    注意,我们需要将以上三个文件Import到soapClasses目标下。如下图:
    另外,为了看到客户端与服务之间的信息传递,我们需要启动Apache SOAP所带的工具,在一个DOS窗口中输入如下命令:
    java org.apache.soap.util.net.TcpTunnelGui 8090 localhost 8080
    注意:在系统变量ClassPath中应加上 C:\soap-2_2\lib\soap.jar
     
    运行结果如下:
    可能出现的问题:
    如果运行中XML-parsers出现了问题,可以将%SYBASE%\Shared\Sun\jdk122\jre\lib\ext\jaxp.jar 删除,然后再试。
    我遇到的一个问题是crimson.jar文件的版本不对:
     
    文件名          大小
    crimson.jar       187.162
    soap.jar        220.703
    xalan.jar        801.714
     
    结论
     
    我们可以用Sybase的应用服务器EAServer和开发工具(PowerBuilder和PowerJ)来快速的开发SOAP的应用。
     
     
    如果有技术问题可以与张晓联系: 68568488-5159  xiao@sybase.com