This article introduces a new way of building enterprise software by leveraging grid computing concepts implemented by the Globus Toolkit version 4 (GT4). GT4 is an open source implementation of the Open Grid Services Infrastructure (OGSI). The implementation is intended to serve as a proof of concept for OGSI, and to be used as a reference for other implementations. This article addresses only the GT4 Java core services, which provide a run-time environment capable of hosting grid services written in Java. The run-time environment mediates between the application and the underlying network, and transport protocol engines.
A grid is a collection of distributed computing resources available over a local or wide area network that appear to an end user or application as one large virtual computing system. Grid computing is an approach to distributed computing that spans not only locations but also organizations, machine architectures, and software boundaries to provide increased power, collaboration, and information access to everyone connected to a grid. Distributed resources, such as cycles, storage, and information, can be accessed from and provided to any location in the grid. The vision is to create virtual dynamic organizations through secure, coordinated resource sharing among individuals, institutions, and resources.
In this article, we will only focus on the GT4 Java core services (Figure 1). These services offer a run-time environment capable of hosting grid services. The run-time environment mediates between the user-defined application services and the GT4 core services, underlying network, and transport protocol engines. GT4 Core also provides development support, including programming models for exposing and accessing grid service implementations such as GRAM (Grid Resource Allocation Management). One of the compelling reasons to use GT4 is that it builds upon existing web services standards and technologies like SOAP and WSDL. All of the grid service interfaces are exposed in WSDL format. GT4 provides software libraries that support security, discovery, resource management, invocation, communication, exception handling, data management, etc.

Figure 1. GT4 Java architecture
Figure 1 show the major architectural components of the server side of GT4. This is just a subset of the functionality that GT4 provides and that we use for this article. The GT4 architecture consists of a grid container to manage all of the deployed web services throughout their lifecycles. The GT4 grid container uses Apache AXIS as its web services engine to handle all of the SOAP message processing, JAX-RPC handler processing, and web services configuration.
|
Related Reading Java Web Services in a Nutshell |
|
We provide this example to show how using the Globus Toolkit can solve the integration challenges of heterogeneous systems within the enterprise. Some applications may be mainframe legacy applications and some may use modern technologies such as J2EE. Even when using up-to-date technologies, sharing information between different applications within the same enterprise can present a tremendous challenge. Figure 2 shows an example of an interaction between loan payment processing and the accounting departments within a mortgage organization. The accounting department uses the loan payment processing service to account for the loan.

Figure 2. Loan processing grid architecture (click for full-size image)
To create and deploy a grid service, we need to:
We use the top-down approach (Figure 3) to create the grid service. This approach starts by providing a WSDL file that contains the abstract definition of the service including the types, messages and portTypes. Starting with a document/literal WSDL and then generating the Java artifacts from that leads to the most interoperability.

Figure 3. Top-down approach
We use some of the tools that come with the GT4 toolkit to generate the binding and stubs. The next step with this approach is to provide the implementation of the interfaces.
|
The port types for the Loan Payment Processing example are defined the a file loan.wsdl. It describes three operations (createLoan, processLoanPayment, and getLoan) that the loan payment processing service will provide. First, let's describe the requests/responses:
<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>
We define the loan data type in a file, loan.xsd. We use the import <xsd:import schemaLocation="loan.xsd"/> directive to import this file into loan.wsdl and use it as a return type for the getLoan operation.
<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>
Next we define all of the messages. A Message element consists of one or more part sections. Each part element corresponds to a parameter. Each part has a type attribute. Messages can be either Requests (input messages) or Responses (output messages).
<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>
Finally, we define all of the port types. A port type defines one or more operations using the operation element. Each unique operation element defines an operation and the input/output messages associated with the operation. The operation elements within a port type define the syntax for calling all methods in the port type.
<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>
|
In the previous step, the LoanPortType endpoint interface was generated. All remotely available operations must be public and throw java.rmi.RemoteException, as defined in the PortType interface. In this section, we provide a class, LoanServiceImpl, that implements the LoanPortType interface. The implementation uses stub classes that were generated from the loan.wsdl file from the previous section.
public class LoanServiceImpl implements LoanPortType
The LoanServiceImpl class implement the methods defined in the LoanPortType interface. The createLoan method takes a loanNumber as a parameter in the constructor of the generated CreateLoan object.
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
Please refer to the full source code in the Resources section for the details of the methods' implementations.
To build a deployable GT4 archive file, we follow the steps described below. The build.xml Ant build file provided with this article contains the tasks to perform these steps. The Ant tasks in build.xml call the following GT4 Ant tasks that can be found in the build files that come with the GT4 distribution:
%GLOBUS_LOCATION%/share/globus_wsrf_common/build-packages.xml
%GLOBUS_LOCATION%/share/globus_wsrf_tools/build-stubs.xml
%GLOBUS_LOCATION%/share/schema
To build our deployable grid archive file (GAR), loan.gar, we follow the following steps (these steps correspond to the Ant tasks in build.xml):
Please refer to the full build.xml in the source code for the complete list of Ant build tasks for the above steps. The GT4 deployment descriptor deploy-server.wsdd for our web service will look like this:
<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>
Let's describe some parameters found in the deploy-server.wsdd file:
Service name: Specifies the location where our web service will be found. If we combine this with the base address of our web services container, we will get the full URI of our web service. For testing purposes using the GT4 standalone container, the URL looks like this:
http://localhost:8080/wsrf/services/loan/impl/LoanService
ClassName: Refers to the class that implements the service interface (LoanServiceImpl).
WSDL file: Tells the GT4 web services container where the WSDL file for this service can be found. This WSDL file, Loan_service.wsdl, is generated automatically by a GT4 Ant task from loan.wsdl.
Load on startup: Allows us to control if we want the service to be loaded as soon as the container is started.
The GAR file loan.gar contains all of the files and information the web server needs to deploy the web service. We use the GT4 deployment tool:
%GLOBUS_LOCATION%/bin/globus-deploy-gar $PROJECT_HOME/loan.gar
to copy the archive files (loan.wsdl, compiled stubs, compiled implementation, loan.wsdd) into the appropriate server location directory tree of the GT4 container.
|
Figure 1 described how the loan origination subsystem and the loan accounting subsystem can act as clients to the loan payment processing web services. Now that we have build and deploy our web service in the GT4 grid container, we need to test the services with a client program. Test cases simulate a loan creation event, a loan monthly payment activity event, and a loan pay-off event. The client expects the service URI as one of its arguments from the command line. The client program is compiled separately. Following are a description of the main steps to implement the client to call our web services:
Create an EndpointReferenceType object representing the endpoint reference of the loan service. Our endpoint reference only needs the service's URI.
EndpointReferenceType endpoint = new EndpointReferenceType();
endpoint.setAddress(new Address(serviceURI));
Next, we obtain a reference to the service's portType. This is done with a stub class called LoanServiceAddressingLocator, which takes care of contacting the service (given its endpoint) and getting a reference to the loan portType.
LoanServiceAddressingLocator locator = new LoanServiceAddressingLocator();
LoanPortType loanPT = locator.getLoanPortTypePort(endpoint);
Once we have that reference, we can work with the web service as if it were a local object. For example, to invoke the remote create operation, we simply have to use the create method in the LoanPortType object.
CreateLoanResponse clr = loanPT.createLoan(new CreateLoan(amount, loanNumber));
Please see the full code listing in the attached source code for the client. Before compiling the client, make sure you run the following script that comes with the GT4 distribution:
%GLOBUS_LOCATION%/etc/globus-devel-env.bat
The globus-devel-env.bat script takes care of putting all of the Globus libraries into the CLASSPATH, because the client is being compiled as a standalone application. Also, make sure that the CLASSPATH used to compile the client contains the directory where all of the compiled stub classes are placed, so our client can access generated stub classes such as LoanServiceAddressingLocator.
Use the following GT4 command to start the grid container:
%GLOBUS_LOCATION%/bin/globus-start-container -nosec
The -nosec option disable the security configuration to simplify testing. If the container is started successfully, you'll see a list with the URIs of all the deployed services. If our LoanService is correctly deployed, the following line appears in the list of deployed services (assuming a default GT4 installation):
[13]: http://localhost:8080/wsrf/services/loan/impl/LoanService
To test the service using the client, we consider the following scenarios: creating a loan, making payments, and paying off the loan.
java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService createLoan 100 120000
Loan 100 created successfully.
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.
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
java Client http://172.24.15.29:8080/wsrf/services/loan/impl/LoanService processLoanPayment 100 117800
Loan 100 processed successfully.
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
This article described how the GT4 grid infrastructure can be leveraged to create application grid services based on existing web services standards. Although GT4 has been primarily used to solve large scientific computational problems, it can be used as a way to implement a service-oriented architecture within an enterprise. This article shows through a simple example how to create and deploy a grid service using the GT4 Core Java Services. It does not cover the more advanced concepts on how to use other grid services, such as the Grid Resource Allocation and Management (GRAM), Reliable File Transfer (RFT), notification, or security.
Birali Hakizumwami is currently working as an application architect.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.