[MOBY-guts] biomoby commit
Mark Wilkinson
mwilkinson at pub.open-bio.org
Sat Nov 8 17:21:32 UTC 2003
mwilkinson
Sat Nov 8 12:21:31 EST 2003
Update of /home/repository/moby/moby-live/Perl/MOBY
In directory pub.open-bio.org:/tmp/cvs-serv20526/Perl/MOBY
Modified Files:
CommonSubs.pm CommonSubs.html
Log Message:
updated CommonSubs to handle new message format; also included a paradigmatic example of a service
moby-live/Perl/MOBY CommonSubs.pm,1.26,1.27 CommonSubs.html,1.5,1.6
===================================================================
RCS file: /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.pm,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.pm 2003/11/06 16:23:14 1.26
+++ /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.pm 2003/11/08 17:21:31 1.27
@@ -8,46 +8,125 @@
=cut
+=head1 Client Side Paradigm
-=head1 SYNOPSIS
+=cut
- use MOBY::CommonSubs qw(:all);
- my @ids = getSimpleArticleIDs("NCBI_gi", \@SimpleArticles);
- my $ns = getSimpleArticleNamespaceURI($SimpleArticle);
+=head2 Service-Side Paradigm
-A COMPLETE EXAMPLE OF A SIMPLE MOBY SERVICE
+The following is a generalized architecture for *all*
+BioMOBY services showing how to parse incoming messages...
sub myServiceName {
- my ($caller, $query) = @_; # get the incoming MOBY query XML
- my @queries = getInputArticles($query); # returns DOM nodes
- my $MOBY_RESPONSE = ""; # set empty response
+ my ($caller, $message) = @_; # get the incoming MOBY query XML
+
+ my @queries = getInputs($message); # returns XML::DOM nodes
+ my $MOBY_RESPONSE = ""; # set empty response
- foreach (@queries){
- my @inputs = @{$_}; #(may be more than one Simple/Collection input per query)
- foreach my $input(@inputs){
- @sequence = getNodeContentWithArticle($_, "String", "SequenceString");
- my $sequence = join "", @sequence; # join all lines of string
- # print STDERR "Analyzing $sequence\n";
- my $result = &_AnalyzeString($sequence); # do your analysis
- $MOBY_RESPONSE .= simpleResponse($result, "outputArticlename");
+ foreach my $query(@queries){
+
+ my $queryID = getInputID($query); # get the queryID attribute of the queryInput
+
+ my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
+ foreach my $input(@input_articles){ # input is a listref
+
+ my ($articleName, $article) = @{$input}; # get the named article
+
+ my $simple = isSimpleArticle($article); # articles may be simple or collection
+ my $collection = isCollectionArticle($article);
+
+ if ($collection){
+
+ # do something wtih the collection...
+ # for example...
+ my @simples = getCollectedSimples($article);
+ # blah blah blah...
+
+ } elsif ($simple){
+ # maybe you just need the ID of the incoming query:
+ my ($id) = getSimpleArticleIDs('NCBI_gi', $article); # if you need the ID
+
+ # or maybe you are going to do something with the content?
+ # for example, this will get the array of text lines
+ # for the moby:String object with the articleName 'SequenceString'
+ # that is in this $article
+ my @sequence = getNodeContentWithArticle($article, "String", "SequenceString");
+
+ # DO YOUR ANALYSIS HERE
+ my $result = ""; #whatever you analysis says
+
+ $MOBY_RESPONSE .= simpleResponse($result, "outputArticlename", $queryID);
+ }
}
}
- return responseHeader . $MOBY_RESPONSE . responseFooter;
+ return responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter;
+ }
+
+=cut
+
+=head1 EXAMPLE
+
+
+A COMPLETE EXAMPLE OF AN EASY MOBY SERVICE
+
+This is a service that:
+
+CONSUMES: Object in the NCBI_Acc namespace
+EXECUTES: Retrieval
+PRODUCES: GenericSequence (in the NCBI_Acc namespace)
+
+
+ use Bio::Perl;
+
+ # this subroutine is called from your dispatch_with line
+ # in your SOAP daemon
+
+ sub myServiceName {
+ my ($caller, $message) = @_; # get the incoming MOBY query XML
+
+ my @queries = getInputs($message); # returns XML::DOM nodes
+ my $MOBY_RESPONSE = ""; # set empty response
+
+ foreach my $query(@queries){
+
+ my $queryID = getInputID($query); # get the queryID attribute of the queryInput
+
+ my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
+ foreach my $input(@input_articles){ # input is a listref
+ my ($articleName, $article) = @{$input}; # get the named article
+ next unless isSimpleArticle($article); # I only allow simple inputs in my service signature
+ my ($id) = getSimpleArticleIDs('NCBI_Acc', $article); # if you need the ID
+ my $seq;
+ eval {$seq = get_sequence('genbank',$id);} # suppress bioperl error messages
+ my $response = "";
+ if ($seq){
+ $length = length($seq);
+ $response = "<GenericSequence namespace='NCBI_Acc' id='$id'>
+ <Integer namespace='' id='' articleName='Length'>$length</Integer>
+ <String namespace='' id='' articleName='SequenceString'>$seq</String>
+ </GenericSequence>";
+ }
+ $MOBY_RESPONSE .= simpleResponse($response, '', $queryID);
+ }
+ }
+ }
+ return responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter;
}
=head1 DESCRIPTION
-Used to do various transactions with MOBY-Central registry, including registering
-new Object and Service types, querying for these types, registering new
-Servers/Services, or queryiong for available services given certain input/output
-or service type constraints.
+CommonSubs are used to do various manipulations of MOBY Messages. It is useful
+both Client and Service side to construct and parse MOBY Messages, and ensure
+that the message structure is valid as per the API.
+
+It DOES NOT connect to MOBY Central for any of its functions.
=head1 AUTHORS
-Mark Wilkinson (markw at illuminae.com)
+Mark Wilkinson (markw at illuminae dot com)
BioMOBY Project: http://www.biomoby.org
@@ -63,6 +142,7 @@
require Exporter;
use XML::DOM;
use MOBY::CrossReference;
+use MOBY::Client::OntologyServer;
@ISA = qw(Exporter);
@EXPORT_OK = qw(
@@ -72,6 +152,10 @@
responseHeader
responseFooter
getInputArticles
+ getInputs
+ getInputID
+ getArticles
+ getCollectedSimples
getNodeContentWithArticle
collectionResponse
validateNamespaces
@@ -88,6 +172,10 @@
responseHeader
responseFooter
getInputArticles
+ getInputs
+ getInputID
+ getArticles
+ getCollectedSimples
getNodeContentWithArticle
collectionResponse
validateNamespaces
@@ -130,7 +218,9 @@
sub getSimpleArticleIDs {
my ($desired_namespace, $input_nodes) = @_;
return undef unless $input_nodes;
+ $input_nodes = [$input_nodes] unless ref($input_nodes) =~ /ARRAY/; # be flexible!
return undef unless scalar @{$input_nodes};
+
my @input_nodes = @{$input_nodes};
my $OS = MOBY::Client::OntologyServer->new;
my ($s, $m);
@@ -218,40 +308,38 @@
name : simpleResponse
function : wraps a simple article in the appropriate queryResponse structure
- usage : $resp .= &simpleResponse($object, 'MyArticleName', $queryInput);
+ usage : $resp .= &simpleResponse($object, 'MyArticleName', $queryID);
args : (in order)
$object - (optional) a MOBY Object as raw XML
$article - (optional) an articeName for this article
- $query - (optional, but strongly recommended) the queryInput block
- to which you are responding, either as raw XML,
- or an XML::DOM object
+ $query - (optional, but strongly recommended) the queryID value for the
+ queryInput block to which you are responding
notes : as required by the API you must return a response for every input.
If one of the inputs was invalid, you return a valid (empty) MOBY
- response by calling &simpleResponse() with no arguments.
+ response by calling &simpleResponse(undef, undef, $queryID) with no arguments.
=cut
sub simpleResponse {
- my ($data, $articleName, $query) = @_; # articleName optional
- my $qID = '';
+ my ($data, $articleName, $qID) = @_; # articleName optional
$data ||='';
- $qID = &_getQueryID($query) if $query;
+ $qID = &_getQueryID($qID) if ref($qID) =~ /XML::DOM/; # in case they send the DOM instead of the ID
if ($articleName) {
return "
- <moby:queryResponse queryID='$qID'>
+ <moby:queryResponse moby:queryID='$qID'>
<moby:Simple articleName='$articleName'>$data</moby:Simple>
</moby:queryResponse>
";
} elsif($data) {
return "
- <moby:queryResponse queryID='qID'>
- <moby:Simple>$data</moby:Simple>
+ <moby:queryResponse moby:queryID='qID'>
+ <moby:Simple articleName='$articleName'>$data</moby:Simple>
</moby:queryResponse>
";
} else {
return "
- <moby:queryResponse queryID='$qID'/>
+ <moby:queryResponse moby:queryID='$qID'/>
";
}
}
@@ -263,8 +351,9 @@
my $doc = $parser->parse($query);
$query = $doc->getDocumentElement();
}
- return '' unless $query->getTagName eq "queryInput";
+ return '' unless $query->getTagName =~/queryInput/;
my $id = $query->getAttribute('queryID');
+ $id ||= $query->getAttribute('moby:queryID');
return $id;
}
@@ -273,26 +362,24 @@
name : collectionResponse
function : wraps a set of articles in the appropriate queryResponse structure
- usage : return responseHeader . &collectionResponse(\@objects, 'MyArticleName') . responseFooter;
+ usage : return responseHeader . &collectionResponse(\@objects, 'MyArticleName', $queryID) . responseFooter;
args : (in order)
\@objects - (optional) a listref of MOBY Objects as raw XML
$article - (optional) an articeName for this article
- $query - (optional, but strongly recommended) the queryInput block
- to which you are responding, either as raw XML,
- or an XML::DOM object
+ $queryID - (optional, but strongly recommended) the queryInput ID
+ to which you are responding
notes : as required by the API you must return a response for every input.
If one of the inputs was invalid, you return a valid (empty) MOBY
- response by calling &collectionResponse() with no arguments.
+ response by calling &collectionResponse(undef, undef, $queryID).
=cut
sub collectionResponse {
- my ($data, $articleName, $query) = @_; # articleName optional
+ my ($data, $articleName, $qID) = @_; # articleName optional
my $content = "";
- my $qID = '';
- $data ||='';
- $qID = &_getQueryID($query) if $query;
+ $data ||=[];
+ $qID ||= '';
unless ((ref($data) =~ /array/i) && $data->[0]){ # we're expecting an arrayref as input data,and it must not be empty
return "<moby:queryResponse queryID='$qID'/>";
}
@@ -319,7 +406,7 @@
} else {
return "
<moby:queryResponse queryID='$qID'>
- <moby:Collection>$content</moby:Collection>
+ <moby:Collection moby:articleName='$articleName'>$content</moby:Collection>
</moby:queryResponse>
";
}
@@ -394,9 +481,11 @@
my ($XML) = @_;
- my $parser = new XML::DOM::Parser;
- my $doc = $parser->parse($XML);
- my $moby = $doc->getDocumentElement();
+ unless (ref($XML) =~ /XML\:\:DOM/){
+ my $parser = new XML::DOM::Parser;
+ my $doc = $parser->parse($XML);
+ $moby = $doc->getDocumentElement();
+ }
my $x = $moby->getElementsByTagName('queryInput'); # get the queryInput block
unless ($x->item(0)){
@@ -411,62 +500,118 @@
}
+=head2 getInputID
-=head2 get_queryInput_Articles
+ name : getInputID
+ function : get the value of the queryID element
+ usage : @queryInputs = getInputID($XML)
+ args : the raw XML or XML::DOM of a <queryInput> block
+ returns : integer, or ''
+ Note : queryInputs and queryResponses are coordinately enumerated!
+ The integer you get here is what you
+ pass as the third argument to the simpleResponse or collectionResponse
+ subroutine to associate the numbered input to the numbered response
- name : get_queryInput_Articles
- function : get the Simple/Collection articles for each queryInput, in order
- usage : @queries = get_queryInput_Articles($XML)
- args : XML of a <queryInput> or an XML::DOM::Node of the <queryInput> element
- returns : a list of listrefs, each listref is the input to a single query.
- Remember that the input to a single query may be one or more Simple
- and/or Collection articles. These are provided as XML::DOM nodes.
-
- i.e.: @queries = ([$SIMPLE_DOM_NODE], [$SIMPLE_DOM_NODE2])
- or : @queries = ([$COLLECTION_DOM_NODE], [$COLLECTION_DOM_NODE2])
-
- the former is generated from the following XML:
+=cut
+
+
+sub getInputID {
+ my ($XML) = @_;
+ unless (ref($XML) =~ /XML\:\:DOM/){
+ my $parser = new XML::DOM::Parser;
+ my $doc = $parser->parse($XML);
+ $XML = $doc->getDocumentElement();
+ }
+ return '' unless $XML->getTagName =~ /queryInput/;
+ my $qid = $XML->getAttribute('queryID');
+ return defined($qid)?$qid:'';
+}
+
+
+
+=head2 getArticles
+
+ name : getArticles
+ function : get the Simple/Collection articles for a single queryInput
+ or queryResponse node
+ usage : @articles = getArticles($XML)
+ args : raw XML or XML::DOM of a moby:queryInput or a moby:queryResponse block
+ returns : a list of listrefs; each listref is one component of the queryInput.
+ a single queryInput/Responsemay consist of one or more named or unnamed
+ simple or collection articles. The listref structure is thus [name, $ARTICLE]:
- ...
- <moby:Query>
+ e.g.: @articles = ['name1', $SIMPLE_DOM]
+ or : @articles = ['name1', $COLLECTION_DOM], ['name2', $SIMPLE_DOM]...
+
+ the former is generated from the following sample XML:
+
<queryInput>
- <Simple>
+ <Simple articleName='name1'>
<Object namespace=blah id=blah/>
</Simple>
</queryInput>
<queryInput>
- <Simple>
+ <Simple articleName='name1'>
<Object namespace=blah id=blah/>
</Simple>
</queryInput>
- </moby:Query>
- ...
=cut
-sub get_queryInput_Articles {
+sub getArticles {
- my ($XML) = @_;
- my $parser = new XML::DOM::Parser;
- my $doc = $parser->parse($XML);
- my $moby = $doc->getDocumentElement();
+ my ($moby) = @_;
+ unless (ref($moby) =~ /XML\:\:DOM/){
+ my $parser = new XML::DOM::Parser;
+ my $doc = $parser->parse($moby);
+ $moby = $doc->getDocumentElement();
+ }
- my $x = $moby->getElementsByTagName('queryInput'); # get the queryInput block
- unless ($x->item(0)){
- $x = $moby->getElementsByTagName('moby:queryInput');
+ return undef unless $moby->getNodeType == ELEMENT_NODE;
+ return undef unless ($moby->getTagName =~ /queryInput/ || $moby->getTagName =~ /queryResponse/);
+ my @articles;
+ foreach $child($moby->getChildNodes){ # there may be more than one Simple/Collection per input; iterate over them
+ next unless $child->getNodeType == ELEMENT_NODE; # ignore whitespace
+ next unless ($child->getTagName =~ /Simple/ || $child->getTagName =~ /Collection/);
+ my $articleName = $child->getAttribute('articleName');
+ $articleName ||= $child->getAttribute('moby:articleName');
+ push @articles, [$articleName, $child]; # take the child elements, which are <Simple/> or <Collection/>
}
+ return @articles; # return them.
+}
- my @queries;
- for (0..$x->getLength-1){ # there may be more than one queryInput per message
- my @this_query;
- foreach $child($x->item($_)->getChildNodes){ # there may be more than one Simple/Collection per input; iterate over them
- next unless $child->getNodeType == ELEMENT_NODE; # ignore whitespace
- push @this_query, $child; # take the child elements, which are <Simple/> or <Collection/>
- }
- push @queries, \@this_query;
- }
- return @queries; # return them in the order that they were discovered.
+
+=head2 getCollectedSimples
+
+ name : getCollectedSimples
+ function : get the Simple articles collected in a moby:Collection block
+ usage : @Simples = getCollectedSimples($XML)
+ args : raw XML or XML::DOM of a moby:Collection block
+ returns : a list of XML::DOM nodes, each of which is a moby:Simple block
+
+=cut
+
+
+sub getCollectedSimples {
+
+ my ($moby) = @_;
+ unless (ref($moby) =~ /XML\:\:DOM/){
+ my $parser = new XML::DOM::Parser;
+ my $doc = $parser->parse($moby);
+ $moby = $doc->getDocumentElement();
+ }
+
+ return undef unless $moby->getNodeType == ELEMENT_NODE;
+ return undef unless ($moby->getTagName =~ /Collection/);
+
+ my @articles;
+ foreach $child($moby->getChildNodes){ # there may be more than one Simple/Collection per input; iterate over them
+ next unless $child->getNodeType == ELEMENT_NODE; # ignore whitespace
+ next unless ($child->getTagName =~ /Simple/);
+ push @articles, $child; # take the child elements, which are <Simple/> or <Collection/>
+ }
+ return (@articles); # return them.
}
@@ -475,7 +620,7 @@
name : getInputArticles
function : get the Simple/Collection articles for each input query, in order
usage : @queries = getInputArticles($XML)
- args : the raw XML of a <MOBY> query
+ args : the raw XML of a moby:MOBY query
returns : a list of listrefs, each listref is the input to a single query.
Remember that the input to a single query may be one or more Simple
and/or Collection articles. These are provided as XML::DOM nodes.
@@ -505,10 +650,12 @@
sub getInputArticles {
- my ($XML) = @_;
- my $parser = new XML::DOM::Parser;
- my $doc = $parser->parse($XML);
- my $moby = $doc->getDocumentElement();
+ my ($moby) = @_;
+ unless (ref($moby) =~ /XML\:\:DOM/){
+ my $parser = new XML::DOM::Parser;
+ my $doc = $parser->parse($moby);
+ $moby = $doc->getDocumentElement();
+ }
my $x = $moby->getElementsByTagName('queryInput'); # get the queryInput block
unless ($x->item(0)){
@@ -520,14 +667,7 @@
my @this_query;
foreach $child($x->item($_)->getChildNodes){ # there may be more than one Simple/Collection per input; iterate over them
next unless $child->getNodeType == ELEMENT_NODE; # ignore whitespace
-# if ($asObject){
-# my $obj;
-# $obj = MOBY::Client::SimpleArticle->new(XML_DOM => $child) if (isSimpleArticle($child));
-# $obj = MOBY::Client::CollectionArticle->new(XML_DOM => $child) if (isCollectionArticle($child));
-# push @this_query, $child;
-# } else {
push @this_query, $child; # take the child elements, which are <Simple/> or <Collection/>
-# }
}
push @queries, \@this_query;
}
@@ -554,7 +694,7 @@
$DOM = $doc->getDocumentElement();
}
$DOM = $DOM->getDocumentElement if ($DOM->isa("XML::DOM::Document"));
- return 1 if ($DOM->getTagName eq "Simple");
+ return 1 if ($DOM->getTagName =~ /Simple/);
return 0;
}
@@ -822,13 +962,13 @@
$ns = $xref->getAttributeNode('moby:namespace') unless $ns;
return undef unless $ns;
my $id = $xref->getAttributeNode('id');
- $id = $xref->getAttributeNode('moby:id') unless $ns;
+ $id = $xref->getAttributeNode('moby:id') unless $id;
return undef unless $id;
my $xr = $xref->getAttributeNode('xref_type');
- $xr = $xref->getAttributeNode('moby:namespace') unless $ns;
+ $xr = $xref->getAttributeNode('moby:xref_type') unless $xr;
return undef unless $xr;
my $ec = $xref->getAttributeNode('evidence_code');
- $ec = $xref->getAttributeNode('moby:namespace') unless $ns;
+ $ec = $xref->getAttributeNode('moby:evidence_code') unless $ec;
return undef unless $ec;
my $au = $xref->getAttributeNode('authURI');
$au = $xref->getAttributeNode('moby:authURI') unless $au;
===================================================================
RCS file: /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.html,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.html 2003/10/25 22:20:47 1.5
+++ /home/repository/moby/moby-live/Perl/MOBY/CommonSubs.html 2003/11/08 17:21:31 1.6
@@ -15,7 +15,13 @@
<ul>
<li><a href="#name">NAME</a></li>
- <li><a href="#synopsis">SYNOPSIS</a></li>
+ <li><a href="#client_side_paradigm">Client Side Paradigm</a></li>
+ <ul>
+
+ <li><a href="#serviceside_paradigm">Service-Side Paradigm</a></li>
+ </ul>
+
+ <li><a href="#example">EXAMPLE</a></li>
<li><a href="#description">DESCRIPTION</a></li>
<li><a href="#authors">AUTHORS</a></li>
<li><a href="#methods">METHODS</a></li>
@@ -27,6 +33,10 @@
<li><a href="#collectionresponse">collectionResponse</a></li>
<li><a href="#responseheader">responseHeader</a></li>
<li><a href="#responsefooter">responseFooter</a></li>
+ <li><a href="#getinputs">getInputs</a></li>
+ <li><a href="#getinputid">getInputID</a></li>
+ <li><a href="#getarticles">getArticles</a></li>
+ <li><a href="#getcollectedsimples">getCollectedSimples</a></li>
<li><a href="#getinputarticles">getInputArticles</a></li>
<li><a href="#issimplearticle">isSimpleArticle</a></li>
<li><a href="#iscollectionarticle">isCollectionArticle</a></li>
@@ -49,43 +59,116 @@
<p>
</p>
<hr />
-<h1><a name="synopsis">SYNOPSIS</a></h1>
+<h1><a name="client_side_paradigm">Client Side Paradigm</a></h1>
+<p>
+</p>
+<h2><a name="serviceside_paradigm">Service-Side Paradigm</a></h2>
+<p>The following is a generalized architecture for *all*
+BioMOBY services showing how to parse incoming messages...</p>
+<pre>
+ sub myServiceName {
+ my ($caller, $message) = @_; # get the incoming MOBY query XML</pre>
+<pre>
+ my @queries = getInputs($message); # returns XML::DOM nodes
+ my $MOBY_RESPONSE = ""; # set empty response
+
+ foreach my $query(@queries){</pre>
<pre>
- use MOBY::CommonSubs qw(:all);
- my @ids = getSimpleArticleIDs("NCBI_gi", \@SimpleArticles);
- my $ns = getSimpleArticleNamespaceURI($SimpleArticle);</pre>
-<p>A COMPLETE EXAMPLE OF A SIMPLE MOBY SERVICE</p>
+ my $queryID = getInputID($query); # get the queryID attribute of the queryInput
+
+ my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
+ foreach my $input(@input_articles){ # input is a listref</pre>
+<pre>
+ my ($articleName, $article) = @{$input}; # get the named article
+
+ my $simple = isSimpleArticle($article); # articles may be simple or collection
+ my $collection = isCollectionArticle($article);</pre>
+<pre>
+ if ($collection){</pre>
+<pre>
+ # do something wtih the collection...
+ # for example...
+ my @simples = getCollectedSimples($article);
+ # blah blah blah...
+
+ } elsif ($simple){
+ # maybe you just need the ID of the incoming query:
+ my ($id) = getSimpleArticleIDs('NCBI_gi', $article); # if you need the ID</pre>
+<pre>
+ # or maybe you are going to do something with the content?
+ # for example, this will get the array of text lines
+ # for the moby:String object with the articleName 'SequenceString'
+ # that is in this $article
+ my @sequence = getNodeContentWithArticle($article, "String", "SequenceString");</pre>
+<pre>
+ # DO YOUR ANALYSIS HERE
+ my $result = ""; #whatever you analysis says
+
+ $MOBY_RESPONSE .= simpleResponse($result, "outputArticlename", $queryID);
+ }
+ }
+ }
+ return responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter;
+ }</pre>
+<p>
+</p>
+<hr />
+<h1><a name="example">EXAMPLE</a></h1>
+<p>A COMPLETE EXAMPLE OF AN EASY MOBY SERVICE</p>
+<p>This is a service that:</p>
+<p>CONSUMES: Object in the NCBI_Acc namespace
+EXECUTES: Retrieval
+PRODUCES: GenericSequence (in the NCBI_Acc namespace)</p>
<pre>
+ use Bio::Perl;
+
+ # this subroutine is called from your dispatch_with line
+ # in your SOAP daemon
+
sub myServiceName {
- my ($caller, $query) = @_; # get the incoming MOBY query XML
- my @queries = getInputArticles($query); # returns DOM nodes
- my $MOBY_RESPONSE = ""; # set empty response
+ my ($caller, $message) = @_; # get the incoming MOBY query XML</pre>
+<pre>
+ my @queries = getInputs($message); # returns XML::DOM nodes
+ my $MOBY_RESPONSE = ""; # set empty response
- foreach (@queries){
- my @inputs = @{$_}; #(may be more than one Simple/Collection input per query)
- foreach my $input(@inputs){
- @sequence = getNodeContentWithArticle($_, "String", "SequenceString");
- my $sequence = join "", @sequence; # join all lines of string
- # print STDERR "Analyzing $sequence\n";
- my $result = &_AnalyzeString($sequence); # do your analysis
- $MOBY_RESPONSE .= simpleResponse($result, "outputArticlename");
+ foreach my $query(@queries){</pre>
+<pre>
+ my $queryID = getInputID($query); # get the queryID attribute of the queryInput
+
+ my @input_articles = getArticles($query); # get the Simple/Collection articles making up this query
+ foreach my $input(@input_articles){ # input is a listref
+ my ($articleName, $article) = @{$input}; # get the named article
+ next unless isSimpleArticle($article); # I only allow simple inputs in my service signature
+ my ($id) = getSimpleArticleIDs('NCBI_Acc', $article); # if you need the ID
+ my $seq;
+ eval {$seq = get_sequence('genbank',$id);} # suppress bioperl error messages
+ my $response = "";
+ if ($seq){
+ $length = length($seq);
+ $response = "<GenericSequence namespace='NCBI_Acc' id='$id'>
+ <Integer namespace='' id='' articleName='Length'>$length</Integer>
+ <String namespace='' id='' articleName='SequenceString'>$seq</String>
+ </GenericSequence>";
+ }
+ $MOBY_RESPONSE .= simpleResponse($response, '', $queryID);
+ }
}
}
- return responseHeader . $MOBY_RESPONSE . responseFooter;
+ return responseHeader("my.authURI.com") . $MOBY_RESPONSE . responseFooter;
}</pre>
<p>
</p>
<hr />
<h1><a name="description">DESCRIPTION</a></h1>
-<p>Used to do various transactions with MOBY-Central registry, including registering
-new Object and Service types, querying for these types, registering new
-Servers/Services, or queryiong for available services given certain input/output
-or service type constraints.</p>
+<p>CommonSubs are used to do various manipulations of MOBY Messages. It is useful
+both Client and Service side to construct and parse MOBY Messages, and ensure
+that the message structure is valid as per the API.</p>
+<p>It DOES NOT connect to MOBY Central for any of its functions.</p>
<p>
</p>
<hr />
<h1><a name="authors">AUTHORS</a></h1>
-<p>Mark Wilkinson (<a href="mailto:markw at illuminae.com">markw at illuminae.com</a>)</p>
+<p>Mark Wilkinson (markw at illuminae dot com)</p>
<p>BioMOBY Project: <a href="http://www.biomoby.org">http://www.biomoby.org</a></p>
<p>
</p>
@@ -127,33 +210,38 @@
<pre>
name : simpleResponse
function : wraps a simple article in the appropriate queryResponse structure
- usage : return responseHeader . &simpleResponse($object, 'MyArticleName') . responseFooter;
+ usage : $resp .= &simpleResponse($object, 'MyArticleName', $queryID);
args : (in order)
$object - (optional) a MOBY Object as raw XML
$article - (optional) an articeName for this article
+ $query - (optional, but strongly recommended) the queryID value for the
+ queryInput block to which you are responding
notes : as required by the API you must return a response for every input.
If one of the inputs was invalid, you return a valid (empty) MOBY
- response by calling &simpleResponse() with no arguments.</pre>
+ response by calling &simpleResponse(undef, undef, $queryID) with no arguments.</pre>
<p>
</p>
<h2><a name="collectionresponse">collectionResponse</a></h2>
<pre>
name : collectionResponse
function : wraps a set of articles in the appropriate queryResponse structure
- usage : return responseHeader . &collectionResponse(\@objects, 'MyArticleName') . responseFooter;
+ usage : return responseHeader . &collectionResponse(\@objects, 'MyArticleName', $queryID) . responseFooter;
args : (in order)
\@objects - (optional) a listref of MOBY Objects as raw XML
$article - (optional) an articeName for this article
+ $queryID - (optional, but strongly recommended) the queryInput ID
+ to which you are responding
notes : as required by the API you must return a response for every input.
If one of the inputs was invalid, you return a valid (empty) MOBY
- response by calling &collectionResponse() with no arguments.</pre>
+ response by calling &collectionResponse(undef, undef, $queryID).</pre>
<p>
</p>
<h2><a name="responseheader">responseHeader</a></h2>
<pre>
- name : responseHeader
+ name : responseHeader($auth)
function : print the XML string of a MOBY response header
- usage : return responseHeader . $DATA . responseFooter;
+ usage : return responseHeader('illuminae.com') . $DATA . responseFooter;
+ args : a string representing the service providers authority URI
caveat : will soon be expanded to include service provision info
and additional namespace declarations
notes : returns everything required up to the response articles themselves.
@@ -167,7 +255,7 @@
<pre>
name : responseFooter
function : print the XML string of a MOBY response footer
- usage : return responseHeader . $DATA . responseFooter;
+ usage : return responseHeader('illuminae.com') . $DATA . responseFooter;
notes : returns everything required after the response articles themselves
i.e. something like:
@@ -175,12 +263,74 @@
</moby:MOBY></pre>
<p>
</p>
+<h2><a name="getinputs">getInputs</a></h2>
+<pre>
+ name : getInputs
+ function : get the queryInput block(s) as XML::DOM nodes
+ usage : @queryInputs = getInputArticles($XML)
+ args : the raw XML of a <MOBY> query, or an XML::DOM document
+ returns : a list of XML::DOM::Node's, each is a queryInput.
+ Note : Remember that queryInputs are numbered! This is what you
+ pass as the third argument to the simpleResponse or collectionResponse
+ subroutine to associate the numbered input to the numbered response</pre>
+<p>
+</p>
+<h2><a name="getinputid">getInputID</a></h2>
+<pre>
+ name : getInputID
+ function : get the value of the queryID element
+ usage : @queryInputs = getInputID($XML)
+ args : the raw XML or XML::DOM of a <queryInput> block
+ returns : integer, or ''
+ Note : queryInputs and queryResponses are coordinately enumerated!
+ The integer you get here is what you
+ pass as the third argument to the simpleResponse or collectionResponse
+ subroutine to associate the numbered input to the numbered response</pre>
+<p>
+</p>
+<h2><a name="getarticles">getArticles</a></h2>
+<pre>
+ name : getArticles
+ function : get the Simple/Collection articles for a single queryInput
+ or queryResponse node
+ usage : @articles = getArticles($XML)
+ args : raw XML or XML::DOM of a moby:queryInput or a moby:queryResponse block
+ returns : a list of listrefs; each listref is one component of the queryInput.
+ a single queryInput/Responsemay consist of one or more named or unnamed
+ simple or collection articles. The listref structure is thus [name, $ARTICLE]:
+
+ e.g.: @articles = ['name1', $SIMPLE_DOM]
+ or : @articles = ['name1', $COLLECTION_DOM], ['name2', $SIMPLE_DOM]...</pre>
+<pre>
+ the former is generated from the following sample XML:</pre>
+<pre>
+ <queryInput>
+ <Simple articleName='name1'>
+ <Object namespace=blah id=blah/>
+ </Simple>
+ </queryInput>
+ <queryInput>
+ <Simple articleName='name1'>
+ <Object namespace=blah id=blah/>
+ </Simple>
+ </queryInput></pre>
+<p>
+</p>
+<h2><a name="getcollectedsimples">getCollectedSimples</a></h2>
+<pre>
+ name : getCollectedSimples
+ function : get the Simple articles collected in a moby:Collection block
+ usage : @Simples = getCollectedSimples($XML)
+ args : raw XML or XML::DOM of a moby:Collection block
+ returns : a list of XML::DOM nodes, each of which is a moby:Simple block</pre>
+<p>
+</p>
<h2><a name="getinputarticles">getInputArticles</a></h2>
<pre>
name : getInputArticles
function : get the Simple/Collection articles for each input query, in order
usage : @queries = getInputArticles($XML)
- args : the raw XML of a <MOBY> query
+ args : the raw XML of a moby:MOBY query
returns : a list of listrefs, each listref is the input to a single query.
Remember that the input to a single query may be one or more Simple
and/or Collection articles. These are provided as XML::DOM nodes.
@@ -203,11 +353,7 @@
</Simple>
</queryInput>
</moby:Query>
- ...
- note : This subroutine enforces valid message structure
- in that you may only have one Simple OR one Collection
- article per queryInput! if you have more, only the first
- is read.</pre>
+ ...</pre>
<p>
</p>
<h2><a name="issimplearticle">isSimpleArticle</a></h2>
More information about the MOBY-guts
mailing list