1 开始前
该文档针对Windows平台已经安装完ws-core-4.0.x的用户。在继续进行之前保证已经设置环境变量GLOBUS_LOCATION,指向ws-core-4.0.x的安装目录(在我的系统中为D:\ws-core-4.0.0)。同时,为了方便,最好将D:\ws-core-4.0.0\bin目录添加到系统目录PATH中。这样可以方便我们执行Globus自带的一些命令。
此外,还需要安装Python脚本执行程序。目前最新的版本是2.4.1,可以到服务器Softwares目录下去下载。另外,还需要正确安装并配置Ant,它将负责生成最终的GAR文件。同时,文档中的EXAMPLES_DIR指代例子的安装目录。
2 最简单的例子
要编写、部署这样一个Web Service需要一下5个简单的步骤:
l 通过编写WSDL文件,定义服务的接口
l 通过编写Java代码,实现上述接口定义的服务
l 编写WSDD部署描述符和JNDI
l 使用ant编译并形成GAR(Globus ARchive)文件
l 通过GT4自带的工具部署服务
下面,我们分别介绍以上五个步骤:
2.1 定义服务接口
通过编写WSDL文件,来定义我们提供服务的接口。这样,客户端通过解析WSDL文件,从而了解服务的具体定义和调用情况。
2.1.1 文件代码
具体的文件(Math.wsdl)如下:
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="MathService"
targetNamespace="http://www.globus.org/namespaces/examples/core/MathService_instance"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://www.globus.org/namespaces/examples/core/MathService_instance"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsrp="http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd"
xmlns:wsrpw="http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl"
xmlns:wsdlpp="http://www.globus.org/namespaces/2004/10/WSDLPreprocessor"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:import
namespace=
"http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl"
location="../../wsrf/properties/WS-ResourceProperties.wsdl" />
<!--============================================================
T Y P E S
============================================================-->
<types>
<xsd:schema targetNamespace="http://www.globus.org/namespaces/examples/core/MathService_instance"
xmlns:tns="http://www.globus.org/namespaces/examples/core/MathService_instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- REQUESTS AND RESPONSES -->
<xsd:element name="add" type="xsd:int"/>
<xsd:element name="addResponse">
<xsd:complexType/>
</xsd:element>
<xsd:element name="subtract" type="xsd:int"/>
<xsd:element name="subtractResponse">
<xsd:complexType/>
</xsd:element>
<xsd:element name="getValueRP">
<xsd:complexType/>
</xsd:element>
<xsd:element name="getValueRPResponse" type="xsd:int"/>
<!-- RESOURCE PROPERTIES -->
<xsd:element name="Value" type="xsd:int"/>
<xsd:element name="LastOp" type="xsd:string"/>
<xsd:element name="MathResourceProperties">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="tns:Value" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="tns:LastOp" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<!--============================================================
M E S S A G E S
============================================================-->
<message name="AddInputMessage">
<part name="parameters" element="tns:add"/>
</message>
<message name="AddOutputMessage">
<part name="parameters" element="tns:addResponse"/>
</message>
<message name="SubtractInputMessage">
<part name="parameters" element="tns:subtract"/>
</message>
<message name="SubtractOutputMessage">
<part name="parameters" element="tns:subtractResponse"/>
</message>
<message name="GetValueRPInputMessage">
<part name="parameters" element="tns:getValueRP"/>
</message>
<message name="GetValueRPOutputMessage">
<part name="parameters" element="tns:getValueRPResponse"/>
</message>
<!--============================================================
P O R T T Y P E
============================================================-->
<portType name="MathPortType"
wsdlpp:extends="wsrpw:GetResourceProperty"
wsrp:ResourceProperties="tns:MathResourceProperties">
<operation name="add">
<input message="tns:AddInputMessage"/>
<output message="tns:AddOutputMessage"/>
</operation>
<operation name="subtract">
<input message="tns:SubtractInputMessage"/>
<output message="tns:SubtractOutputMessage"/>
</operation>
<operation name="getValueRP">
<input message="tns:GetValueRPInputMessage"/>
<output message="tns:GetValueRPOutputMessage"/>
</operation>
</portType>
</definitions>
该文件被保存在EXAMPLES_DIR\schema\examples\MathService_instance目录下。
2.1.2 名字空间的映射
通过下面文件(EXAMPLES_DIR\namespace2package.mappings)来完成WSDL中名字空间的映射:
http\://www.globus.org/namespaces/examples/core/MathService_instance=org.globus.examples.stubs.MathService_instance
http\://www.globus.org/namespaces/examples/core/MathService_instance/bindings=org.globus.examples.stubs.MathService_instance.bindings
http\://www.globus.org/namespaces/examples/core/MathService_instance/service=org.globus.examples.stubs.MathService_instance.service
2.2 实现服务
下面就实现前面接口中定义的。
2.2.1 QName接口
我们会频繁的通过服务的Qualified Name来访问给服务,所以将这个Qualified Name定义到一个接口(EXAMPLES_DIR \org\globus\examples\services\core\first\impl)中:
// MathQNames.java
package org.globus.examples.services.core.first.impl;
import javax.xml.namespace.QName;
public interface MathQNames {
public static final String NS = "http://www.globus.org/namespaces/examples/core/MathService_instance";
public static final QName RP_VALUE = new QName(NS, "Value");
public static final QName RP_LASTOP = new QName(NS, "LastOp");
public static final QName RESOURCE_PROPERTIES = new QName(NS,
"MathResourceProperties");
}
2.2.2 服务的实现
在这个最简单的例子中,我们将所有的有关服务(service)和资源(resource)的代码都放入一个类中。但是,通常情况下,会有两个类文件。一个用来存放有关服务的代码,一个用来存放有关资源的代码。
类的代码如下:
package org.globus.examples.services.core.first.impl;
import java.rmi.RemoteException;
import org.globus.wsrf.Resource;
import org.globus.wsrf.ResourceProperties;
import org.globus.wsrf.ResourceProperty;
import org.globus.wsrf.ResourcePropertySet;
import org.globus.wsrf.impl.ReflectionResourceProperty;
import org.globus.wsrf.impl.SimpleResourcePropertySet;
import org.globus.examples.stubs.MathService_instance.AddResponse;
import org.globus.examples.stubs.MathService_instance.SubtractResponse;
import org.globus.examples.stubs.MathService_instance.GetValueRP;
public class MathService implements Resource, ResourceProperties {
/* Resource Property set */
private ResourcePropertySet propSet;
/* Resource properties */
private int value;
private String lastOp;
/* Constructor. Initializes RPs */
public MathService() throws RemoteException {
/* Create RP set */
this.propSet = new SimpleResourcePropertySet(
MathQNames.RESOURCE_PROPERTIES);
/* Initialize the RP's */
try {
ResourceProperty valueRP = new ReflectionResourceProperty(
MathQNames.RP_VALUE, "Value", this);
this.propSet.add(valueRP);
setValue(0);
ResourceProperty lastOpRP = new ReflectionResourceProperty(
MathQNames.RP_LASTOP, "LastOp", this);
this.propSet.add(lastOpRP);
setLastOp("NONE");
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/* Get/Setters for the RPs */
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getLastOp() {
return lastOp;
}
public void setLastOp(String lastOp) {
this.lastOp = lastOp;
}
/* Remotely-accessible operations */
public AddResponse add(int a) throws RemoteException {
value += a;
lastOp = "ADDITION";
return new AddResponse();
}
public SubtractResponse subtract(int a) throws RemoteException {
value -= a;
lastOp = "SUBTRACTION";
return new SubtractResponse();
}
public int getValueRP(GetValueRP params) throws RemoteException {
return value;
}
/* Required by interface ResourceProperties */
public ResourcePropertySet getResourcePropertySet() {
return this.propSet;
}
}
2.3 在Web服务部署描述符中配置服务
我们需要把些好的Web服务部署到Web容器中去,才能让客户端对服务进行访问。这一步我们是通过Web服务部署描述符(WSDD)来实现的。
2.3.1 WSDD(Web Service Deploy Descriptor)
<?xml version="1.0" encoding="UTF-8"?>
<deployment name="defaultServerConfig"
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<service name="examples/core/first/MathService" provider="Handler" use="literal" style="document">
<parameter name="className" value="org.globus.examples.services.core.first.impl.MathService"/>
<wsdlFile>share/schema/examples/MathService_instance/Math_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>
</deployment>
我们将这个文件(deploy-server.wsdd)放于EXAMPLES_DIR\ org\globus\examples\services\core\first目录下。
2.3.2 JNDI
虽然这里面我们使用最简单的一个例子,但是JNDI文件还是必须的,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<jndiConfig xmlns="http://wsrf.globus.org/jndi/config">
<service name="examples/core/first/MathService">
<resource name="home" type="org.globus.wsrf.impl.ServiceResourceHome">
<resourceParams>
<parameter>
<name>factory</name>
<value>org.globus.wsrf.jndi.BeanFactory</value>
</parameter>
</resourceParams>
</resource>
</service>
</jndiConfig>
2.4 创建GAR文件
在这里,我们需要Ant和Python的支持。首先,简单的将源文件中的build.xml、build.mappings以及globus-build-service.py三个文件拷贝到EXAMPLES_DIR目录下。在命令行上加入如下命令创建GAR文件:
globus-build-service.py first
输出的结果像下面这样:
Buildfile: build.xml
init:
[mkdir] Created dir: D:\test\build
[mkdir] Created dir: D:\test\build\classes
[mkdir] Created dir: D:\test\build\lib
[mkdir] Created dir: D:\test\build\stubs-org_globus_examples_services_core_f
irst
[mkdir] Created dir: D:\test\build\stubs-org_globus_examples_services_core_f
irst\src
[mkdir] Created dir: D:\test\build\stubs-org_globus_examples_services_core_f
irst\classes
[mkdir] Created dir: D:\test\build\stubs
[mkdir] Created dir: D:\test\build\stubs\classes
[mkdir] Created dir: D:\test\build\schema
[copy] Copying 30 files to D:\test\build\schema
[mkdir] Created dir: D:\test\org\globus\examples\services\core\first\etc
flatten:
WSDLUptodate:
flatten:
[echo] Processing WSDL in Math.wsdl
[java] Retrieving document at 'D:\test\build\schema\examples\MathService_in
stance\Math.wsdl'.
[java] Retrieving document at '../../wsrf/properties/WS-ResourceProperties.
wsdl', relative to 'file:/D:/test/build/schema/examples/MathService_instance/Mat
h.wsdl'.
generateBindings:
bindingUptodate:
generateBinding:
[echo] Generating bindings for Math_flattened.wsdl
stubs:
mergePackageMapping:
[echo] Merging D:\test\namespace2package.mappings
generateStubs:
[echo] Generating stubs from Math_service.wsdl
[java] {http://schemas.xmlsoap.org/ws/2004/03/addressing}Action already exi
sts
factoryFlatten:
generateFactoryBindings:
factoryStubs:
compileStubs:
[javac] Compiling 10 source files to D:\test\build\stubs-org_globus_examples
_services_core_first\classes
[copy] Copying 10 files to D:\test\build\stubs\classes
jarStubs:
[jar] Building jar: D:\test\build\lib\org_globus_examples_services_core_fi
rst_stubs.jar
compile:
[javac] Compiling 2 source files to D:\test\build\classes
jar:
[jar] Building jar: D:\test\build\lib\org_globus_examples_services_core_fi
rst.jar
dist:
makeGar:
testJars:
copyJars:
[copy] Copying 2 files to D:\test\tmp\gar\lib
testSchema:
copySchema:
[copy] Copying 4 files to D:\test\tmp\gar\schema
testEtc:
copyEtc:
[copy] Copied 1 empty directory to 1 empty directory under D:\test\tmp\gar\
etc
[antcall] Parent project doesn't contain any reference '${garshare.id}'
testShare:
copyShare:
[antcall] Parent project doesn't contain any reference '${gardocs.id}'
testDocs:
copyDocs:
[antcall] Parent project doesn't contain any reference '${garbin.id}'
testBin:
copyBin:
[copy] Copying 1 file to D:\test\tmp\gar
[copy] Warning: Could not find file D:\test\org\globus\examples\services\co
re\first\deploy-client.wsdd to copy.
[copy] Copying 1 file to D:\test\tmp\gar
[jar] Building jar: D:\test\org_globus_examples_services_core_first.gar
[delete] Deleting directory D:\test\tmp\gar
all:
BUILD SUCCESSFUL
Total time: 25 seconds
如果没有出现错误,会在根目录下面创建一个名为org_globus_examples_services_core_first.gar的文件。
2.5 部署服务到容器中去
此时,部署服务的工具是由GT4提供的。因为我们已经将%GLOBUS_LOCATION\bin目录加入的系统路径中去,所以我们可以在服务台上直接输入下面命令,就可以方便地将上面编写的服务部署到服务器上去:
globus-deploy-gar org_globus_examples_services_core_first.gar
2.6 小结
通过以上五步,我们就开发了最简单的一个基于GT4的Web服务。下面,我们将通过编写简单的例子对该服务进行测试。
3 测试
3.1 编写客户端程序
我们将编写一个简单的客户端程序,并将其放在EXAMPLES_DIR \org\globus\examples\clients\MathService_instance\Client.java。它的全部代码如下:
package org.globus.examples.clients.MathService_instance;
import org.apache.axis.message.addressing.Address;
import org.apache.axis.message.addressing.EndpointReferenceType;
import org.globus.examples.stubs.MathService_instance.MathPortType;
import org.globus.examples.stubs.MathService_instance.GetValueRP;
import org.globus.examples.stubs.MathService_instance.service.MathServiceAddressingLocator;
public class Client {
public static void main(String[] args) {
MathServiceAddressingLocator locator = new MathServiceAddressingLocator();
try {
String serviceURI = args[0];
// Create endpoint reference to service
EndpointReferenceType endpoint = new EndpointReferenceType();
endpoint.setAddress(new Address(serviceURI));
MathPortType math = locator.getMathPortTypePort(endpoint);
// Get PortType
//math = locator.getMathPortTypePort(endpoint);
// Perform an addition
math.add(10);
// Perform another addition
math.add(5);
// Access value
System.out.println("Current value: "
+ math.getValueRP(new GetValueRP()));
// Perform a subtraction
math.subtract(5);
// Access value
System.out.println("Current value: "
+ math.getValueRP(new GetValueRP()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2 编译客户端程序
3.2.1 设置环境变量
在编译客户端程序之前,我们需要将GT4自带的类库导入到系统变量CLASSPATH下。为此,GT4给我们提供了一个批处理文件,我们只需要简单的在GLOBUS_LACATION\etc目录下执行如下命令即可:
3.2.2 编译
接下来,到EXAMPLES_DIR目录下,执行下面的命令来编译客户端程序:
javac -classpath ./build/stubs/classes/;%CLASSPATH% org/globus/examples/clients/MathService_instance/Client.java
注:在PDF文档中给出的批处理命令是Unix/Linux系统下面的,需要对其进行更改才可以在Windows系统下正确执行!
3.2.3 启动容器
最后,我们需要启动容器。这时,最好另外开启一个命令行窗口,再输入如下命令:
globus-start-container –nosec
这时输出的结果类似下面的代码:
Starting SOAP server at: http://202.115.30.208:8080/wsrf/services/
With the following services:
[1]: http://202.115.30.208:8080/wsrf/services/Version
[2]: http://202.115.30.208:8080/wsrf/services/NotificationConsumerService
[3]: http://202.115.30.208:8080/wsrf/services/NotificationTestService
[4]: http://202.115.30.208:8080/wsrf/services/SecureCounterService
[5]: http://202.115.30.208:8080/wsrf/services/PersistenceTestSubscriptionManager
[6]: http://202.115.30.208:8080/wsrf/services/gsi/AuthenticationService
[7]: http://202.115.30.208:8080/wsrf/services/TestRPCService
[8]: http://202.115.30.208:8080/wsrf/services/SubscriptionManagerService
[9]: http://202.115.30.208:8080/wsrf/services/ManagementService
[10]: http://202.115.30.208:8080/wsrf/services/TestServiceWrongWSDL
[11]: http://202.115.30.208:8080/wsrf/services/WidgetService
[12]: http://202.115.30.208:8080/wsrf/services/SampleAuthzService
[13]: http://202.115.30.208:8080/wsrf/services/examples/core/first/MathService
[14]: http://202.115.30.208:8080/wsrf/services/AuthzCalloutTestService
[15]: http://202.115.30.208:8080/wsrf/services/WidgetNotificationService
[16]: http://202.115.30.208:8080/wsrf/services/AdminService
[17]: http://202.115.30.208:8080/wsrf/services/ShutdownService
[18]: http://202.115.30.208:8080/wsrf/services/ContainerRegistryService
[19]: http://202.115.30.208:8080/wsrf/services/CounterService
[20]: http://202.115.30.208:8080/wsrf/services/TestService
[21]: http://202.115.30.208:8080/wsrf/services/TestAuthzService
[22]: http://202.115.30.208:8080/wsrf/services/SecurityTestService
[23]: http://202.115.30.208:8080/wsrf/services/ContainerRegistryEntryService
[24]: http://202.115.30.208:8080/wsrf/services/NotificationConsumerFactoryServic
e
[25]: http://202.115.30.208:8080/wsrf/services/TestServiceRequest
这时,注意观察,我们刚才部署的服务是否正常启动。
注:默认容器需要占用8080端口,如果系统上安装了Tomcat这样应用服务器,也有可能也占用了该端口。所以可以将Tomcat服务暂时关闭。
3.3 测试结果
如果发现了类似上面红色代码那段,表示容器中已经成功启动了我们发布的服务。此时,在原先的那个命令行下输入如下命令来执行我们写的客户端程序:
java -classpath ./build/stubs/classes/;%CLASSPATH% org.globus.examples.clients.MathService_instance.Client http://127.0.0.1:8080/wsrf/services/examples/core/first/MathService
注:在PDF文档中给出的批处理命令是Unix/Linux系统下面的,需要对其进行更改才可以在Windows系统下正确执行!
如果我们连续执行两次上面的命令,会输出如下结果:
D:\test>java -classpath ./build/stubs/classes/;%CLASSPATH% org.globus.examples.c
lients.MathService_instance.Client http://127.0.0.1:8080/wsrf/services/examples/
core/first/MathService
Current value: 15
Current value: 10
D:\test>java -classpath ./build/stubs/classes/;%CLASSPATH% org.globus.examples.c
lients.MathService_instance.Client http://127.0.0.1:8080/wsrf/services/examples/
core/first/MathService
Current value: 25
Current value: 20
3.4 小结
通过上面的测试,我们可以验证Web服务的正确性。同时要注意Windows和Unix/Linxu系统下命令书写的差别。
来自:http://www.blogjava.net/sk8boy/archive/2006/12/15/14573.html