??xml version="1.0" encoding="utf-8" standalone="yes"?>用Globus Toolkit 4构徏WEB服务
xzzhouhu 发表?2005-12-06
点击?1041 评论?0 评h(hun):3/1
关键?Globus Toolkit
摘要:
本文主要介绍?jin)通过一U新的方法来构徏企业软gQ即通过调整Globus Toolkit 4实现的网D的概念来实现。GT4是一U可以通过开攄格服务架构(OGSIQ来实施的开放资源。这U实施主要目的是为网格服务架构提供了(jin)依据Q同时也可以为别的网格服务架构实施提供参考。本文详l介l了(jin)GT4中JAVA的核?j)服务,q些服务具备提供代管|格服务实时q行环境的能力,当然q些|格服务都是由JAVA写的。实时运行环境在|格服务的应用和|络承蝲之间和传输协议引擎之间vC(jin)协调的作用?文章工具
版权声明QQ何获得Matrix授权的网站,转蝲时请务必以超链接形式标明文章原始出处和作者信息及(qing)本声?/span>
作?Birali Hakizumwami;xzzhouhu
原文地址:http://www.onjava.com/pub/a/onjava/2005/10/19/constructing-web-services-with-globus-toolkit.html
中文地址:http://www.matrix.org.cn/resource/article/44/44032_Globus_Toolkit.html
关键词:(x) Globus Toolkit
摘要Q?/b>
本文主要介绍?jin)通过一U新的方法来构徏企业软gQ即通过调整Globus Toolkit 4实现的网D的概念来实现。GT4是一U可以通过开攄格服务架构(OGSIQ来实施的开放资源。这U实施主要目的是为网格服务架构提供了(jin)依据Q同时也可以为别的网格服务架构实施提供参考。本文详l介l了(jin)GT4中JAVA的核?j)服务,q些服务具备提供代管|格服务实时q行环境的能力,当然q些|格服务都是由JAVA写的。实时运行环境在|格服务的应用和|络承蝲之间和传输协议引擎之间vC(jin)协调的作用?br />
一Q网格的定义
|格的定义:(x)
|格是收集网l上所有可用的分布式计资源提供给最l用hl徏成一个巨大的计算pȝ。网D给分布式计提供了(jin)一U全新的Ҏ(gu)Q不仅在跨地且在跨l织Q机器结构和软g限制Q给q接到网格的每个用户提供更多的资源,计算Z间的协作和信息访问。分布式资源Q像计算周期Q存储和信息Q可以在|格中的M地区讉KQ同时也可以在网g提供q些服务供其他用戯问。这p通过在每个独立的l织或资源之间进行安全的协调资源׃nQ共同徏立一个动态虚拟组l机构?br />
二.Globus Toolkit Version 4
在本文中Q我们主要讨论GT4中JAVA的核?j)服务。(如图1Q,q些服裉峁┝舜芡IԎ袷凳痹诵谢肪车哪芰ΑJ凳痹诵谢肪吃谟没Фㄒ宓挠τ梅窈虶T4的核?j)服务之_(d)|络承蝲和传输协议引擎之间vC(jin)协调的作用。GT4核心(j)服务q提供了(jin)E序开发支持的功能Q包括开攑ּ开发模式和讉K|格服务的实玎ͼ像GRAM(Grid Resource Allocation Management,|格资源理)。应用GT4强有力的理由是因ؓ(f)它是建立在现有的WEB服务标准和技术的基础上,像SOAP和W(xu)SDL。网格服务提供的接口都是通过WSDL来描q的。GT4提供?jin)一个Y件仓库,像安全支持,软g的探索,软g的资源管理,软g的调用,软g之间的通信Q异常处理和数据理{?
Q图1Q?br />
?主要描述?jin)在服务器端的GT4中的主要lgl构。这只是GT4所提供功能的一部分Q我们只是认为它很适合本文。GT4l构׃个网格容器组成,|格容器主要用来理所有部|的WEB服务Q诏I于每个WEB服务的运行周期。GT4使用apache的axis作ؓ(f)它的WEB服务的引擎来处理所有的SOAP消息QJAX-RPC QJava API for XML-Based RPCQ处理和W(xu)EB服务的配|?br />
三.h偿还例子Q?/span>
我们列Dq样一个例子,主要惛_大家展示在企业内部如何通过Globus Toolkit 来解决不同类操作pȝ之间q行融合。在企业内部Q有些应用可能是原来L遗留下来的,技术比较落后,有些应用已经采用?jin)现代技术,像J2EE。甚x们采用最先进的技术在一个企业内部的应用之间q行信息׃n也要面(f)巨大的挑战。图2l出?jin)这样一个例子,在一个抵押机构内Q在h偿还信息处理和会(x)计部门信息处理之间的交互Q?
Q图2Q?br />
?x)计部门使用甌h处理服务来申误ƾ?br />
Z(jin)创徏和部|网格服务,我们需要:(x)
*通过创徏WSDL文g来定义服务的接口
*用JAVA来实?br />*通过创徏WSDD文g来定义服务的部v参数
*使用ANT~译源代码ƈ生成GAR文g
*用GT4分发工具部vGAR文g
我们必须使用从上往下的Ҏ(gu)来创建网格服务,Q图3Q?br />
q种Ҏ(gu)首先从提供WSDL文g开始,在WSDL文g中包括对WEB服务的抽象定义,包括服务cdQ消息类型和端口cd。从WSDL文档开始ƈҎ(gu)WSDL文档创徏?jin)JAVA模型Q从而导致与其他pȝ更好交互?br />
我们使用GT4 toolkit自带的工hq行服务的绑定和产生客户D需要的根类。这U方法的下一步就是提供接口的实现?br />
h偿还服务处理定义Q?/b>
对于h偿还服务处理的例子的接口cd我们定义为loan.wsdlQ它描述?jin)贷Ƒցq服务所提供的三个部分的操作Q申误ƾ,h处理和获得贷ƾ)(j)。首先我们描q贷Ƒցq服务的h和响应:(x)<types>
<xsd:element name="createLoan">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="loanNumber" type="xsd:int"/>
<xsd:element name="amountUPB" type="xsd:double"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="createLoanResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="returnValue" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="processLoanPayment">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="loanNumber" type="xsd:int"/>
<xsd:element name="amount" type="xsd:double"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="processLoanPaymentResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="returnValue" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="getLoan">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="loanNumber" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="getLoanResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="returnValue" type="tns:LoanType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</types>
我们在文?loan.xsd.中定义了(jin)h的数据类型,我们通过使用?import <xsd:import schemaLocation="loan.xsd"/> ”可以直接将loan.xsd.文g导入到文件loan.wsdl 中,q且用它作ؓ(f)获得h操作q回的类?br /><complexType name="LoanType">
<sequence>
<element name="loanNumber" type="int"/>
<element name="UPB" type="double"/>
<element name="status" type="string"/>
<element name="createDate" type="string"/>
</sequence>
</complexType>
下一步,我们要定义所有的消息服务。一条消息元素可能由一个或多个部分l成Q消息元素的每个部分对应一个参敎ͼq且q有一个类型属性。消息既可以是一个请求消息(输入消息Q,也可以是一个响应消息(输出消息Q?br /><message name="CreateLoanInputMessage">
<part name="parameters" element="tns:createLoan"/>
</message>
<message name="CreateLoanOutputMessage">
<part name="parameters" element="tns:createLoanResponse"/>
</message>
<message name="ProcessLoanPaymentInputMessage">
<part name="parameters" element="tns:processLoanPayment"/>
</message>
<message name="ProcessLoanPaymentOutputMessage">
<part name="parameters"
element="tns:processLoanPaymentResponse"/>
</message>
<message name="GetLoanInputMessage">
<part name="parameters" element="tns:getLoan"/>
</message>
<message name="GetLoanOutputMessage">
<part name="parameters" element="tns:getLoanResponse"/>
</message>
最后我们定义所有的端口cdQ每个接口类型定义了(jin)一个或多个操作来用当前的操作元素Q每个独立的操作元素又定义了(jin)一个操作和与操作有联系的消息的输入输出。在一个端口类型内操作元素定义?jin)端口类型内所有调用方法的语法?br /><portType name="LoanPortType">
<operation name="createLoan">
<input message="tns:CreateLoanInputMessage"/>
<output message="tns:CreateLoanOutputMessage"/>
<fault name="Fault" message="ogsi:FaultMessage"/>
</operation>
<operation name="processLoanPayment">
<input message="tns:ProcessLoanPaymentInputMessage"/>
<output message="tns:ProcessLoanPaymentOutputMessage"/>
<fault name="Fault" message="ogsi:FaultMessage"/>
</operation>
<operation name="getLoan">
<input message="tns:GetLoanInputMessage"/>
<output message="tns:GetLoanOutputMessage"/>
<fault name="Fault" message="ogsi:FaultMessage"/>
</operation>
</portType>
服务的实玎ͼ(x)
在前面的步骤中,l端h端口cd的接口已l生,在定义这些端口类型的接口Ӟ所有的q程操作都要设ؓ(f)publicQƈ且抛出java.rmi.RemoteException。在本文中给Z(jin)LoanServiceImplc,主要实现h端口cd的接口,q些实现要用到前面所讲到的用loan.wsdl文g所生成的根cR?br />public class LoanServiceImpl implements LoanPortType
其中LoanServiceImpl 所实现的方法定义在LoanPortType接口中,createLoanҎ(gu)在生一个createLoan对象的构造器中要获取一个贷ƾ数字作为它的参数?br />public CreateLoanResponse createLoan(CreateLoan cl)
throws java.rmi.RemoteException
public ProcessLoanPaymentResponse processLoanPayment(ProcessLoanPayment plp)
throws java.rmi.RemoteException
public GetLoanResponse getLoan(GetLoan gl) throws java.rmi.RemoteException
请参考完整代码详l描q方法的实现?br />
~译q创?偿还处理的WEB服务Q?br />下面我们介绍通过以下步骤来创建易部v的GT4打包文档。Ant在编译本文所提供文g时所产生的build.xml中包含了(jin)ant的执行Q务的步骤。在build.xml中ant的执行Q务调用GT4中的antdQ这些Q务伴随着GT4的发布可以在~译文g中找到?br />%GLOBUS_LOCATION%/share/globus_wsrf_common/build-packages.xml
%GLOBUS_LOCATION%/share/globus_wsrf_tools/build-stubs.xml
%GLOBUS_LOCATION%/share/schema
~译GT4中易部v的GAR文g
Z(jin)创徏易部|的|格打包文gQloan.garQ我们通过以下步骤来实玎ͼ(x)Q这些步骤与builder.xml中的antd是一致的Q:(x)
· 与WSDL文gl定
· 通过WSDL 文g生成一个根c,在安装时Q提供一个特D文件来对不同的命名I间和包之间q行映射Q这些包与表g的目录结构一致?br />· ~译根类
· ~译接口c?br />· 用JAR压羃接口c,和根cM?loan.jar and loan_stubs.jar).
· 通过创徏部v描述文gdeploy-server.wsdd.来生成易部v的GAR文gQloan.gar
请参考源代码中完整的build.xml文gQ通过以上步骤来实Cpd的ant~译d。GT4描述我们的WEB服务文gdeploy-server.wsdd想q样Q?br /><service name="loan/impl/LoanService" provider="Handler"
use="literal" style="document">
<parameter name="className" value="loan.impl.LoanServiceImpl"/>
<wsdlFile>share/schema/loan/Loan_service.wsdl</wsdlFile>
<parameter name="allowedMethods" value="*"/>
<parameter name="handlerClass"
value="org.globus.axis.providers.RPCProvider"/>
<parameter name="scope" value="Application"/>
<parameter name="providers" value="GetRPProvider"/>
<parameter name="loadOnStartup" value="true"/>
</service>
让我们来介绍一下deploy-server.wsdd中的一些参敎ͼ(x)
服务名称Q指定我们所提供的WEB服务的\径,我们它与WEB服务容器的地址相结合v来,我们?x)得到WEB服务的完整的URL。ؓ(f)?jin)便于测试,使用独立的GT4容器QURL像q样Q?br />
http://localhost:8080/wsrf/services/loan/impl/LoanService
cdQ指实现服务接口的类(LoanServiceImpl).
WSDL文gQ告诉GT4中的WEB服务容器对于当前的WEB服务的WSDL文g在那里可以找到。WSDL文gLoan_service.wsdl是在GT4 从loan.wsdlq行ANT时自动生的?br />启动时装载:(x)如果我们需要服务在WEB服务容器启动时就开始装载,允许我们控制服务的装载?br />
部vGAR文gQ?/b>
GAR文gloan.gar包含?jin)所有的文g和W(xu)EB服务器需要的部v信息Q我们用GT4部v工具Q?br />
%GLOBUS_LOCATION%/bin/globus-deploy-gar $PROJECT_HOME/loan.gar
拯文档文gQloan.wsdlQ编译的根类Q编译的接口实现Qloan.wsddQ到GT4容器的目录下适当位置?br />
试借贷Ƒ֤理实?/b>
在图1描述?jin)如何将h方的子系l和hl算子系l作为借贷ƄWEB服务的客L(fng)Q现在我们就在GT4|格服务容器中创建和部vWEB服务Q我们需要用一个客L(fng)q行试Q测试用例模拟一个贷ƾ事Ӟ一个贷ƾ月度偿q事件和一个贷ƾ还清事件。作为客L(fng)来说Q他们希望WEB服务的URIQ统一资源标识W)(j)能够作ؓ(f)客户端访问WEB服务的依据。客L(fng)的程序要独立的进行编译,下面来描q客L(fng)讉KWEB服务的主要步骤:(x)
创徏一l端引用cd对象Q来代表l端引用的贷ƾ服务。我们的l端引用只需要服务的URIQ?br />EndpointReferenceType endpoint = new EndpointReferenceType();
endpoint.setAddress(new Address(serviceURI));
下一步,我们要获得引用服务的端口cdQ这需要一个根c调用LoanServiceAddressingLocator, LoanServiceAddressingLocator主要是用来维持客L(fng)与WEB服务之间的通信和获得引用贷Ƅ口的cd?br />LoanServiceAddressingLocator locator = new LoanServiceAddressingLocator();
LoanPortType loanPT = locator.getLoanPortTypePort(endpoint);
一旦我们获得这个引用,我们可以作ؓ(f)本地对象来操作WEB服务。例如,调用q程的创建操作,我们仅仅需要在h端口cd中用创建方法?br />CreateLoanResponse clr = loanPT.createLoan(new CreateLoan(amount, loanNumber));
请参考附件中完整的客L(fng)代码。在~译客户端之前,请保证运行下面的脚本Q以便于GT4的发布:(x)
%GLOBUS_LOCATION%/etc/globus-devel-env.bat
globus-devel-env.bat文g主要是将Globus的类库注册到pȝ的classpath中,因ؓ(f)客户端是作ؓ(f)独立的应用来~译的,同样Q要保证在编译客L(fng)的目录中所攄的已~译的根cL能通过classpath扑ֈQ因此我们的客户端可以访问服务器端的根类Q像LoanServiceAddressingLocator?br />
启动|格容器
使用下面的命令来启动|格容器Q?br />
%GLOBUS_LOCATION%/bin/globus-start-container –nosec
-nosec参数主要是ؓ(f)?jin)简化测试,略去安全讄。如果网格容器启动成功,你将?x)看到已部v的服务的URI列表Q如果LoanService正确的部|Ԍ在已部v的服务的列表中有下面的一行:(x)
[13]: http://localhost:8080/wsrf/services/loan/impl/LoanService
试借贷Ƒ֤理的WEB服务
通过客户端进行测试,我们假设有以下操作:(x)甌hQ偿q贷ƾ,q清h?br />
· 创徏一个初始化h~号?00q且q有12000未还
java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService createLoan 100 120000
Loan 100 created successfully.
· 假定两个月偿q,每个月还$1100Q本例不考虑利息的计)(j)
java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService processLoanPayment 100 1100
Loan 100 processed successfully.
java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService processLoanPayment 100 1100
Loan 100 processed successfully.
· 查看h的状?br />java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService getLoanData 100
Loan Data
Create Date Mon Jun 06 16:41:06 EDT 2005
Unpaid Principal Balance 117800.0
Status ACTIVE
· W三个月q清余款Q?117,800Q?br />java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService processLoanPayment 100 117800
Loan 100 processed successfully
· 查看h状?br />java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService getLoanData 100
Loan Data
Create Date Mon Jun 06 16:41:06 EDT 2005
Unpaid Principal Balance 0.0
Status PAIDOFF
l束语:(x)
本文主要描述?jin)在Z现有的WEB服务标准的基上,如何调整GT4|格l构来创Z个网格服务应用。尽GT4已经主要的应用在大型的科学计问题上Q但是在一个企业内部它可以作ؓ(f)实现面向服务l构QSOAQ的一U方法。本文主要是通过一个简单的实例来描q如何用GT4中的JAVA核心(j)服务来创建和部v一个网格服务,但是q没有覆盖到更多的其他的更先q的关于如何使用|格服务概念Q向|格服务的分配和理Q文件传输的可靠性,|格异常和安全?br />
资源
·本文的示例代?/a>
·Matrix-Java开发者社?http://www.matrix.org.cn
·onjava.com:onjava.com
]]>
归到commons下面.主要的开发h员是QCraig McClanahan。Craig McClanahan是我比较崇拜的开?br />人员之一。他开发了(jin)无数的OpenSource目。包括大安知道的Tomcat、Struts同时q是jsp,servlet
Spec制定成员之一Qƈ是Java Server Face(jsf)的Team Leader.在此向Craig McClanahan致敬?br />Digester把xml文g解析为Java Object有点象Castor。在本文中我使用一个简单的例子来介l?br />Digester的用,详细的文档看下面的连?http://jakarta.apache.org/commons/digester.html
我做一个最单的例子Q因为Digester功能比较强大Q需要更详细的例子参阅下面的文章
http://www.onjava.com/pub/a/onjava/2002/10/23/digester.html?page=1
http://www.javaworld.com/javaworld/jw-10-2002/jw-1025-opensourceprofile.html
使用Digester,需要jakarta下的如下? BeanUtils, Collections, Logging.
Digester的下载地址:
http://apache.linuxforum.net/dist/jakarta/commons/digester/binaries/
目前版本?.4
二:(x)开始用Digester.
现在有一个如下的xml文g
user.xml(e:/user.xml)
-------
<users>
<name>BASIC</name>
<pass>Example Basic Authentication Area</pass>
</users>
一个如下的java Object
com.henry.test.digester.BaseObject
-----------------------------------
public class BaseObject {
private String name = "";
private String pass = "";
/**
* Returns the name.
* @return String
*/
public String getName() {
return name;
}
/**
* Returns the pass.
* @return String
*/
public String getPass() {
return pass;
}
/**
* Sets the name.
* @param name The name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* Sets the pass.
* @param pass The pass to set
*/
public void setPass(String pass) {
this.pass = pass;
}
public void setInfo(String name,String pass){
this.name = name;
this.pass = pass;
}
public void info() {
log("name:" + name + "...pass :" + pass);
}
private void log(String str) {
System.out.println(str);
}
}
现在我们要把user.xml里面的内容解析ؓ(f)一个BaseObject.
在以前我使用JDOM做解析。代码估计需?00行左叟?br />现在我用Digester完成此项工作Q你?x)发现非常的?gu)Q而且很简单?/p>
三:(x)解析xml文g
Test.java
---------------
//import org.apache.commons.digester.Digester;
...............
public void parse() {
Digester digester = new Digester();
//创徏Digester对象
BaseObject obj = new BaseObject();
try {
digester.addObjectCreate("users", "com.henry.test.digester.BaseObject");
//创徏一个对象com.henry.test.digester.BaseObject
//对象对应的xml中ؓ(f)容users下的配置
digester.addCallMethod("users/name", "setName", 0);
//调用对象的方法setNameq把users/name节点的g为对象方法的参数
digester.addCallMethod("users/pass", "setPass", 0);
/*下面是调用setInfo(String,String)讄信息的?br />*digester.addObjectCreate("users", "com.henry.test.digester.BaseObject");
*digester.addCallMethod("users","setInfo",2);
*digester.addCallParam("users/name",0);
*digester.addCallParam("users/pass",1);
*/
//上面的两D代码功能一样都是用反实现对象的创徏和方法的调用
//W二D|一个方法有多个参数的情?br />obj=(BaseObject)(digester.parse("e:/user.xml"));
obj.info();
} catch (Exception ex) {
log(ex.getMessage());
}
}
............
上面的如此简单的代码可以实C个配|文件的解析。不错吧?/p>
四:(x)l束?br />xml解析的方式有很多U,单的q用jdom可以解决问?再不行用Xerces{等。但对于一?br />配置文g的解析用Digester不失Z个很好的选择.单,而且基本可以满需要。够用ؓ(f)原则.
我没有去比较使用Digester,jdom的运行效率,因ؓ(f)实在是没有必要。但我用过jdom去解析,虽然
很简单,但肯定比Digester复杂.
如果你对Digester有更q理解Q记得联pLQ?a href="mailto:henry_ge@mail.com">henry_ge@mail.com.如果上面的文章有什么错?br />或者不I也请l我指出Q发送到上面的地址.