This document summarises steps in order to develop (to implement) an asynchronous SOAP based BioMoby service using Perl MoSeS.
The main thing to understand is that MoSeS does not give you a full implementation of your service. You still need to program the business logic (e.g. to extract data from your database) - but you do not need to worry about the BioMoby and SOAP protocol details.
To implement SOAP services using MoSeS, you need to have the following installed on your machine:
Once you have installed Perl MoSeS and all of its dependencies on your machine, you will have to run through the MoSeS set up. This is only done once per user of MoSeS (unless you are upgrading Perl-MoSeS). For more information, please view the MOSES::MOBY documentation.
In order to implement a Biomoby service, we must first register one in the registry of our choosing.
We can register a service using a perl script or one of the many GUIs created by the Biomoby developers. This tutorial will be using a simple perl script, but you are invited to try GUIs such as Dashboard or The Moby Registration Pages.
The service that we will be registering is going to be a simple echo service. To spice things up a little bit, our service will echo the reverse string that it receives.
The script that we will use for registering our service is shown below:
#!/usr/bin/perl -w use strict; use MOBY::Client::Central; # instantiate a client to mobycentral my $m = MOBY::Client::Central->new( Registries => { mobycentral => { URL => "http://moby.ucalgary.ca/moby/MOBY-Central.pl", URI => "http://moby.ucalgary.ca/MOBY/Central", }, } ); # give our new service a name my $serviceName = "getReverseEchoString"; # give our service a service type my $serviceType = "TutorialService"; # the uri of the service provider my $authURI = "samples.jmoby.net"; # the email address of the service provider my $email = 'your.email@domain.com'; # the url to our dispatcher file # for more information on this url, visit # http://search.cpan.org/dist/MOSES-MOBY/lib/MOSES/MOBY.pm#Quick_Start_-_Five_Steps_to_the_First_Service # paying attention to point #4 my $URL = "http://localhost/cgi-bin/AsyncMobyServer.cgi"; # a small description of what our service does my $description = "This service consumes a string of text and returns the reverse string back to the caller"; # the inputs to our service my @input_namespaces = (); my @input_simples = ('String', \@input_namespaces); my @input_articles = ('my_input_string', \@input_simples); my @all_inputs = (\@input_articles); # the outputs to our service my @output_namespaces = (); my @output_simples = ('String', \@output_namespaces); my @output_articles = ('my_reverse_string', \@output_simples); my @all_outputs = (\@output_articles); # register the service my $REG = $m->registerService( serviceName => $serviceName, serviceType => $serviceType, authURI => $authURI, contactEmail => $email, description => $description, category => "moby-async", URL => $URL, input => \@all_inputs, output => \@all_outputs, secondary => undef, ); # where we successful? $REG->success?print "Success!\n":print "Failure: ",$REG->message,"\n"; # END of Script
The above script will register the service getReverseEchoString into the registry. Further discussion on the registering of servics is beyond the scope of this tutorial. For more information on that topic, please visit the Biomoby homepage.
Now that we have registered our service, we can now use MoSeS to generate the basis for our service.
Before we generate any code, we have to ensure that our cache (the one created when running the moses-install.pl script) is up to date.
If you see a message like the following:
There was a problem updating the cache. Did you create it first?Followed by an exception, use the -f option instead of the -u option.
At the command prompt, issue the following command:
You should see text like the following:
Generating services from samples.jmoby.net: Done.
If you happen to see redefinition warnings, please just ignore them; The warnings look like the following:
Generating services from samples.jmoby.net:
Subroutine header redefined at /usr/local/share/perl/5.8.8/MOBY/Async/WSRF.pm line 521.
Subroutine new redefined at /usr/local/share/perl/5.8.8/MOBY/Async/WSRF.pm line 694.
Subroutine DESTROY redefined at /usr/local/share/perl/5.8.8/MOBY/Async/WSRF.pm line 704.
Done.
Basically, we used the script moses-generate-services.pl to:
We are now ready to implement the business logic of our service!
Now that we are ready to implement the business logic, we will have to find, open and edit the module getReverseEchoString.pm.
MoSeS automatically created this file for you and left just the subroutine process_it for you to code your implementation. Fortunately, MoSeS provides some sample code for you to see how the datatypes are manipulated, how to get/set service notes, etc.
my $my_input_string = eval { $request->my_input_string };
The above snippet of code illustrates how MoSeS extracts the input data to our service. If you recall, when we registered our service, we stated that our service consumes a String and gave that String the name (in Biomoby speak 'ArticleName') 'my_input_string'.
If you had more than one input to a service, you would be able to access them simply by doing a
$request->articleName_of_input
Where articleName_of_input is the name that you gave the input when you registerd the service.
In the Biomoby world only datatypes that are considered primitives have values. Primitives include types such as String, Integer, Boolean, DateTime, Float, etc. In MoSeS, these values can be get/set using the method 'value'.
So in our service implementation, we have to extract the value of the String in order to reverse echo it back to a user of our service.
my $string = $my_input_string->value if defined $my_input_string; $string = "" unless defined $my_input_string;
Now that we have our string, we can reverse it,
$string = reverse $string;
Now we can set the output of our service to have the value of our string by replacing:
# fill the response my $my_reverse_string = new MOSES::MOBY::Data::String( value => "this is a value ", # TO BE EDITED );
with,
# fill the response my $my_reverse_string = new MOSES::MOBY::Data::String( value => "$string", # TO BE EDITED );
Optionally, to test out the asynchronous aspect of our service, feel free to slow your service down. Something like the following would do that for you:
# this will cause our service to sleep for 60 seconds # as long as data was sent to our service sleep(60) if defined $my_input_string;
You can add the optional code below the definition of $my_reverse_string.
That is all there is to it. Now we can test our service!
To test the service, issue the following command:
moses-testing-service.pl Service::getReverseEchoString
This tells MoSeS to obtain the module Service::getReverseEchoString and call it. The service should output something like the following:
<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent moby:authority="samples.jmoby.net">
<moby:serviceNotes>
<moby:Notes>Response created at Thu May 1 18:57:13 2008 (GMT), by the service 'getReverseEchoString'.</moby:Notes>
</moby:serviceNotes>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_reverse_string">
<moby:String moby:id="" moby:namespace=""/>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>
The output is nothing special because we didn't provide the service with an input string to reverse! On the plus side, we now know that the service at least works!
Let's provide input to the service to test whether or not our functionality works as expected! Copy the following bit of XML and save it to a file (with the name input.xml). We will then use that file as input to our service.
<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_input_string">
<moby:String moby:id="" moby:namespace="">I want this string reversed!</moby:String>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>
To test the service again, this time with some input, issue the following command:
moses-testing-service.pl Service::getReverseEchoString input.xml
This tells MoSeS to obtain the module Service::getReverseEchoString and call it with the text from input.xml. The service should output something like the following:
<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent moby:authority="samples.jmoby.net">
<moby:serviceNotes>
<moby:Notes>Response created at Thu May 1 18:57:13 2008 (GMT), by the service 'getReverseEchoString'.</moby:Notes>
</moby:serviceNotes>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_reverse_string">
<moby:String moby:id="" moby:namespace="">!desrever gnirts siht tnaw I</moby:String>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>
Wow, our service works as expected! We will test it once again using SOAP, after we deploy it on our machine.
Deploying an asynchronous SOAP based Perl MoSeS services is very straight forward!
The only thing you need to do is to tell your Web Server where there is a starting cgi-bin script.
The cgi-bin script was already created during the installation in <your-home-directory>/Perl-MoSes/ directory and is called AsyncMobyServer.cgi.
Make a symbolic link from the cgi-bin directory of your Web Server (e.g on some Linux distributions, using Apache Web server, the cgi-bin directory is /usr/lib/cgi-bin) to the cgi-bin script.
For example:
cd /usr/lib/cgi-bin sudo ln -s /home/ekawas/Perl-MoSeS/AsyncMobyServer.cgi .
You only have to do this once. In other words, all other asynchronous SOAP based services that you construct using MoSeS automatically use that cgi-bin script, because the moses-generate-services.pl script updates the ASYNC_SERVICE_TABLE that we talked about earlier.
Now that the service has been deployed, you can test it using WSRF/SOAP with the following command:
moses-testing-service.pl -v -a http://localhost/cgi-bin/AsyncMobyServer.cgi getReverseEchoString input.xml
The -v option is just a flag that makes the script be verbose, so that you can see what is going on.
When we call the script with the -a option, we tell the moses-testing-service.pl script that we would like to call our service using Asynchronous SOAP. We then must provide the script with 2 or 3 parameters:
The expected output should be very similar to the output we saw above when we tested our service:
Sending the following data to getReverseEchoString_submit asynchronously:
<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_input_string">
<moby:String moby:id="" moby:namespace="">I want this string reversed!</moby:String>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY> Current State: running
Current State: running
Current State: running <?xml version="1.0"?>
<moby:MOBY xmlns:moby="http://www.biomoby.org/moby">
<moby:mobyContent moby:authority="samples.jmoby.net">
<moby:serviceNotes>
<moby:Notes>Response created at Thu May 1 19:22:00 2008 (GMT), by the service 'getReverseEchoString'.</moby:Notes>
</moby:serviceNotes>
<moby:mobyData moby:queryID="job_0">
<moby:Simple moby:articleName="my_reverse_string">
<moby:String moby:id="" moby:namespace="">!desrever gnirts siht tnaw I</moby:String>
</moby:Simple>
</moby:mobyData>
</moby:mobyContent>
</moby:MOBY>
That's all there is to constructing asynchronous SOAP based Perl MoSeS services!