[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 = &quot;&quot;;           # set empty response
+ 
+   foreach my $query(@queries){</pre>
 <pre>
- use MOBY::CommonSubs qw(:all);
- my @ids = getSimpleArticleIDs(&quot;NCBI_gi&quot;, \@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, &quot;String&quot;, &quot;SequenceString&quot;);</pre>
+<pre>
+            #  DO YOUR ANALYSIS HERE
+            my $result = &quot;&quot;; #whatever you analysis says
+            
+            $MOBY_RESPONSE .= simpleResponse($result, &quot;outputArticlename&quot;, $queryID);
+        }
+     }
+   }
+   return responseHeader(&quot;my.authURI.com&quot;) . $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 = &quot;&quot;;  # 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 = &quot;&quot;;           # set empty response
  
-   foreach (@queries){
-     my @inputs = @{$_}; #(may be more than one Simple/Collection input per query)
-     foreach my $input(@inputs){
-        @sequence = getNodeContentWithArticle($_, &quot;String&quot;, &quot;SequenceString&quot;);
-        my $sequence = join &quot;&quot;, @sequence; # join all lines of string
-        # print STDERR &quot;Analyzing $sequence\n&quot;; 
-        my $result = &amp;_AnalyzeString($sequence);  # do your analysis
-        $MOBY_RESPONSE .= simpleResponse($result, &quot;outputArticlename&quot;);
+   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 = &quot;&quot;;
+        if ($seq){
+            $length = length($seq);
+            $response = &quot;&lt;GenericSequence namespace='NCBI_Acc' id='$id'&gt;
+                           &lt;Integer namespace='' id='' articleName='Length'&gt;$length&lt;/Integer&gt;
+                           &lt;String namespace='' id='' articleName='SequenceString'&gt;$seq&lt;/String&gt;
+                         &lt;/GenericSequence&gt;&quot;;
+        }
+            $MOBY_RESPONSE .= simpleResponse($response, '', $queryID);
+        }
      }
    }
-   return responseHeader . $MOBY_RESPONSE . responseFooter;
+   return responseHeader(&quot;my.authURI.com&quot;) . $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 . &amp;simpleResponse($object, 'MyArticleName') . responseFooter;
+ usage    : $resp .= &amp;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 &amp;simpleResponse() with no arguments.</pre>
+            response by calling &amp;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 . &amp;collectionResponse(\@objects, 'MyArticleName') . responseFooter;
+ usage    : return responseHeader . &amp;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 &amp;collectionResponse() with no arguments.</pre>
+            response by calling &amp;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 @@
      &lt;/moby:MOBY&gt;</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 &lt;MOBY&gt; 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 &lt;queryInput&gt; 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>
+                &lt;queryInput&gt;
+                    &lt;Simple articleName='name1'&gt;
+                      &lt;Object namespace=blah id=blah/&gt;
+                    &lt;/Simple&gt;
+                &lt;/queryInput&gt;
+                &lt;queryInput&gt;
+                    &lt;Simple articleName='name1'&gt;
+                      &lt;Object namespace=blah id=blah/&gt;
+                    &lt;/Simple&gt;
+                &lt;/queryInput&gt;</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 &lt;MOBY&gt; 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 @@
                     &lt;/Simple&gt;
                 &lt;/queryInput&gt;
               &lt;/moby:Query&gt;
-                 ...
- 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