The first step in writing a Grid Service (or a Web Service) is to define the service interface. We need to specify what our service is going to provide to the outer world. At this point we're not concerned with the inner workings of that service (what algorithms it uses, what databases it will access, etc.) We just need to know what operations will be available to our users. Remember that, in Web/Grid Services lingo, the service interface is usually called the port type (usually written portType).
As we saw in A short introduction to Web Services, there is a special XML language which can be used to specify what operations a web service offers: the Web Service Description Language (WSDL). So what we need to do in this step is write a description of our MathService using WSDL. However, this is not entirely true. In GT3 we have two options:
Writing the WSDL directly. This is the most versatile option. If we write WSDL directly, we have total control over the description of our service's portType. However, it is not the most user-friendly one, since WSDL is a rather verbose language.
Generating WSDL from a Java interface. We can generate WSDL automatically from a Java interface. This is the easiest option, but not the most versatile (since very complicated interfaces are not always converted correctly to WSDL).
At first sight, it might seem that starting with an interface language (such as Java interface or an IDL interface) might be the best option, since it is the most user-friendly. In fact, if we wanted to define our interface in Java, we could simply write the following:
public interface Math { public void add(int a); public void subtract(int a); public int getValue(); }
...and we'd be finished with step 1! However, we are going to start with a WSDL description of the interface, even if it is a bit harder to understand than using a Java interface. The main reason for this is that, although Java interfaces might be easier to write and understand, in the long run they produce much more problems than WSDL. So, the sooner we start writing WSDL, the better.
Actually, what we're going to write is not WSDL, but Grid WSDL (or GWSDL), which is an extension of WSDL used in the OGSI specification (and, therefore, in the Globus Toolkit). This 'extended' WSDL supports all the features described in the What is a Grid Service? page which are not supported in plain Web Services (and, therefore, in plain WSDL). In a moment we'll see the exact differences between WSDL and GWSDL. Before that, we'll take a good look at the GWSDL code which is equivalent to the Java interface shown above.
However, the goal of this page is not to give a detailed explanation of how to write a GWSDL file, but rather to present the GWSDL file for this particular example and explain the main differences between WSDL and GWSDL. If you have no idea whatsoever of how to write WSDL, now is a good time to take a look at the following section of the How to... appendix: How to write a GWSDL description of your Grid Service.
The GWSDL code we'll be using is the equivalent of the Java interface shown above. However, that interface might raise a couple of eyebrows. If we said that our MathService is going to allow addition and subtraction, why do add and subtract receive only one parameter? Did the author of the tutorial flunk lower school math? Addition and subtraction involves two numbers! And what's with that getValue method? An explanation is in order...
The reason why addition and subtraction have one parameter is because we're going to use our service as an accumulator to demonstrate how grid services are stateful (remember: stateful means the service remembers internal values from one call to the other). MathService will have an internal value which will initially be zero. Each call to add and subtract will modify that internal value, which we'll be able to access thanks to the getValue method. This will allow us to observe that the service remembers that internal value from once call to the next (unlike a plain stateless web service, which would be unable to 'remember' that value).
Ok, so supposing you either know WSDL or have visited the How to write a GWSDL description of your Grid Service page, take a good thorough look at this GWSDL code:
<?xml version="1.0" encoding="UTF-8"?> <definitions name="MathService" targetNamespace="http://www.globus.org/namespaces/2004/02/progtutorial/MathService" xmlns:tns="http://www.globus.org/namespaces/2004/02/progtutorial/MathService" xmlns:ogsi="http://www.gridforum.org/namespaces/2003/03/OGSI" xmlns:gwsdl="http://www.gridforum.org/namespaces/2003/03/gridWSDLExtensions" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import location="../../ogsi/ogsi.gwsdl" namespace="http://www.gridforum.org/namespaces/2003/03/OGSI"/> <types> <xsd:schema targetNamespace="http://www.globus.org/namespaces/2004/02/progtutorial/MathService" attributeFormDefault="qualified" elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"> <xsd:element name="add"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:int"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="addResponse"> <xsd:complexType/> </xsd:element> <xsd:element name="subtract"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:int"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="subtractResponse"> <xsd:complexType/> </xsd:element> <xsd:element name="getValue"> <xsd:complexType/> </xsd:element> <xsd:element name="getValueResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:int"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </types> <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="GetValueInputMessage"> <part name="parameters" element="tns:getValue"/> </message> <message name="GetValueOutputMessage"> <part name="parameters" element="tns:getValueResponse"/> </message> <gwsdl:portType name="MathPortType" extends="ogsi:GridService"> <operation name="add"> <input message="tns:AddInputMessage"/> <output message="tns:AddOutputMessage"/> <fault name="Fault" message="ogsi:FaultMessage"/> </operation> <operation name="subtract"> <input message="tns:SubtractInputMessage"/> <output message="tns:SubtractOutputMessage"/> <fault name="Fault" message="ogsi:FaultMessage"/> </operation> <operation name="getValue"> <input message="tns:GetValueInputMessage"/> <output message="tns:GetValueOutputMessage"/> <fault name="Fault" message="ogsi:FaultMessage"/> </operation> </gwsdl:portType> </definitions>
This file is $TUTORIAL_DIR/schema/progtutorial/MathService/Math.gwsdl. If you're wondering why you have to save it in that particular directory, take a look at the Tutorial Directory Structure appendix. |
If you know WSDL, you'll recognize this as a pretty straightforward WSDL file which defines three operations: add, subtract, and getValue (along with all the necessary messages and types). Let's take a closer look at some important parts of the code. First of all, notice how the target namespace for the Grid Service is:
http://www.globus.org/namespaces/2004/02/progtutorial/MathService
Furthermore, we have to declare the following OGSI namespaces:
xmlns:ogsi="http://www.gridforum.org/namespaces/2003/03/OGSI" xmlns:gwsdl="http://www.gridforum.org/namespaces/2003/03/gridWSDLExtensions"
We also have to import a GWSDL file that defines all the OGSI-specific types, messages, and portTypes.
<import location="../../ogsi/ogsi.gwsdl" namespace="http://www.gridforum.org/namespaces/2003/03/OGSI"/>
Finally, notice how we have no bindings whatsoever in our GWSDL file (bindings are an essential part of a normal WSDL file). We don't have to add them manually, since they are generated automatically with a GT3 tool.
One of the nice things about (G)WSDL is that it's language-neutral. In other words, there is no mention to the language in which the service is going to be implemented, or to the language in which the client is going to be implemented.
However, there will of course come a moment when I'll want to refer to this interface from a specific language (in our case, Java). We do this through a set of stub classes (stubs where described in A short introduction to Web Services) which are generated from the GWSDL file using a GT3 tool. For that tool to successfully generate the stub classes, we need to tell it where (i.e. in what Java package) to place the stub classes. We do this with a mappings file, which maps GWSDL namespaces to Java packages:
http\://www.globus.org/namespaces/2004/02/progtutorial/MathService= org.globus.progtutorial.stubs.MathService http\://www.globus.org/namespaces/2004/02/progtutorial/MathService/bindings= org.globus.progtutorial.stubs.MathService.bindings http\://www.globus.org/namespaces/2004/02/progtutorial/MathService/service= org.globus.progtutorial.stubs.MathService.service
Each mapping must go in one line (i.e. the above file should have three lines). This file is $TUTORIAL_DIR/namespace2package.mappings. |
The first namespace is the target namespace of the GWSDL file. The other two namespaces are automatically generated when a GT3 tool 'completes' the GWSDL file (including the necessary bindings). For all the tutorial, we'll be placing all the stub classes in the following Java package:
org.globus.progtutorial.stubs
Since we're defining a service called MathService, we're specifically mapping the GWSDL file to the following package:
org.globus.progtutorial.stubs.MathService
However, take into account that the stubs classes are generated from the GWSDL file, so they won't exist until we compile the service (which is when the stub classes are generated). In other words, don't look for the org.globus.progtutorial.stubs package in $TUTORIAL_DIR, because you won't find them there. If you are of a curious predisposition, don't worry, as soon as we generate the stub classes, we'll take a (very brief) look at the directory where they are generated.
Remember that this is GWSDL, an extension of WSDL. Actually, this is not entirely true. GWSDL has certain features that WSDL 1.1 doesn't have, but which will be available in WSDL 1.2/2.0. Since WSDL 1.2/2.0 is still a W3C Working Draft (in other words, not a stable standard, and bound to change in the near future), the Global Grid Forum was unable to use WSDL 1.2/2.0 (with all its great Grid-friendly improvements) in OGSI. So, they created GWSDL as a temporary solution. In fact, the Global Grid Forum has said that, as soon as WSDL 1.2/2.0 is a W3C Recommendation (a stable standard), it will substitute GWSDL for WSDL 1.2/2.0. However, since the announcement of WSRF, this has changed (as OGSI will be discontinued when WSRF appears). WSRF will not use GWSDL, but it won't wait for WSDL 1.2/2.0 either, so it will use pure WSDL 1.1 for interface description.
So, what exactly are the improvements in GWSDL? Well, they're basically related to the improvements that Grid Services introduce with respect to Web Services (as seen in What is a Grid Service?). If you are WSDL-literate, you've probably already spotted one improvement in the above code:
<gwsdl:portType name="MathPortType" extends="ogsi:GridService">
</gwsdl:portType>
First of all, notice how we're not using the WSDL <portType> tag, but a tag from the GWSDL namespace: <gwsdl:portType>. This new tag has an extends attribute. This is the first major improvement in GWSDL: portType extension. You can define a PortType as an extension of one of more portTypes. In this case, we're extending from an OGSI PortType called GridService (all Grid Services must implement this interface).
The second major improvement is related to Service Data, which we will see in one of the following chapters.