3.1. Step 1: Defining the interface in WSDL

The first step in writing a web service (including those that use WSRF to keep state) 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, other systems it interacts with, etc.). We just need to know what operations will be available to our users. In Web Services lingo, the service interface is usually called the port type (usually written portType).

As we saw in Section 1.2, “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.

At first sight, it might seem that starting with an interface language (such as a Java interface or an IDL interface) might be the best option, since (as you'll soon find out) it is more user-friendly than directly coding in WSDL. 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 getValueRP();
}

...and we'd be nearly finished with step 1! (we would still need to specify the resource properties). 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. Before that, we'll take a good look at the WSDL 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 WSDL file, but rather to present the WSDL file for this particular example. If you have no idea whatsoever of how to write WSDL, now is a good time to take a look at Section A.1, “...write a WSDL description of your WSRF stateful Web service”. Come on, go take a look at the appendix. We'll be waiting for you right here.

3.1.1. The WSDL code

Ok, so supposing you either know WSDL or have visited the WSDL appendix, take a good thorough look at this WSDL code:

<?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>
[Note]

This file is $EXAMPLES_DIR/schema/examples/MathService_instance/Math.wsdl. This file is located in that particular directory because of the tool we'll be using to build the service. You can find more details about the directory structure required by this tool in Appendix B, Tutorial directory structure.

If you know WSDL, you'll recognize this as a pretty straightforward WSDL file which defines three operations: add, subtract, and getValueRP (along with all the necessary messages and types). However, this WSDL file does have some peculiarities specific to WSRF and Globus.

3.1.2. WSRF and Globus-specific features of WSDL

Our WSDL file has three features which are specific to WSRF or to the Globus implementation of WSRF we're using. The following is just a brief overview of these three features. You can find more WSDL details in Section A.1, “...write a WSDL description of your WSRF stateful Web service”.

  • Resource properties: We use the wsrp:ResourceProperties attribute of the portType element to specify what our service's resource properties are. The resource properties must be declared in the <types> section of the WSDL file. Remember that the resource properties are where we'll keep all our state information.

  • The WSDL Preprocessor: Thanks to the wsdlpp:extends attribute of the portType element we can include existing WSRF portTypes in our own portType without having to copy-and-paste from the official WSRF WSDL files. A WSDL Preprocessor will use the value of that attribute to generate correct WSDL which includes our own portType definitions plus any WSRF portType we might need in our service. This is a Globus-specific feature that is included to make life easier for programmers.

    In our case, notice how we're including the the GetResourceProperty portType from the WS-ResourceProperties WSDL file.

  • No bindings: Bindings are an essential part of a normal WSDL file. However, we don't have to add them manually, since they are generated automatically by a GT4 tool that is called when we build the service.

[Warning]The WSDL Preprocessor

The WSDL Preprocessor (the wsdlpp:extends attribute in the portType element) is provided in GT4 as a convenience. Conceptually, it is very important to understand that WSDL files using wsdlpp:extends will always be converted to standard WSDL before they are actually used. In other words, wsdlpp:extends doesn't affect GT4's interoperability with other WSRF implementations because the extends attribute is always "purged" from our WSDL file before the service is deployed. This process is usually called "flattening" because we take several WSDL files (our file plus any WSRF WSDL files we extend from) and then merge them into a single (flattened) file. GT4 will always publish the flattened version of our WSDL file.

Also, take into account that you are not required to use wsdlpp:extends. If you choose to, you can write the flattened version directly. However, this involves a fair amount of copy-pasting that can be very error-prone. The book examples all use wsdlpp:extends.

Bottom line: GT4 doesn't require that other Web Services implementations or other WSRF implementations use wsdlpp:extends because WSDL files are always exchanged in their flattened versions. It is a purely internal feature of the toolkit.

3.1.3. Namespace mappings

One of the nice things about WSDL is that it's language-neutral. In other words, there is no mention of the language in which the service is going to be implemented, or of the language in which the client is going to be implemented.

However, there will of course come a moment when we'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 were described in Section 1.2, “A short introduction to Web Services”) which are generated from the WSDL file using a GT4 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 WSDL namespaces to Java packages:

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
[Note]

Each mapping must go in one line (i.e. the above file should have three lines). Also, take into account that the backslash before the colon is intentional. This file is $EXAMPLES_DIR/namespace2package.properties.

The first namespace is the target namespace of the WSDL file. The other two namespaces are automatically generated when a GT4 tool 'completes' the WSDL file (including the necessary bindings). Throughout the tutorial, the stub classes for the examples will be placed in the following Java package:

org.globus.examples.stubs

Since we're defining a service called MathService_instance, we're specifically mapping the WSDL file to the following package:

org.globus.examples.stubs.MathService_instance

However, take into account that the stubs classes are generated from the WSDL 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.examples.stubs package in $EXAMPLES_DIR, because you won't find them there. If you are of a curious disposition, 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.