Writing Web services


Information here is out of date, please refer to the web site of GFac directly.
Sample services, Adder, Multiplier, are supplied along with XBaya. You can skip this section of the document to try XBaya.


Theoretically, a component can be any Web services. All you need is a running Web service and the WSDL of the service. However, this section describes how to create a simple component using the Generic Factory Toolkit. The component we make here is an Adder component, which adds two input numbers and output the result. For the detail of the Generic Factory Toolkit, please see its document.

Writing a Service Map Document

The first thing to do is to create a Service Map Document for the Adder service. We describe several important parts below. (The whole sample Service Map Document is here.)

Mandatory input parameters

The following input parameters are mandatory. "brokerURL" specifies the borker of the notification to use. "topic" specifies the topic that a workflow uses. "correlationID" is an ID to distinguish each invocation of the service. They are used internally by workflow, and should be hidden from users in future releases.

        <parameterDescription>The URL of notification broker</parameterDescription>

        <parameterDescription>The topic of notification</parameterDescription>

        <parameterDescription>The correlation ID</parameterDescription>

Input/output parameters for the service

These are the actual parameters used by a component. Here, we define two input parameters, x and y, and one output parameter, z.

        <parameterDescription>This is the first input</parameterDescription>

        <parameterDescription>This is the second input</parameterDescription>

        <parameterDescription>This is the result</parameterDescription>

Creating the WSDL

You need to create the WSDL for the component. To generate the WSDL from the Service Map Document, you can use the Generic Factory Toolkit. The following is the sample command line.

% export GFAC_DIR=/u/sshirasu/workspace/SecureGFac
% $GFAC_DIR/run.sh util --serviceMapFile service-map.xml

This will create var/awsdl?????.xml. This is an abstract WSDL, which does not have location of the service. It is because we don't need the location of the service when we compose a workflow. We will need a WSDL with a service location when we actually run the workflow.

You need to register the WSDL to a component registry so that the X Workflow Composer can use it. The newest version of the Generic Factory Toolkit registers the WSDL to the resource catalog automatically when you create the WSDL. So, you don't need to worry about it. If you want to test locally without the resource catalog, copy the WSDL file to under the component/wsdl directory. (You may want to rename the file to reflect the service, such as Adder.wsdl.) The detail about component registries will be described at Component Registries.

Writing a Jython service script

The following is the Jython script that implements the service.

When the script is called from the Generic Factory Toolkit, some variables are automatically initialized to hide error-prone implementation details. An instance of the Notifier class, "notifier", is instantiated with proper brokerURL, topic, and correlationID. All you need to do to send notification is just call either the "info()", "finish()", or "fail()" method.

On top of that, parameters specified in the service map document are also initialized. In the case of the example below, "x" and "y" are initialized.

When you want to debug the script without the Generic Factory Toolkit, you can initialize these variables. The trick shown in the example below makes the script run both from the Generic Factory Toolkit or from the command-line without any modification.

# This is to use notification.
from edu.indiana.extreme.gFac.util import Notifier

# This is to catch Java Exception.
from java.lang import Throwable

     if notifier != None:
          print "Executed from the Generic Factory Toolkit."
except NameError, e:
     print "Executed from the command-line."
     # Initialize variables for debugging.
     # These variables are initialized automatically when called by 
     # the General Factory Toolkit.
     brokerURL = "rainier.extreme.indiana.edu:12346"
     topic = "testTopic"
     correlationID ="testCorrelationID"
     sender = "Adder"
     global notifier
     notifier = Notifier(brokerURL, topic, correlationID, sender)
     global x
     x = 3
     global y
     y = 4

print x
print y

# Do service specific task from here.

# Send a INFORMATION notification

# It is recommended to catch the exception in the script.
     z = int(x) + int(y)
     print z

     # Send the output as a FINISHED_SUCCESS notification.

# Catch Java Exceptions
except Throwable, e:
     print e
     # Send the error message and exception as a FINISHED_FAILED notification.
     notifier.fail("Detailed error message", e)

# Catch Jython Exceptions
except Exception, e:
     print e
     # Send the error message and exception as a FINISHED_FAILED notification.
     notifier.fail("Detailed error message: " + repr(e))

The most important thing is that the output of the script have to be sent by calling "notifier.finish()". Otherwise, the workflow script waits for the output forever. When the script fails, it is recommended to call "notifier.fail()" with the description of the error. But, in the worst case, the Generic Factory Toolkit catches any exception thrown from the script and send notification. The worst thing you can do is to catch exceptions and do nothing. This again cause the workflow script to wait forever.

If the component has multiple outputs, you need to name each parameter when you call "notification.finish()". For example, if you have two output, "a" and "b", the following is the example. You need to make sure that the output names have to match with the ones you defined in the service map.


Satoshi Shirasuna