1 #$Id: Central.pm,v 1.224 2005/12/09 16:49:54 mwilkinson Exp $
5 MOBY::Central.pm - API for communicating with the MOBY Central registry
12 use vars
qw($AUTOLOAD $WSDL_TEMPLATE);
14 use MOBY::OntologyServer;
15 use MOBY::service_type;
17 use MOBY::service_instance;
18 use MOBY::simple_input;
19 use MOBY::simple_output;
20 use MOBY::collection_input;
21 use MOBY::collection_output;
22 use MOBY::secondary_input;
23 use MOBY::central_db_connection;
27 #use MOBY::RDF::ServiceInstanceRDF;
29 #use RDF::Core::Model;
30 #use RDF::Core::Literal;
31 #use RDF::Core::Statement;
32 #use RDF::Core::Model::Serializer;
33 #use RDF::Core::Storage::Memory;
34 #use RDF::Core::Constants qw(:xml :rdf :rdfs);
35 use MOBY
::MobyXMLConstants
;
39 open( OUT
, ">/tmp/CentralRegistryLogOut.txt" ) || die "cant open logfile\n";
40 print OUT
"created logfile\n";
46 REQUIRES MYSQL 3.23 or later!!!!
48 If you are a Perl user, you should be using the
49 MOBY::Client:Central module to talk to MOBY-Central
51 If you need to connect directly, here is how it
52 is done in perl 5.6 and 5.6.1. It wont work
53 in Perl 5.8... sorry. Look how MOBY::Client::Cent
54 does it if you want to use Perl 5.8
57 --------------------------------------
60 use SOAP::Transport::HTTP;
62 my $x = new SOAP::Transport::HTTP::CGI;
63 # fill in your server path below...
64 $x->dispatch_to('WWW_SERVER_PATH', 'MOBY::Central');
68 ---------------------------------------
72 use SOAP::Lite +autodispatch =>
73 proxy => 'http://mobycentral.icapture.ubc.ca/cgi-bin/MOBY05/mobycentral.pl',
76 die ref $res ? $res->faultstring : $soap->transport->status, "\n";
79 my $NAMES_XML = MOBY::Central->retrieveObjectNames;
81 # ... do something with the XML
83 ----------------------------------------
88 Used to do various transactions with MOBY-Central registry, including registering
89 new Object and Service types, querying for these types, registering new
90 Servers/Services, or queryiong for available services given certain input/output
91 or service type constraints.
97 This depends on a config file to get its database connection information. At a minimum
98 this config file must have the following clause:
108 The space before and after the '=' is critical.
110 The end of a clause is indicated by a blank line.
112 Additional identically formatted clauses may be added for each of:
119 if these ontologies are being served from a local database (via the
120 OntologyServer module). These clauses will be read by the OntologyServer
121 module if they are present, otherwise default connections will be made
122 to the MOBY Central ontology server.
124 The config file must be readable by the webserver, and the webserver
125 environment should include the following ENV variable:
127 $ENV{MOBY_CENTRAL_CONFIG} = /path/to/config/file.name
132 Mark Wilkinson (markw@illuminae.com)
134 BioMOBY Project: http://www.biomoby.org
138 =head1 Registration XML Object
140 This is sent back to you for all registration and
144 <success>$success</success>
146 <message><![CDATA[$message]]></message>
150 success is a boolean indicating a
151 successful or a failed registration
153 id is the deregistration ID of your registered
154 object or service to use in a deregister call.
156 message will contain any additional information
157 such as the reason for failure.
164 my $id = $details->{id
};
165 my $success = $details->{success
};
166 my $message = $details->{message
};
168 $RDF = $details->{RDF
};
170 # return "<MOBYRegistration>
172 # <success>$success</success>
173 # <message><![CDATA[$message]]></message>
174 # <RDF><![CDATA[$RDF]]></RDF>
175 # </MOBYRegistration>";
176 return "<MOBYRegistration>
178 <success>$success</success>
179 <message><![CDATA[$message]]></message>
181 </MOBYRegistration>";
203 my ( $caller, %args ) = @_;
204 print STDERR
"\nuse of MOBY::Central->new is deprecated\n";
208 =head2 registerObjectClass
210 The registerObjectClass call is:
214 =item * used to register a new object Class into the Class ontology
216 =item * can envision this as simply registering a new node into the Class ontology graph, and creating the primary connections from that node.
218 =item * MOBY, by default, supports three types of Class Relationships: ISA, HAS, and HASA (these are the relationship ontology terms)
222 =item * Foo ISA bar is a straight inheritence, where all attributes of bar are guaranteed to be present in foo.
224 =item * foo HAS bar is a container type, where bar is an object inside of foo in one or more copies.
226 =item * foo HASA bar is a container type, where bar is an object inside of foo in one copy only
230 =item * notice that, in a HAS and HASA relationships, it is necessary to indicate an article name for each contained object type. Thus, for example, you could have a sequence object that contained a String object with name "nucleotideSequence" and an Integer object with the name "sequenceLength".
236 <registerObjectClass>
237 <objectType>NewObjectType</objectType>
238 <Description><![CDATA[
239 human readable description
242 <Relationship relationshipType="RelationshipOntologyTerm">
243 <objectType articleName="SomeName">ExistingObjectType</objectType>
249 <authURI>Your.URI.here</authURI>
250 <contactEmail>You@your.address.com</contactEmail>
251 </registerObjectClass>
256 ...Registration Object...
261 sub registerObjectClass
{
263 # this contacts the ontology server to register
264 # the ontology and writes the resulting URI into
265 # the MOBY Central database
266 my ( $pkg, $payload ) = @_;
267 my ( $success, $message );
268 my $OntologyServer = &_getOntologyServer
( ontology
=> 'object' );
269 my $RelOntologyServer = &_getOntologyServer
( ontology
=> 'relationship' );
270 my ( $term, $desc, $relationships, $email, $auth, $clobber ) =
271 &_registerObjectPayload
($payload);
273 unless ( defined $term && defined $desc && defined $auth && defined $email )
275 if ( $term =~ /FAILED/ ) { return &_error
( "Malformed XML;", "" ); }
276 return &_error
("Malformed XML; may be missing required parameters objectType, Description, authURI or contactEmail",
280 return &_error
( "Malformed authURI - must not have an http:// prefix", "" )
282 return &_error
( "Malformed authURI - must take the form NNN.NNN.NNN", "" )
283 unless $auth =~ /\./;
284 return &_error
("Malformed email - must be a valid email address of the form name\@organization.foo",
287 unless $email =~ /\S\@\S+\.\S+/;
288 return &_error
("Object name may not contain spaces or other characters invalid in a URN",
291 if $term =~ /\s\"\&\<\>\[\]\^\`\{\|\}\~/;
292 if ( $term =~ m
"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?" )
294 return &_error
( "Object name may not be an URN or URI", "" ) if $1;
298 # validate that the final ontology will be valid by testing against existing relationships and such
299 while ( my ( $reltype, $obj ) = each %{$relationships} ) {
300 my ( $success, $message, $URI ) =
301 $RelOntologyServer->relationshipExists(
304 ); # success = 1 if it does
305 ($success == 0) && return &_error
( $message, $URI );
306 foreach ( @
{$obj} ) {
307 ++$ISAs if ( $URI =~ /isa$/i );
308 my ( $objectType, $articleName ) = @
{$_};
309 my ( $success, $message, $URI ) =
310 $OntologyServer->objectExists( term
=> $objectType )
311 ; # success = 1 if it does
312 ($success == 0) && return &_error
( $message, $URI );
316 "Object must have exactly one ISA parent in the MOBY Object ontology")
318 $clobber = defined($clobber) ?
$clobber : 0;
320 unless ( $clobber eq 0 || $clobber eq 1 || $clobber eq 2 ); # safety!
321 my ( $exists, $exists_message, $URI ) =
322 $OntologyServer->objectExists( term
=> $term ); # success = 1 if it does
323 ( ( $exists == 1 && !$clobber )
324 && return &_error
( "Object $term already exists", $URI ) );
327 ; # it makes no sense to clobber something that doesnt' exist
330 if ( $clobber == 1 ) {
331 my ( $success, $message ) =
332 $OntologyServer->deprecateObject( term
=> $term );
333 ($success == 0) && return &_error
( $message, $URI );
335 elsif ( $clobber == 2 ) {
336 my ( $success, $message ) =
337 $OntologyServer->deleteObject( term
=> $term );
338 ($success == 0) && return &_error
( $message, $URI );
342 # now test if the object inherits from primitives... if so, abort
343 if ( keys %{$relationships} ) {
344 while ( my ( $reltype, $obj ) = each %{$relationships} ) {
345 next unless ($reltype =~ /isa/i); # we are only testing isa relationships here.
346 foreach ( @
{$obj} ) {
347 my ( $objectType, $articleName ) = @
{$_};
348 if (&_testObjectTypeAgainstPrimitives
($objectType)){
349 return &_error
( "Inheritance from Primitive data-types is now deprecated. You shold construct your object using a HASA relationship. for example, text-plain HASA string (as opposed to ISA string)", "" );
355 # should be good to go now...
358 ( $success, $message, $URI ) = $OntologyServer->createObject(
360 description
=> $desc,
362 contact_email
=> $email
364 ($success == 0) && return &_error
( $message, $URI );
367 if ( keys %{$relationships} ) { # need to pull them out with ISA's first
368 foreach my $reltype(qw{ISA HASA HAS
}){
369 my ( $obj ) = $relationships->{$reltype};
370 foreach ( @
{$obj} ) {
371 my ( $objectType, $articleName ) = @
{$_};
372 my ( $success, $message ) =
373 $OntologyServer->addObjectRelationship(
374 subject_node
=> $term,
375 relationship
=> $reltype,
376 object_node
=> $objectType,
377 articleName
=> $articleName,
379 contact_email
=> $email
382 push @failures, $objectType;
383 $messages .= $message."; ";
388 if ( scalar(@failures) ) {
389 my ( $success, $message, $deleteURI ) =
390 $OntologyServer->deleteObject( term
=> $term )
391 ; # hopefully this situation will never happen!
392 ($success == 0) && return &_error
(
393 "object failed ISA and/or HASA connections,
394 and subsequently failed deletion. This is a critical error,
395 and may indicate corruption of the MOBY Central registry.", $deleteURI
397 return &_error
("object failed to register due to failure during registration of ISA/HASA relationships. Message returned was $messages"
398 . ( join ",", (@failures) ) . "\n",
402 return &_success
( "Object $term registered successfully.", $URI );
406 sub _registerObjectPayload
{
407 my ($payload) = @_; #EDDIE - assuming that payload is a string
408 my $Parser = XML
::LibXML
->new();
409 my $doc = $Parser->parse_string($payload);
410 my $Object = $doc->documentElement();
411 my $obj = $Object->nodeName;
412 return undef unless ( $obj eq 'registerObjectClass' );
413 my $term = &_nodeTextContent
( $Object, "objectType" );
414 my $desc = &_nodeCDATAContent
( $Object, "Description" );
415 my $authURI = &_nodeTextContent
( $Object, "authURI" );
416 my $email = &_nodeTextContent
( $Object, "contactEmail" );
417 my $clobber = &_nodeTextContent
( $Object, "Clobber" );
419 #my @ISA = &_nodeArrayContent($Object, "ISA");
420 #my @HASA = &_nodeArrayExtraContent($Object, "HASA","articleName");
423 my $x = $doc->getElementsByTagName("Relationship");
424 my $no_relationships = $x->size;
425 for ( my $n = 1 ; $n <= $no_relationships ; ++$n ) {
426 my $relationshipType =
427 $x->get_node($n)->getAttributeNode('relationshipType')
428 ; # may or may not have a name
429 if ($relationshipType) {
430 $relationshipType = $relationshipType->getValue();
434 "FAILED! must include a relationshipType in every relationship\n";
436 my @child = $x->get_node($n)->childNodes;
438 next unless $_->nodeType == ELEMENT_NODE
;
440 $_->getAttributeNode('articleName'); # may or may not have a name
441 if ($article) { $article = $article->getValue() }
442 my @child2 = $_->childNodes;
445 #print getNodeTypeName($_), "\t", $_->toString,"\n";
446 next unless $_->nodeType == TEXT_NODE
;
447 push @
{ $relationships{$relationshipType} },
448 [ $_->toString, $article ];
452 return ( $term, $desc, \
%relationships, $email, $authURI, $clobber );
455 sub _testObjectTypeAgainstPrimitives
{
456 # THIS SUBROUTINE NEEDS TO BE REMOVED AND PLACED INTO THE ONTOLOGY SERVER
457 # one day when MOBY Central and the ontologies are separated properly
459 my $OS = MOBY
::OntologyServer
->new(ontology
=> 'object');
461 my ($success, $desc, $inputlsid) = $OS->objectExists(term
=> $type);
463 my $CONF = MOBY
::Config
->new;
464 my @primitives = @
{$CONF->primitive_datatypes}; # get the list of known primitive datatypes
465 my $x = 0; # set flag down
466 # convert everything to an LSID first
468 my @primitive_lsids = map{my ($s, $d, $l) = $OS->objectExists(term
=> $_); $l} @primitives;
470 map {($x=1) if ($inputlsid eq $_)} @primitive_lsids; # test primitives against this one
472 my $OSrel = MOBY
::OntologyServer
->new(ontology
=> 'relationship');
473 my ($exists1, $desc2, $isalsid) = $OSrel->relationshipExists(term
=> 'isa', ontology
=> 'object');
475 my $relationships = $OS->Relationships(
476 ontology
=> 'object',
478 relationship
=> $isalsid,
481 #relationships{relationship} = [[lsid1,articleNmae], [lsid2, articleName], [lsid3, articleName]]
482 my ($isa) = keys(%$relationships); # can only be one key returned, and must be isa in this case
484 (@ISAlist = @
{$relationships->{$isa}}) if ($relationships->{$isa}) ;
485 # for each of the inherited parents, check their articleNames
486 foreach my $ISA(@ISAlist){ # $ISA = [lsid, articleName] (but articleName shuld be null anyway in this case)
487 my $what_it_is = $ISA->{lsid
};
488 # my $articleName = $ISA->{articleName}
489 map {($x=1) if ($what_it_is eq $_)} @primitive_lsids; # test primitives against this one
491 return $x; # return flag state
496 =head2 deregisterObjectClass
500 =item * used to remove an Object Class from the Class ontology
502 =item * this will not be successful until you respond positively to an email sent to the address that you provided when registering that object.
504 =item * you may only deregister Classes that you yourself registered!
506 =item * you may not deregister Object Classes that are being used as input or output by ANY service
508 =item * you may not deregister Object Classes that are in a ISA or HASA relationship to any other Object Class.
515 <deregisterObjectClass>
516 <objectType>ObjectOntologyTerm</objectType>
517 </deregisterObjectClass>
521 ...Registration Object...
525 sub deregisterObjectClass
{
526 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
527 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
529 my ( $pkg, $payload ) = @_;
530 my $OntologyServer = &_getOntologyServer
( ontology
=> 'object' );
531 return &_error
( "Message Format Incorrect", "" ) unless ($payload);
532 my ($class) = &_deregisterObjectPayload
($payload);
533 $debug && &_LOG
("deregister object type $class\n");
534 return &_error
( "Must include class of object to deregister", "" )
536 my ( $success, $message, $existingURI ) =
537 $OntologyServer->objectExists( term
=> $class );
538 return &_error
( "Object class $class does not exist", "" )
539 unless ($existingURI);
541 my $errormsg = $adaptor->check_object_usage(type
=> $existingURI);
543 "Object class $class is used by a service and may not be deregistered",
548 my ( $success2, $message2, $URI ) =
549 $OntologyServer->deleteObject( term
=> $class );
550 ($success2 == 0) && return &_error
( $message2, $URI );
551 return &_success
( $message2, $URI );
555 sub _deregisterObjectPayload
{
557 my $Parser = XML
::LibXML
->new();
558 my $doc = $Parser->parse_string($payload);
559 my $Object = $doc->getDocumentElement();
560 my $obj = $Object->nodeName;
561 return undef unless ( $obj eq 'deregisterObjectClass' );
562 return &_nodeTextContent
( $Object, "objectType" );
565 =head2 registerServiceType
570 =item * used to register a new node in the Service Ontology
572 =item * the ISA ontology terms must exist or this registration will fail.
574 =item * all parameters are required.
576 =item * email must be valid for later deregistration or updates
583 <registerServiceType>
584 <serviceType>NewServiceType</serviceType>
585 <contactEmail>your_name@contact.address.com</contactEmail>
586 <authURI>Your.URI.here</authURI>
588 <![CDATA[ human description of service type here]]>
590 <Relationship relationshipType="RelationshipOntologyTerm">
591 <serviceType>ExistingServiceType</serviceType>
592 <serviceType>ExistingServiceType</serviceType>
594 <Relationship relationshipType="AnotherRelationship">
597 </registerServiceType>
602 ...Registration Object...
606 sub registerServiceType
{
608 # this contacts the ontology server to register
609 # the ontology and writes the resulting URI into
610 # the MOBY Central database
611 my ( $pkg, $payload ) = @_;
612 my ( $success, $message, $URI );
613 my $OntologyServer = &_getOntologyServer
( ontology
=> 'service' );
616 "\n\npayload\n**********************\n$payload\n***********************\n\n"
618 my ( $term, $desc, $relationships, $email, $auth ) =
619 &_registerServiceTypePayload
($payload);
622 "\n\nterm $term\ndesc $desc\nrel $relationships\nemail $email\nauth $auth"
624 unless ( defined $term && defined $desc && defined $auth && defined $email )
627 if ( $term =~ /FAILED/ ) {
628 return &_error
( "Malformed XML\n $term", "" );
631 "Malformed XML\n may be missing required parameters serviceType, Description, authURI or contactEmail",
635 return &_error
( "Malformed authURI - must not have an http:// prefix", "" )
637 return &_error
( "Malformed authURI - must take the form NNN.NNN.NNN", "" )
638 unless $auth =~ /\./;
640 "Malformed email - must be a valid email address of the form name\@organization.foo",
643 unless $email =~ /\S\@\S+\.\S+/;
645 # validate that the final ontology will be valid
646 my ( $exists, $exists_message, $existingURI ) =
647 $OntologyServer->serviceExists( term
=> $term ); # success = 1 if it does
649 && return &_error
( "Service type $term already exists", $existingURI )
652 # is the relationship valid?
653 my $OSrel = MOBY
::OntologyServer
->new( ontology
=> 'relationship' );
654 if ( keys %{$relationships} ) {
655 while ( my ( $reltype, $obj ) = each %{$relationships} ) {
656 my ( $success, $desc, $URI ) = $OSrel->relationshipExists(
658 ontology
=> 'service'
660 ( !$success ) && return &_error
(
661 "Relationship type $reltype does not exist in the relationship ontology",
667 # are the predicate service types valid?
668 my $OSsrv = MOBY
::OntologyServer
->new( ontology
=> 'service' );
669 if ( keys %{$relationships} ) {
670 while ( my ( $srvtype, $svcs ) = each %{$relationships} ) {
671 foreach my $svc ( @
{$svcs} ) {
672 my ( $success, $desc, $URI ) =
673 $OSsrv->serviceExists( term
=> $svc );
674 ( !$success ) && return &_error
(
675 "Service type $srvtype does not exist in the service ontology",
682 # hunky dorey. Now register!
683 ( $success, $message, $URI ) = $OntologyServer->createServiceType(
685 description
=> $desc,
687 contact_email
=> $email
689 ($success == 0) && return &_error
( $message, $URI );
691 if ( keys %{$relationships} ) {
692 while ( my ( $reltype, $obj ) = each %{$relationships} ) {
693 foreach my $serviceType ( @
{$obj} ) {
694 my ( $success, $message ) =
695 $OntologyServer->addServiceRelationship(
696 subject_node
=> $term,
697 relationship
=> $reltype,
698 object_node
=> $serviceType,
700 contact_email
=> $email
702 ($success == 0) && push @failures, $serviceType;
706 if ( scalar(@failures) ) {
707 my ( $success, $message, $deleteURI ) =
708 $OntologyServer->deleteServiceType( term
=> $term )
709 ; # hopefully this situation will never happen!
710 ($success == 0) && return &_error
(
711 "Service registration failed ISA connections,
712 and subsequently failed deletion. This is a critical error,
713 and may indicate corruption of the MOBY Central registry", $deleteURI
716 "Service failed to register due to failure during registration of relationships"
717 . ( join ",", (@failures) ) . "\n",
721 return &_success
( "Service type $term registered successfully.", $URI );
725 sub _registerServiceTypePayload
{
727 $debug && &_LOG
("_registerServiceTypePayload payload=$payload\n");
728 my $Parser = XML
::LibXML
->new();
729 my $doc = $Parser->parse_string($payload);
730 my $Object = $doc->getDocumentElement();
731 my $obj = $Object->nodeName;
732 return undef unless ( $obj eq 'registerServiceType' );
733 my $type = &_nodeTextContent
( $Object, "serviceType" );
734 my $email = &_nodeTextContent
( $Object, "contactEmail" );
735 my $auth = &_nodeTextContent
( $Object, "authURI" );
736 my $desc = &_nodeCDATAContent
( $Object, "Description" );
738 my $x = $doc->getElementsByTagName("Relationship");
739 my $no_relationships = $x->size();
741 for ( my $n = 1 ; $n <= $no_relationships ; ++$n ) {
742 my $relationshipType =
743 $x->get_node($n)->getAttributeNode('relationshipType')
744 ; # may or may not have a name
745 if ($relationshipType) {
746 $relationshipType = $relationshipType->getValue();
750 "FAILED! must include a relationshipType in every relationship\n";
752 my @child = $x->get_node($n)->childNodes;
754 next unless $_->nodeType == ELEMENT_NODE
;
755 my @child2 = $_->childNodes;
758 #print getNodeTypeName($_), "\t", $_->toString,"\n";
759 next unless $_->nodeType == TEXT_NODE
;
760 push @
{ $relationships{$relationshipType} }, $_->toString;
766 "got $type, $desc, \%relationships, $email, $auth from registerServiceTypePayload\n"
768 return ( $type, $desc, \
%relationships, $email, $auth );
771 =head2 deregisterServiceType
775 =item * used to deregister a Service term from the Service ontology
777 =item * will fail if any services are instances of that Service Type
779 =item * will fail if any Service Types inherit from that Service Type.
786 <deregisterServiceType>
787 <serviceType>ServiceOntologyTerm</serviceType>
788 </deregisterServiceType>
792 ...Registration Object...
796 sub deregisterServiceType
{
797 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
798 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
800 my ( $pkg, $payload ) = @_;
801 my $OntologyServer = &_getOntologyServer
( ontology
=> 'service' );
802 return &_error
( "Message Format Incorrect", "" ) unless ($payload);
803 my ($term) = &_deregisterServiceTypePayload
($payload);
804 $debug && &_LOG
("deregister serviceType accession $term\n");
806 "Must include an accession number to deregister a serviceType", "" )
808 my ( $success, $message, $existingURI ) = $OntologyServer->serviceExists( term
=> $term ); # hopefully this situation will never happen!
809 return &_error
( "Service Type $term does not exist in the ontology", "" )
810 unless ($existingURI);
812 my $result = $adaptor->query_service_instance(service_type_uri
=> $existingURI);
813 my $row = shift(@
$result);
814 my $lsid = $row->{lsid
};
816 return &_error
( "A registered service depends on this service type", "" )
818 my ( $success2, $message2, $deleteURI ) =
819 $OntologyServer->deleteServiceType( term
=> $term )
820 ; # hopefully this situation will never happen!
821 (($success2 == 0)) && return &_error
( $message2, $deleteURI );
822 return &_success
( "Service type $term deleted.", $deleteURI );
826 sub _deregisterServiceTypePayload
{
828 my $Parser = XML
::LibXML
->new();
829 my $doc = $Parser->parse_string($payload);
830 my $Object = $doc->getDocumentElement();
831 my $obj = $Object->nodeName; #Eddie- unsure
832 return undef unless ( $obj eq 'deregisterServiceType' );
833 return &_nodeTextContent
( $Object, "serviceType" );
836 =head2 registerNamespace
841 =item * used to register a new Namespace in the Namespace controlled vocabulary
843 =item * must provide a valid email address
845 =item * all parameters are required.
853 <namespaceType>NewNamespaceHere</namespaceType>
854 <contactEmail>your_name@contact.address.com</contactEmail>
855 <authURI>Your.URI.here</authURI>
857 <![CDATA[human readable description]]>
863 ...Registration Object...
868 sub registerNamespace
{
870 # this contacts the ontology server to register
871 # the ontology and writes the resulting URI into
872 # the MOBY Central database
873 my ( $pkg, $payload ) = @_;
874 my ( $success, $message );
875 my $OntologyServer = &_getOntologyServer
( ontology
=> 'namespace' );
878 "\n\npayload\n**********************\n$payload\n***********************\n\n"
880 my ( $term, $auth, $desc, $email ) = &_registerNamespacePayload
($payload);
881 $debug && &_LOG
("\n\nterm $term\ndesc $desc\nemail $email\nauth $auth");
882 unless ( defined $term && defined $desc && defined $auth && defined $email )
885 "Malformed XML; may be missing required parameters namespaceType, Description, authURI or contactEmail",
889 return &_error
( "Malformed authURI - must not have an http:// prefix", "" )
891 return &_error
( "Malformed authURI - must take the form NNN.NNN.NNN", "" )
892 unless $auth =~ /\./;
894 "Malformed email - must be a valid email address of the form name\@organization.foo",
897 unless $email =~ /\S\@\S+\.\S+/;
898 my ( $exists, $exists_message, $URI ) =
899 $OntologyServer->namespaceExists( term
=> $term )
900 ; # success = 1 if it does
902 && return &_error
( "Namespace $term already exists", $URI ) );
903 ( $success, $message, $URI ) = $OntologyServer->createNamespace(
905 description
=> $desc,
907 contact_email
=> $email
909 ($success == 0) && return &_error
( $message, $URI );
910 return &_success
( "Namespace type $term registered successfully.", $URI );
914 sub _registerNamespacePayload
{
916 my $Parser = XML
::LibXML
->new();
917 my $doc = $Parser->parse_string($payload);
918 my $Object = $doc->getDocumentElement();
919 my $obj = $Object->nodeName;
920 return undef unless ( $obj eq 'registerNamespace' );
921 my $type = &_nodeTextContent
( $Object, "namespaceType" );
922 my $authURI = &_nodeTextContent
( $Object, "authURI" );
923 my $desc = &_nodeCDATAContent
( $Object, "Description" );
924 my $contact = &_nodeTextContent
( $Object, "contactEmail" );
925 return ( $type, $authURI, $desc, $contact );
928 =head2 deregisterNamespace
932 =item * used to remove a Namespace from the controlled vocabulary
934 =item * will fail if that namespace is being used by any services
936 =item * you will recieve an email for confirmation of the deregistration
943 <deregisterNamespace>
944 <namespaceType>MyNamespace</namespaceType>
945 </deregisterNamespace>
949 ...Registration Object...
954 sub deregisterNamespace
{
955 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
956 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
958 my ( $pkg, $payload ) = @_;
959 my $OntologyServer = &_getOntologyServer
( ontology
=> 'namespace' );
960 return &_error
( "Message Format Incorrect", "" ) unless ($payload);
961 my ($term) = &_deregisterNamespacePayload
($payload);
962 $debug && &_LOG
("deregister namespaceType accession $term\n");
963 return &_error
( "Must include a Namespace type to deregister.", "" )
965 my ( $success, $message, $existingURI ) =
966 $OntologyServer->namespaceExists( term
=> $term );
967 return &_error
( "Namespace Type $term does not exist", "" )
968 unless ($existingURI);
969 my ($err, $errstr) = $adaptor->check_namespace_usage(namespace_type_uris
=> $existingURI,
971 return &_error
( $errstr, "")
974 my ( $success2, $message2, $URI ) =
975 $OntologyServer->deleteNamespace( term
=> $term );
976 ($success2 == 0) && return &_error
( $message2, $URI );
977 return &_success
( "Namespace type $term deregistered successfully.", $URI );
981 sub _deregisterNamespacePayload
{
983 my $Parser = XML
::LibXML
->new();
984 my $doc = $Parser->parse_string($payload);
985 my $Object = $doc->getDocumentElement();
986 my $obj = $Object->nodeName;
987 return undef unless ( $obj eq 'deregisterNamespace' );
988 return &_nodeTextContent
( $Object, "namespaceType" );
991 =head2 registerService
995 =item * all elements are required
997 =item * a service must have at least one Input OR Output Object Class. Either Input or Output may be blank to represent "PUT" or "GET" services respectively
999 =item * the contactEmail address must be valid, as it is used to authorize deregistrations and changes to the service you registered.
1001 =item * the "authoritativeService" tag is used to indicate whether or not the registered service is "authoritative" for that transformation. i.e. if anyone else were to perform the same transformation they would have to have obtained the information to do so from you. This is similar to, but not necessarily identical to, mirroring someone elses data, since the data in question may not exist prior to service invocation.
1003 =item * only Input Secondary articles are defined during registration; Output Secondary objects are entirely optional and may or may not be interpreted Client-side using their articleName tags.
1005 =item * Service Categories:
1009 =item * moby - for services that use the MOBY SOAP messaging format and object structure (i.e. the objects used in service transaction inherit from the root 'Object' Class in the MOBY Class ontology).
1013 =item * authURI - a URI representing your organization (e.g. yourdomain.com); no http-prefix, and no trailing path information is allowed.
1015 =item * serviceName - an arbitrary, but unique, name for your service within your authURI namespace
1017 =item * URL - the URL to a SOAP CGI server that can invoke a method as described by your serviceName
1021 =item * wsdl - for other SOAP services that do not use the MOBY messaging format. The other elements in the registration should be interpreted as follows:
1025 =item * authURI - a URI representing your organization (e.g. yourdomain.com); no http-prefix, and no trailing path information is allowed.
1027 =item * serviceName - an arbitrary, but unique, name for your service within your authURI namespace
1029 =item * URL - the URL from which a WSDL document describing your service can be retrieved by an HTTP GET call.
1033 =item * Comments about Input and Output for MOBY and non-MOBY services
1037 =item * in "moby" services, the input and output messaging structure is defined by the BioMOBY API, and the services use data Objects that are defined in the Class ontology as inheriting from the root "Object" Class.
1039 =item * For "wsdl" services, there is additional flexibility:
1043 =item * Similar to a "moby" service, your "wsdl" service must consume/produce named data types. These are represented as LSID's
1045 =item * YOU DO NOT NEED TO REGISTER THESE DATA TYPES in MOBY Central; it is up to you what your LSID's represent, and MOBY Central WILL NOT try to resolve them!
1047 =item * You may mix ontologies when describing your service - i.e. you may freely use any MOBY Object as your input or (XOR) your output and use a non-MOBY object (LSID) for the alternate so long as you follow the MOBY message structure for the parameter that uses the MOBY Object
1051 =item * You may register, for example, a service that consumes a non-MOBY data Class and outputs a MOBY data class, so long as you follow the MOBY Messaging format for the output data
1053 =item * You may register, for example, a service that consumes a MOBY data Class and outputs a non-MOBY data class, so long as you follow the MOBY Messaging format for the input data
1055 =item * NOTE: Nether of the cases above are considered MOBY services, and are therefore described in the category of "soap" service
1061 =item * secondaryArticles - not applicable; should be left out of message.
1073 <Category>moby</Category> <!-- one of 'moby', 'cgi', 'wsdl' ; currently only 'moby' and 'wsdl' services are fully supported -->
1074 <serviceName>YourServiceNameHere</serviceName>
1075 <serviceType>TypeOntologyTerm</serviceType>
1076 <authURI>your.URI.here</authURI>
1077 <URL>http://URL.to.your/Service.script</URL>;
1078 <contactEmail>your_name@contact.address.com</contactEmail>
1079 <authoritativeService>1 | 0 </authoritativeService>
1080 <Description><![CDATA[
1081 human readable COMPREHENSIVE description of your service]]>
1084 <!-- zero or more Primary (Simple and/or Collection) articles -->
1087 <!-- zero or more INPUT Secondary articles -->
1088 </secondaryArticles>
1090 <!-- zero or more Primary (Simple and/or Collection) articles -->
1096 ...Registration Object...
1098 There are two forms of Primary articles:
1102 =item * Simple - the article consists of a single MOBY Object
1104 =item * Collection - the article consists of a collection ("bag") of MOBY Objects (not necessarily the same object type).
1108 =item * Their number/order is not relevant, nor predictable
1110 =item * If order is important to the service provider, then a collection should not be used, rather the collection should be broken into named Simple parameters. This may impose limitations on the the types of services that can be registered in MOBY Central. If it becomes a serious problem, a new Primary article type will be added in a future revision.
1112 =item * The use of more than one Class in a collection is difficult to interpret, though it is equally difficult to envision a service that would require this. It is purposely left losely defined since any given Service Instance can tighten up this definition during the registration process.
1114 =item * A collection may contain zero or more Objects of each of the Classes defined in the XML during Service Instance registration.
1118 =item * Each distinct Object Class only needs to be included once in the XML. Additional entries of that Class within the same Collection definition must be ignored.
1126 An example of the use of each of these might be another BLAST service, where you provide the sequences that make up the Blast database as well as the sequence to Blast against it. The sequences used to construct the database might be passed as a Collection input article containing multiple Sequence Objects, while the sequence to Blast against it would be a Simple input article consisting of a single Sequence Object.
1128 There is currently only one form of Secondary article:
1132 =item * Secondary - the article may or may not be specifically configured by the client as Input, and may or may not be returned by the Service as output.
1136 =item * In the case of inputs, they are generally user-configurable immediately prior to service invocation.
1138 =item * During service invocation a Client must send all Secondary articles defined in the Service Instance, even if no value has been provided either as default, or Client-side.
1140 =item * Secondary articles that are considered "required" by the Service should be registered with a default value.
1142 =item * The Service may fail if an unacceptable value is passed for any Secondary Article.
1149 Articles are, optionally, named using the articleName attribute. This might be used if, for example, the service requires named inputs. The order of non-named articles in a single Input or Output set MUST not be meaningful.
1151 The XML structure of these articles is as follows:
1155 =item * Simple (note that the lsid attribute of the objectType and Namespace element need only be present in the article when it is present in a response document from MOBY Central such as the result of a findService call. These attributes are ignored by MOBY Central when they appear in input messages such as registerService)
1157 <Simple articleName="NameOfArticle">
1158 <objectType lsid='urn:lsid:...'>ObjectOntologyTerm</objectType>
1159 <Namespace lsid='urn:lsid:...'>NamespaceTerm</Namespace>
1160 <Namespace lsid='urn:lsid:...'>...</Namespace><!-- one or more... -->
1163 =item * Collection note that articleName of the contained Simple objects is not required, and is ignored.
1166 <Collection articleName="NameOfArticle">
1167 <Simple>......</Simple> <!-- Simple parameter type structure -->
1168 <Simple>......</Simple> <!-- DIFFERENT Simple parameter type (used only when multiple Object Classes appear in a collection) -->
1174 <Parameter articleName="NameOfArticle">
1175 <datatype>Integer|Float|String|DateTime</datatype>
1176 <default>...</default> <!-- any/all of these -->
1177 <max>...</max> <!-- ... -->
1178 <min>...</min> <!-- ... -->
1179 <enum>...<enum> <!-- ... -->
1180 <enum>...<enum> <!-- ... -->
1188 # inputXML (FOR CGI GET SERVICES):
1190 # <Category>cgi</Category>
1191 # <serviceName>YourServiceNameHere</serviceName>
1192 # <serviceType>YourServiceTypeHere</serviceType>
1193 # <authURI>your.URI.here</authURI>
1194 # <contactEmail>blah@blow.com</contactEmail>
1195 # <URL>http://URL.to.your/CGI.pl</URL>
1196 # <authoritativeService>your.URI.here</authoritativeService>
1198 # <!-- zero or more pimary (simple or collection) articles -->
1201 # <!-- zero or more pimary (simple or collection) articles -->
1203 # <secondaryArticles>
1204 # </secondaryArticles>
1205 # <Description><![CDATA[
1206 # human readable description of your service]]>
1208 # </registerService>
1210 sub registerService
{
1211 my ( $pkg, $payload ) = @_;
1213 $serviceName, $serviceType, $AuthURI,
1214 $contactEmail, $URL, $authoritativeService,
1215 $desc, $Category, $INPUTS,
1216 $OUTPUTS, $SECONDARY, $signatureURL
1218 = &_registerServicePayload
($payload);
1220 #--------RDFagent call----------------------------------------
1222 if ( defined $signatureURL ) {
1225 foreach $i ( $serviceName, $serviceType, $AuthURI, $contactEmail, $URL,
1235 my $conf = MOBY
::Config
->new();
1236 my $path = $conf->{mobycentral
}->{rdfagent
};
1237 my $rez = system( $path. " " . $signatureURL );
1238 return &_success
( "The RDFagent call was successful. Report will send to you by E-mail",
1243 "Some problem with a connection or RDF model building", "" )
1248 #---------------------------------------------------------------
1249 $authoritativeService = defined($authoritativeService) ?
1 : 0;
1251 $error .= "missing serviceName \n" unless defined $serviceName;
1252 $error .= "missing serviceType \n" unless defined $serviceType;
1253 $error .= "invalid character string for serviceName. Must start with a letter followed by [A-Za-z0-9_]\n" if ($serviceName =~ /^[^A-Za-z]/);
1254 $error .= "invalid character string for serviceName. Must start with a letter followed by [A-Za-z0-9_]\n" if ($serviceName =~ /^.+?[^A-Za-z0-9_]/);
1256 # $error .="missing signatureURL \n" unless defined $signatureURL;
1257 $error .= "missing authURI \n" unless defined $AuthURI;
1258 $error .= "missing contactEmail \n" unless defined $contactEmail;
1259 return &_error
( "Malformed authURI - must not have an http:// prefix", "" )
1260 if $AuthURI =~ '[/:]';
1261 return &_error
( "Malformed authURI - must take the form NNN.NNN.NNN", "" )
1262 unless $AuthURI =~ /\./;
1263 return &_error
("Malformed email - must be a valid email address of the form name\@organization.foo","")
1264 unless $contactEmail =~ /\S\@\S+\.\S+/;
1265 $error .= "missing URL \n" unless defined $URL;
1266 $error .= "missing description \n" unless defined $desc;
1267 $error .= "missing Category \n" unless defined $Category;
1268 return &_error
( "malformed payload $error\n\n", "" ) if ($error);
1270 "Category may take the (case sensitive) values 'moby', 'cgi', 'soap'\n",
1274 ( $Category eq "wsdl" )
1276 # || ($Category eq "cgi")
1277 || ( $Category eq "moby" )
1279 $debug && &_LOG
("Entering switch with $Category method\n");
1280 return &_error
("Service categories other than 'moby' and 'wsdl' are not yet implemented","")
1281 unless ( ( $Category eq "moby" ) || ( $Category eq "wsdl" ) );
1283 #test the existence of the service
1284 return &_error
( "This service already exists", "" ) if (MOBY
::service_instance
->new(
1285 servicename
=> $serviceName,
1286 authority_uri
=> $AuthURI,
1290 my @IN = @
{$INPUTS};
1291 my @OUT = @
{$OUTPUTS};
1292 my @SECS = @
{$SECONDARY};
1294 "must include at least one input and/or one output object type", "" )
1295 unless ( scalar @IN || scalar @OUT );
1296 my %objects_to_be_validated;
1297 foreach ( @IN, @OUT ) {
1299 foreach my $objectName ( &_extractObjectTypes
($_) ) {
1300 $objects_to_be_validated{$objectName} = 1;
1303 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'object' );
1304 foreach ( keys %objects_to_be_validated ) {
1305 my ( $valid, $message, $URI ) = $OS->objectExists( term
=> $_ );
1306 return &_error
( "$message", "$URI" )
1308 || ( ( $_ =~ /urn:lsid/i ) && !( $_ =~ /urn:lsid:biomoby.org/i ) )
1309 ); # either valid, or a non-moby LSID
1313 "\n\n\aall objects okay - either valid MOBY objects, or LSID's\n");
1314 $OS = MOBY
::OntologyServer
->new( ontology
=> 'service' );
1315 my ( $valid, $message, $URI ) = $OS->serviceExists( term
=> $serviceType );
1317 #print STDERR "\n\nChecking $URI\n\n";
1318 return &_error
( "$message", "$URI" )
1321 || ( ( $serviceType =~ /urn:lsid/i )
1322 && !( $serviceType =~ /urn:lsid:biomoby.org/i ) )
1323 ); # either valid, or a non-MOBY LSID
1324 #print STDERR "\n\nChecking $URI OK!!\n\n";
1325 # right, registration should be successful now!
1326 my $SVC = MOBY
::service_instance
->new(
1327 category
=> $Category,
1328 servicename
=> $serviceName,
1329 service_type
=> $serviceType,
1330 authority_uri
=> $AuthURI,
1332 contact_email
=> $contactEmail,
1333 authoritative
=> $authoritativeService,
1334 description
=> $desc,
1335 signatureURL
=> $signatureURL,
1337 return &_error
( "Service registration failed for unknown reasons", "" ) if ( !defined $SVC );
1339 $debug && &_LOG
("new service instance created\n");
1341 foreach my $IN (@IN) {
1342 my ( $success, $msg ) = &_registerArticles
( $SVC, "input", $IN, undef );
1343 unless ( $success == 1 ){
1344 $SVC->DELETE_THYSELF;
1345 return &_error
("Registration Failed During INPUT Article Registration: $msg", "" )
1348 foreach my $OUT (@OUT) {
1349 my ( $success, $msg ) = &_registerArticles
( $SVC, "output", $OUT, undef );
1350 unless ( $success == 1 ){
1351 $SVC->DELETE_THYSELF;
1352 return &_error
("Registration Failed During OUTPUT Article Registration: $msg", "" )
1355 foreach my $SEC (@SECS) {
1356 my ( $success, $msg ) = &_registerArticles
( $SVC, "secondary", $SEC, undef );
1357 unless ( $success == 1 ){
1358 $SVC->DELETE_THYSELF;
1359 return &_error
("Registration Failed During SECONDARY Article Registration: $msg", "" )
1363 # we're going to do a findService here to find the service that we just created
1364 # and use the resulting XML to create a MOBY::Client::ServiceInstance object
1365 # that we can then use to retrieve the RDF for that service signature.
1366 # this is roundabout, I agree, but it is the most re-usable way to go at
1368 my ( $si, $reg ) = &findService
(
1370 <authURI>$AuthURI</authURI>;
1371 <serviceName>$serviceName</serviceName>;
1375 $SVC->DELETE_THYSELF;
1376 return &_error
("Registration Failed - newly registered service could not be discovered","");
1378 #my $services = MOBY::Client::Central::_parseServices( '', '', $si );
1379 #my $service_instance = shift @{$services};
1381 # my $storage = new RDF::Core::Storage::Memory;
1382 # my $model = new RDF::Core::Model( Storage => $storage );
1383 # my $RDF_MODEL = MOBY::RDF::ServiceInstanceRDF->new(
1385 #service_instance => $service_instance );
1386 # my $RDF_XML = $RDF_MODEL->serialize;
1387 #my $LSID = $service_instance->LSID;
1389 # my $RDF = _getServiceInstanceRDF($LSID);
1392 return &_success
( "Registration successful but LSID resolution error",
1393 $SVC->service_instance_id, "" );
1395 unless ( $RDF =~ /RDF/ ) {
1397 "Registration successful but LSID resolution error $RDF",
1398 $SVC->service_instance_id, "" );
1400 return &_success
( "Registration successful", $SVC->service_instance_id,
1404 sub _getServiceInstanceRDF
{
1405 my ( $self, $LSID ) = @_;
1406 #my $lsid = LS::ID->new($LSID);
1408 my $lsid_error = "";
1412 #use LS::Authority::WSDL::Constants;
1413 #use LS::Client::BasicResolver;
1416 #my $resolver = LS::Client::BasicResolver->new();
1417 #my $authority = $resolver->resolve( lsid => $lsid );
1418 #unless ($authority) {
1419 # $lsid_error .= "The authority for $LSID could not be located";
1422 #return $lsid_error unless $authority;
1423 #$authority->clean_cache();
1425 # my $resource = $authority->getResource($lsid);
1426 # unless ($resource) {
1427 # $lsid_error .= $authority->error_string . " ";
1428 # return $lsid_error;
1431 # my $response = $resource->get_metadata;
1432 # unless ( ref($response) =~ /LS::Service::Response/ ) {
1434 #TODO raise an error
1435 # $lsid_error .= "Metadata response didn't come back";
1436 # return $lsid_error;
1439 # my $rsp = $response->response;
1440 # unless ( ref($rsp) =~ /IO::File/ ) {
1442 #TODO raise an error
1443 # $lsid_error .= "metadata response was not a filehandle";
1453 sub _registerArticles
{
1454 my ( $SVC, $inout, $node, $collid ) = @_
1455 ; # node is a node of the XML dom representing an article to be registered
1456 return ( -1, 'Bad node' ) unless $node->nodeType == ELEMENT_NODE
;
1458 # this is a Simple, Collection, or Parameter object
1459 my $simp_coll = $node->nodeName;
1460 $debug && &_LOG
("TAGNAME in $inout _registerArticle is $simp_coll");
1461 my $article = $node->getAttributeNode("articleName");
1463 if ($article) { $article = $article->getValue() }
1464 $debug && &_LOG
("ARTICLENAME in _registerArticle is $article");
1465 if (lc($inout) eq "input"){
1466 return (-1, "Input Simples and collections are required to have an articleName as of API version 0.86") if (!$article && !$collid);
1469 my ( $object_type, @namespaces );
1470 if ( $simp_coll eq "Collection" ) {
1471 $debug && &_LOG
("Collection!\n");
1473 if ( $inout eq 'input' ) {
1475 $SVC->add_collection_input( article_name
=> $article );
1477 elsif ( $inout eq 'output' ) {
1479 $SVC->add_collection_output( article_name
=> $article );
1482 $SVC->DELETE_THYSELF;
1483 return ( -1, "found article that was neither input nor output" );
1486 my $Simples = $node->getElementsByTagName('Simple');
1487 my $length = $Simples->size();
1488 unless ( $length > 0 ) {
1489 return ( -1,"Your collection must be a collection of one Simple type"
1492 unless ( $length == 1 ) {
1493 return ( -1,"As of API v0.86, Collections must not be of more than one Simple type"
1496 for ( my $x = 1 ; $x <= $length ; ++$x ) {
1497 my ( $success, $message ) = &_registerArticles
( $SVC, $inout, $Simples->get_node($x), $collection_id );
1498 unless ( $success == 1 ) { return ( -1, $message ); }
1500 } elsif ( $simp_coll eq "Simple" ) {
1501 my $article = $node->getAttributeNode("articleName");
1502 $article = $article->getValue() if $article;
1504 # get object type and its URI from the ontoogy server
1505 my $types = $node->getElementsByTagName('objectType');
1506 my $OE = MOBY
::OntologyServer
->new( ontology
=> "object" );
1507 foreach ( $types->get_node(1)->childNodes ) { # should only ever be one!
1508 ( $_->nodeType == TEXT_NODE
) && ( $object_type = $_->toString );
1510 my ( $success, $message, $typeURI ) =
1511 $OE->objectExists( term
=> $object_type );
1512 if ( ( !($success) && ( $object_type =~ /urn:lsid:biomoby.org/i ) )
1513 || ( !($success) && !( $object_type =~ /urn:lsid/i ) ) )
1514 { # if the object doesn't exist, and it isn't an LSID
1515 $SVC->DELETE_THYSELF;
1517 "object: $object_type does not exist, and is not an LSID" );
1518 } # kill it all unless this was successful!
1519 my $namespace_string;
1520 my $namespaces = $node->getElementsByTagName('Namespace');
1521 my $num_ns = $namespaces->size();
1522 $OE = MOBY
::OntologyServer
->new( ontology
=> "namespace" );
1523 for ( my $n = 1 ; $n <= $num_ns ; ++$n ) {
1524 foreach my $name ( $namespaces->get_node($n)->childNodes ) {
1525 if ( $name->nodeType == TEXT_NODE
) {
1526 my $term = $name->toString;
1527 my ( $success, $message, $URI ) =
1528 $OE->namespaceExists( term
=> $term );
1529 if ( ( !($success) && ( $term =~ /urn:lsid:biomoby.org/i ) )
1530 || ( !($success) && !( $term =~ /urn:lsid/i ) ) )
1531 { # if the object doesn't exist, and it isn't an LSID
1532 $SVC->DELETE_THYSELF;
1534 "namespace: $term doesn't exist and is not an LSID"
1537 $namespace_string .= $URI . ",";
1541 chop($namespace_string); # remove trailing comma
1543 my $service_instance_id;
1545 { # this SIMPLE is either alone, or is part of a COLLECTION ($collid > 0)
1546 # therefore we want either its service instance ID, or its Collection ID.
1547 $service_instance_id = $SVC->service_instance_id;
1548 } # one or the other, but not both
1549 if ( $inout eq 'input' ) {
1550 my $sinput = $SVC->add_simple_input(
1551 object_type_uri
=> $typeURI,
1552 namespace_type_uris
=> $namespace_string,
1553 article_name
=> $article,
1554 collection_input_id
=> $collid,
1557 $SVC->DELETE_THYSELF;
1558 return ( -1, "registration failed during registration of input object $typeURI. Unknown reasons.");
1561 elsif ( $inout eq 'output' ) {
1562 my $soutput = $SVC->add_simple_output(
1563 object_type_uri
=> $typeURI,
1564 namespace_type_uris
=> $namespace_string,
1565 article_name
=> $article,
1566 collection_output_id
=> $collid,
1569 $SVC->DELETE_THYSELF;
1570 return ( -1,"registration failed during registration of output object $typeURI. Unknown reasons."
1575 elsif ( $simp_coll eq "Parameter" ) {
1576 my $parameter = $node;
1577 my $article = $parameter->getAttributeNode("articleName");
1578 $article = $article->getValue() if $article;
1579 my ( $datatype, $def, $max, $min, @enums );
1580 my $types = $parameter->getElementsByTagName('datatype');
1581 if ( $types->get_node(1) ) {
1582 foreach ( $types->get_node(1)->childNodes )
1583 { # should only ever be one!
1584 ( $_->nodeType == TEXT_NODE
) && ( $datatype .= $_->nodeValue );
1588 #ensure that thet type is correct (Integer | String | Float | DateTime)
1589 $datatype =~ s/\s//g;
1590 my $secondaries = $CONFIG->{valid_secondary_datatypes
};
1592 map { $valid = 1 if $datatype eq $_ } @
{$secondaries};
1594 $SVC->DELETE_THYSELF;
1595 return ( -1,"Registration failed. $datatype must be one of type Integer, String, DateTime, or Float."
1599 my $defs = $parameter->getElementsByTagName('default');
1600 if ( $defs->get_node(1) ) {
1601 foreach ( $defs->get_node(1)->childNodes )
1602 { # should only ever be one!
1603 ( $_->nodeType == TEXT_NODE
) && ( $def .= $_->nodeValue );
1606 my $maxs = $parameter->getElementsByTagName('max');
1607 if ( $maxs->get_node(1) ) {
1608 foreach ( $maxs->get_node(1)->childNodes )
1609 { # should only ever be one!
1610 ( $_->nodeType == TEXT_NODE
) && ( $max .= $_->nodeValue );
1613 my $mins = $parameter->getElementsByTagName('min');
1614 if ( $mins->get_node(1) ) {
1615 foreach ( $mins->get_node(1)->childNodes )
1616 { # should only ever be one!
1617 ( $_->nodeType == TEXT_NODE
) && ( $min .= $_->nodeValue );
1620 my $enums = $parameter->getElementsByTagName('enum');
1621 my $numenums = $enums->size();
1622 for ( my $n = 1 ; $n <= $numenums ; ++$n ) {
1623 foreach ( $enums->get_node($n)->childNodes )
1624 { # should only ever be one!
1625 ( $_->nodeType == TEXT_NODE
)
1626 && ( push @enums, $_->nodeValue );
1629 my $enum_string = join "", ( map { $_ . "," } @enums );
1630 chop $enum_string; # get rid of trailing comma
1631 $datatype =~ s/^\s+//;
1632 $datatype =~ s/\s+$//;
1639 my $sec = $SVC->add_secondary_input(
1640 default_value
=> $def,
1641 maximum_value
=> $max,
1642 minimum_value
=> $min,
1643 enum_value
=> $enum_string,
1644 datatype
=> $datatype,
1645 article_name
=> $article,
1649 $SVC->DELETE_THYSELF;
1651 "registration failed during registration of parameter $article. Must be of type Integer, String, DateTime, or Float."
1659 sub _registerServicePayload
{
1661 my $Parser = XML
::LibXML
->new();
1662 my $doc = $Parser->parse_string($payload);
1663 my $Object = $doc->getDocumentElement();
1664 my $obj = $Object->nodeName;
1665 return undef unless ( $obj eq 'registerService' );
1666 my $serviceName = &_nodeTextContent
( $Object, "serviceName" );
1667 my $Category = &_nodeTextContent
( $Object, "Category" );
1668 my $serviceType = &_nodeTextContent
( $Object, "serviceType" );
1669 my $AuthURI = &_nodeTextContent
( $Object, "authURI" );
1670 my $contactEmail = &_nodeTextContent
( $Object, "contactEmail" );
1671 my $authoritativeService =
1672 &_nodeTextContent
( $Object, "authoritativeService" );
1673 my $URL = &_nodeTextContent
( $Object, "URL" );
1674 my $signatureURL = &_nodeTextContent
( $Object, "signatureURL" );
1675 my $desc = &_nodeCDATAContent
( $Object, "Description" );
1676 my $INPUTS = &_nodeRawContent
( $Object, "Input" ); # returns array ref
1677 my $OUTPUTS = &_nodeRawContent
( $Object, "Output" ); # returns array ref
1679 &_nodeRawContent
( $Object, "secondaryArticles" ); # returns array ref
1681 $serviceName, $serviceType, $AuthURI,
1682 $contactEmail, $URL, $authoritativeService,
1683 $desc, $Category, $INPUTS,
1684 $OUTPUTS, $SECONDARIES, $signatureURL
1689 sub _extractObjectTypes
{
1690 my ($DOM) = @_; # DOM is either a <Simple/> or a <Collection/> article
1691 $debug && &_LOG
("\n\n\nExtracting object types from \n$DOM \n\n");
1692 unless ( ref($DOM) =~ /^XML/ ) {
1693 my $Parser = XML
::LibXML
->new();
1694 my $doc = $Parser->parse_string($DOM);
1695 $DOM = $doc->getDocumentElement();
1697 my $x = $DOM->getElementsByTagName("objectType");
1699 my $l = $x->size(); # might be a Collection object with multiple simples...
1700 for ( my $n = 1 ; $n <= $l ; ++$n ) {
1701 my @child = $x->get_node($n)->childNodes;
1704 && &_LOG
( getNodeTypeName
($_), "\t", $_->toString, "\n" )
1705 ; #hopefully uses MobyXMLConstants.pm
1706 next unless ( $_->nodeType == TEXT_NODE
);
1707 my $name = $_->toString;
1709 push @objectnames, $name;
1712 return (@objectnames);
1715 =head2 registerServiceWSDL
1717 Title : NOT YET IMPLEMENTED
1723 sub registerServiceWSDL
{
1724 my ( $pkg, $serviceType, $wsdl ) = @_;
1725 return &_error
( "not yet implemented", "" );
1728 =head2 deregisterService
1730 Title : deregisterService
1731 Usage : $REG = $MOBY->deregisterService($inputXML)
1732 Function : deregister a Service
1733 Returns : $REG object
1736 <authURI>biomoby.org</authURI>
1737 <serviceName>MyFirstService</serviceName>
1738 </deregisterService>
1740 ouptutXML : see Registration XML object
1745 sub deregisterService
{
1746 my ( $pkg, $payload ) = @_;
1747 $debug && &_LOG
("\nstarting deregistration\n");
1748 my ( $authURI, $serviceName ) = &_deregisterServicePayload
($payload);
1749 return &_error
( "must provide an authority and a service name\n", "" )
1750 unless ( $authURI && $serviceName );
1751 return &_error
("The service specified by authority=$authURI servicename=$serviceName does not exist in the registry","")
1753 MOBY
::service_instance
->new(
1754 servicename
=> $serviceName,
1755 authority_uri
=> $authURI,
1758 my $SERVICE = MOBY
::service_instance
->new(
1759 servicename
=> $serviceName,
1760 authority_uri
=> $authURI
1762 return &_error
("service lookup failed for unknown reasons","") unless ($SERVICE);
1764 if ( $SERVICE->signatureURL ) {
1766 "it is illegal to deregister a service that has a signatureURL. Such services must be deregistered by deleting the RDF at the location identified by the signatureURL",
1771 my $result = $SERVICE->DELETE_THYSELF;
1773 return &_success
( "Service Deregistered Successfully", "" );
1776 return &_error
( "Service deletion failed for unknown reasons", "" );
1781 sub _deregisterServicePayload
{
1783 $debug && &_LOG
( "deregisterService payload: ", ($payload), "\n" );
1784 my $Parser = XML
::LibXML
->new();
1785 my $doc = $Parser->parse_string($payload);
1786 my $Object = $doc->getDocumentElement();
1787 my $obj = $Object->nodeName; #Eddie - unsure
1788 return undef unless ( $obj eq 'deregisterService' );
1789 my $authURI = &_nodeTextContent
( $Object, "authURI" );
1790 my $name = &_nodeTextContent
( $Object, "serviceName" );
1791 return ( $authURI, $name );
1798 <!-- Service Query Object -->
1801 ServiceQueryObject XML:
1803 To query MOBY Central, you fill out the relevant elements of a Query Ojbect. These include the input and/or output data Classes (by name from the Class ontology), the Service-type (by name from the Service-type ontology), the authority (service provider URI), or any number of keywords that must appear in the service description.
1807 =item * MOBY Central finds all services which match the contents of the Query Object.
1809 =item * All elements are optional, however at least one must be present.
1811 =item * All elements present are considered as increasingly limiting on the search (i.e. "AND").
1813 =item * keywords are:
1817 =item * comma-delimited
1819 =item * sentence-fragments are enclosed in double-quotes
1821 =item * wildcard "*" is allowed in combination with keyword fragments and or sentence fragments (lone "*" is meaningless and ignored)
1823 =item * multiple keywords are considered joined by "AND".
1829 In addition to the search parameters, there are two "flags" that can be set in the Query object:
1833 =item * expandServices: this flag will cause MOBY Central to traverse the Service ontology and discover services that are child types (more specific) than the Service-type you requested
1835 e.g. you might request "alignment", and it would discover services such as "Blast", "Smith Waterman", "Needleman Wunsch"
1837 =item * expandObjects: this flag will cause MOBY Central to traverse the Class ontology to find services that operate not only on the Object Class you are querying, but also any parent types or sub-objects of that Object Class.
1839 e.g. if you request services that work on AnnotatedSequence Objects this flag will also return services that work on Sequence objects, since AnnotatedSequence objects inherit from Sequence objects
1843 The Query object structure is as follows:
1847 <!-- one or more Simple or Collection Primary articles -->
1852 <!-- one or more Simple or Collection Primary articles -->
1855 <authoritative>1</authoritative>
1856 <Category>moby</Category>
1857 <serviceType>ServiceTypeTerm</serviceType>
1858 <serviceName>ServiceName</serviceName>
1859 <authURI>http://desired.service.provider</authURI>;
1860 <expandObjects>1|0</expandObjects>
1861 <expandServices>1|0</expandServices>
1863 <keyword>something</keyword>
1872 <Service authURI="authority.URI.here" serviceName="MyService" lsid="urn:lsid:authority.uri:serviceinstance:id">
1873 <serviceType lsid='urn:...'>Service_Ontology_Term</serviceType>
1874 <Protocol>moby</Protocol> <!-- or 'cgi' or 'soap' -->
1875 <authoritative>1</authoritative>
1876 <contactEmail>your@email.address</contactEmail>
1877 <URL>http://endpoint.of.service</URL>
1879 <!-- one or more Simple and/or Collection Primary articles -->
1882 <!-- one or more Simple and/or Collection Primary articles -->
1885 <!-- one or more Secondary articles -->
1886 </secondaryArticles>
1887 <Description><![CDATA[free text description here]]></Description>
1889 ... <!-- one or more Service blocks may be returned -->
1898 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
1899 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
1901 my ( $pkg, $payload ) = @_;
1902 $debug && &_LOG
("\nLOOKING FOR SERVICES\n");
1903 my %findme = &_findServicePayload
($payload);
1905 "'serviceType' => $findme{serviceType},
1906 'authURI' => $findme{AuthURI},
1907 'servicename' => $findme{servicename},
1908 'expandObjects' => $findme{expandObjects},
1909 'expandServices' => $findme{expandServices},
1910 'authoritative' => $findme{authoritative},
1911 'category' => $findme{Category},
1912 'keywords' => $findme{keywords},
1915 my %valid_service_ids;
1916 my $criterion_count = 0;
1918 # we want to avoid joins, since they slow things down, so...
1919 # the logic is that we keep a hash of valid id's
1920 # and the number of times they are discovered
1921 # we also count the number of criterion
1922 # we only want the service_id's that appear as many times as the criterion we have
1923 # since they will have matched every criterion.
1925 if ( $findme{authoritative
} ) {
1929 "authoritative added; criterion count is now $criterion_count\n");
1930 my $ids = _extract_ids
($adaptor->query_service_instance(authoritative
=> $findme{authoritative
}));
1934 ### MARK - we need to extract ids at each step...
1938 unless ( scalar @
{$ids} ) {
1939 return &_serviceListResponse
(undef );
1942 && _LOG
( "services " . ( join ',', @
{$ids} ) . " incrememted\n" );
1943 foreach ( @
{$ids} ) {
1944 $debug && &_LOG
("found service_instance_id $_\n");
1945 ++$valid_service_ids{$_}; # increment that particular id's count by one
1948 if ( $findme{serviceType
} ) { # must have something more than empty content
1949 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'service' );
1950 $findme{serviceType
} =~ s/^moby\://;
1951 my ( $exists, $message, $URI ) =
1952 $OS->serviceExists( term
=> $findme{serviceType
} );
1954 return &_serviceListResponse
(undef );
1959 "serviceType added; criterion count is now $criterion_count\n");
1960 my $children_string = "'$URI',";
1961 if ( $findme{'expandServices'} ) {
1962 $debug && _LOG
("Expanding Services\n");
1963 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'service' );
1964 my %relationships = %{ $OS->traverseDAG( $URI, "leaves" ) };
1966 @
{ $relationships{'urn:lsid:biomoby.org:servicerelation:isa'} };
1967 $children_string .= ( join ',', map { "\'$_\'" } @children );
1968 #*******FIX this isn't very perlish... sending a comma-delimited string to a subroutine instead of an array
1969 # need to change that one day soon!
1971 $children_string =~ s/\,$//;
1972 my $ids = _extract_ids
($adaptor->match_service_type_uri(service_type_uri
=> $children_string));
1975 && _LOG
( "services " . ( join ',', @
{$ids} ) . " incrememted\n" );
1976 foreach ( @
{$ids} ) {
1977 $debug && &_LOG
("found service_instance_id $_\n");
1978 ++$valid_service_ids{$_}; # increment that particular id's count by one
1981 if ( $findme{authURI
} ) {
1984 && _LOG
("authURI added; criterion count is now $criterion_count\n");
1985 my $ids = _extract_ids
($adaptor->query_service_instance(authority_uri
=> $findme{'authURI'}));
1987 unless ( scalar @
{$ids} ) {
1988 return &_serviceListResponse
(undef );
1991 && _LOG
( "services " . ( join ',', @
{$ids} ) . " incrememted\n" );
1992 foreach ( @
{$ids} ) {
1993 $debug && &_LOG
("found service_instance_id $_\n");
1994 ++$valid_service_ids{$_}; # increment that particular id's count by one
1997 if ( $findme{servicename
} ) {
2001 "servicename added; criterion count is now $criterion_count\n");
2003 my $ids = _extract_ids
($adaptor->query_service_instance(servicename
=> $findme{servicename
}));
2005 unless ( scalar @
{$ids} ) {
2006 return &_serviceListResponse
( undef );
2009 && _LOG
( "services " . ( join ',', @
{$ids} ) . " incrememted\n" );
2010 foreach ( @
{$ids} ) {
2011 $debug && &_LOG
("found service_instance_id $_\n");
2012 ++$valid_service_ids{$_}; # increment that particular id's count by one
2015 $findme{category
} = 'moby' unless $findme{category
};
2016 if ( $findme{category
} ) {
2019 && _LOG
("category added; criterion count is now $criterion_count\n");
2021 my $ids = _extract_ids
($adaptor->query_service_instance(category
=> lc( $findme{category
}) ));
2023 unless ( scalar @
{$ids} ) {
2024 return &_serviceListResponse
( undef );
2027 && _LOG
( "services " . ( join ',', @
{$ids} ) . " incrememted\n" );
2028 foreach ( @
{$ids} ) {
2029 $debug && &_LOG
("found service_instance_id $_\n");
2030 ++$valid_service_ids{$_}; # increment that particular id's count by one
2033 if ( $findme{keywords
} && ( scalar @
{ $findme{keywords
} } ) ) {
2036 && _LOG
("Keywords added; criterion count is now $criterion_count\n");
2038 my ($ids) = $adaptor->check_keywords(keywords
=> \@
{$findme{keywords
}});
2039 $ids = _extract_ids
($ids); # this is the hash-list that comes back from do_query
2041 unless ( scalar @
{$ids} ) {
2042 return &_serviceListResponse
( undef );
2045 && _LOG
( "services " . ( join ',', @
{$ids} ) . " incrememted\n" );
2046 foreach ( @
{$ids} ) {
2047 $debug && &_LOG
("found service_instance_id $_\n");
2048 ++$valid_service_ids{$_}; # increment that particular id's count by one
2051 if ( $findme{inputObjects
} && ( scalar @
{ $findme{inputObjects
} } ) ) {
2055 "inputObject added; criterion count is now $criterion_count\n");
2056 my $obj = ( shift @
{ $findme{inputObjects
} } );
2059 &_searchForServicesWithArticle
( "input", $obj,$findme{'expandObjects'}, '' )
2062 && _LOG
("Initial Search For Services with INPUT Article found @si_ids\n");
2065 # we need to do a join, without doing a join...
2066 if ( scalar @si_ids ) {
2067 map { $instances{$_} = 1 }
2068 @si_ids; # get an id of the good services from the first object
2069 while ( my $obj = shift( @
{ $findme{inputObjects
} } ) )
2070 { # iterate through the rest of the objects
2073 && _LOG
( "FIRST: ", "input", $obj,
2074 $findme{'expandObjects'}, '' );
2076 &_searchForServicesWithArticle
("input", $obj,$findme{'expandObjects'}, '' ); # get their service ids
2078 && _LOG
("Subsequent Search For Services with INPUT Article found @new_ids\n");
2081 foreach my $id (@new_ids)
2082 { # check the new id set against the set we know is already valid
2083 next unless defined $id;
2084 if ( $instances{$id} ) {
2085 push @good_ids, $id;
2086 } # if they are in common, then that id is still good
2088 map { $good_ids{$_} = 1 }
2089 @good_ids; # make a hash of the new good id's
2090 %instances = %good_ids
2091 ; # and replace the original list with this more limited one
2095 # now %instances contains only valid ID numbers
2097 && _LOG
( "Final results incremented of search for INPUT: "
2098 . ( join ',', ( keys %instances ) )
2100 foreach ( keys %instances ) {
2101 $debug && &_LOG
("found id $_\n");
2102 ++$valid_service_ids{$_};
2105 if ( $findme{outputObjects
} && ( scalar @
{ $findme{outputObjects
} } ) ) {
2109 "outputObject added; criterion count is now $criterion_count\n");
2110 my $obj = ( shift @
{ $findme{outputObjects
} } );
2112 @si_ids = &_searchForServicesWithArticle
("output", $obj, '' )if defined $obj;
2115 "Initial Search For Services with OUTPUT Article found @si_ids\n");
2118 # we need to do a join, without doing a join...
2119 if ( scalar @si_ids ) {
2120 map { $instances{$_} = 1 }
2121 @si_ids; # get an id of the good services from the first object
2122 while ( my $obj = shift( @
{ $findme{outputObjects
} } ) )
2123 { # iterate through the rest of the objects
2126 &_searchForServicesWithArticle
("output", $obj, '' )
2127 ; # get their service ids
2129 && _LOG
("Subsequent Search For Services with OUTPUT Article found @new_ids\n"
2133 foreach my $id (@new_ids)
2134 { # check the new id set against the set we know is already valid
2135 next unless defined $id;
2136 if ( $instances{$id} ) {
2137 push @good_ids, $id;
2138 } # if they are in common, then that id is still good
2140 map { $good_ids{$_} = 1 }
2141 @good_ids; # make a hash of the new good id's
2142 %instances = %good_ids
2143 ; # and replace the original list with this more limited one
2147 # now %instances contains only valid ID numbers
2149 && _LOG
( "Final results incremented of search for OUTPUT: "
2150 . ( join ',', ( keys %instances ) )
2152 foreach ( keys %instances ) {
2153 $debug && &_LOG
("found id $_\n");
2154 ++$valid_service_ids{$_};
2158 while ( my ( $id, $freq ) = each %valid_service_ids ) {
2161 "TALLY IS ID: $id FREQ:$freq\n CRITERION COUNT $criterion_count\n"
2165 $criterion_count; # has to have matched every criterion
2168 return &_serviceListResponse
(@final );
2172 my ($linehash) = @_;
2173 # ths data comes from the do_query of the mysql call
2175 my @lines = @
$linehash;
2176 return [] unless scalar(@lines);
2179 my $id = $_->{service_instance_id
};
2186 sub _searchForServicesWithArticle
{
2187 my ($inout, $node, $expand, $coll ) = @_;
2189 unless $node->nodeType ==
2190 ELEMENT_NODE
; # this will erase all current successful service instances!
2192 && _LOG
( "searchServWthArticle ", $inout, $node, $expand, $coll );
2194 # this element node may be a Simple or a Collection object
2195 my $simp_coll = $node->nodeName;
2196 $debug && &_LOG
("TAGNAME in _searchForArticle is $simp_coll");
2198 if ( $simp_coll eq "Collection" ) {
2199 @valid_ids = &_searchForCollection
( $node, $expand, $inout );
2201 elsif ( $simp_coll eq "Simple" ) {
2202 @valid_ids = &_searchForSimple
( $node, $expand, $inout );
2207 sub _searchForSimple
{
2208 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
2209 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
2211 # returns list of service_instance ID's
2212 # that match this simple
2213 my ( $node, $expand, $inout ) = @_;
2214 $debug && _LOG
( $node, $expand, $inout );
2215 my ( $objectURI, $namespaceURIs ) =
2216 &_extractObjectTypesAndNamespaces
($node); # (objectType, [ns1, ns2, ns3])
2217 unless ($objectURI) { return () }
2218 my $ancestor_string = "'$objectURI',";
2220 $debug && _LOG
("Expanding Objects\n");
2221 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'object' );
2222 my %relationships = %{ $OS->traverseDAG( $objectURI, "root" ) };
2224 @
{ $relationships{'urn:lsid:biomoby.org:objectrelation:isa'} };
2225 $ancestor_string .= ( join ',', map { "\'$_\'" } @ancestors );
2227 $ancestor_string =~ s/\,$//;
2229 my $result = $adaptor->find_by_simple(inout
=> $inout,
2230 ancestor_string
=> $ancestor_string,
2231 namespaceURIs
=> $namespaceURIs);
2235 foreach my $row (@
$result)
2237 # get the service instance ID and the namespaces that matched
2238 my $id = $row->{service_instance_id
};
2239 my $nss = $row->{namespace_type_uris
};
2240 if ( $nss && scalar @
{$namespaceURIs} )
2241 { # if this service cares about namespaces at all,
2242 # and if namespaces were specified in the query,
2243 # then validate the discovered service against this list
2244 my @ns = split ",", $nss
2245 ; # because of the database structure we have to re-test for *identity*, not just like%% similarity
2246 my %nshash = map { ( $_, 1 ) } @ns, @
{ $namespaceURIs
2247 }; #we're going to test identity by building a hash of namespaces as keys
2249 scalar( keys %nshash ) <
2250 scalar(@ns) + scalar( @
{$namespaceURIs} ) )
2251 { # if the number of keys is less than the sum of the number of keys goign into the hash, then one of them was identical
2252 push @valid_services,
2253 $id; # and therefore it really is a match, and is valid
2256 else { # if no namespace was specified, then all of them are valid
2257 push @valid_services, $id;
2261 && _LOG
( "Resulting IDs were " . ( join ',', @valid_services ) . "\n" );
2262 return @valid_services;
2266 sub _searchForCollection
{
2267 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
2268 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
2270 my ( $node, $expand, $inout ) =
2271 @_; # $node in this case is a Collection object
2273 # luckily, we can return a redundant list of service id's and
2274 # this will be cleaned up in the caller
2276 foreach my $simple ( $node->childNodes() ) {
2277 next unless ( $simple->nodeType == ELEMENT_NODE
);
2278 next unless ( $simple->nodeName =~ /simple/i );
2279 my ( $objectURI, $namespaceURIs ) =
2280 &_extractObjectTypesAndNamespaces
($simple);
2282 my $result = $adaptor->find_by_collection(inout
=> $inout,
2283 objectURI
=> $objectURI,
2284 namespaceURIs
=> $namespaceURIs);
2286 foreach my $row (@
$result )
2287 { # get the service instance ID and the namespaces that matched
2288 my $id = $row->{service_instance_id
};
2289 my $nss = $row->{namespace_type_uris
};
2290 if ( $nss && scalar @
{$namespaceURIs} )
2291 { # if this service cares about namespaces at all,
2292 # and if namespaces were specified in the query,
2293 # then validate the discovered service against this list
2294 my @ns = split ",", $nss
2295 ; # because of the database structure we have to re-test for *identity*, not just like%% similarity
2296 my %nshash = map { ( $_, 1 ) } @ns, @
{ $namespaceURIs
2297 }; #we're going to test identity by building a hash of namespaces as keys
2299 scalar( keys %nshash ) <
2300 scalar(@ns) + scalar( @
{$namespaceURIs} ) )
2301 { # if the number of keys is less than the sum of the number of keys goign into the hash, then one of them was identical
2302 push @validservices,
2303 $id; # and therefore it really is a match, and is valid
2306 else { # if no namespace was specified, then all of them are valid
2307 push @validservices, $id;
2311 return @validservices;
2315 sub _findServicePayload
{
2317 my $Parser = XML
::LibXML
->new();
2318 my $doc = $Parser->parse_string($payload);
2319 my $Object = $doc->getDocumentElement();
2320 my $obj = $Object->nodeName;
2321 return undef unless ( $obj eq 'findService' );
2322 my $serviceType = &_nodeTextContent
( $Object, "serviceType" );
2323 $serviceType && ( $serviceType =~ s/\s+//g );
2324 my $servicename = &_nodeTextContent
( $Object, "serviceName" );
2325 $servicename && ( $servicename =~ s/\s+//g );
2326 my $authoritative = &_nodeTextContent
( $Object, "authoritative" );
2327 $authoritative && ( $authoritative =~ s/\s+//g );
2328 my $Category = &_nodeTextContent
( $Object, "Category" );
2329 $Category && ( $Category =~ s/\s+//g );
2330 my $AuthURI = &_nodeTextContent
( $Object, "authURI" );
2331 $AuthURI && ( $AuthURI =~ s/\s+//g );
2332 my $expandObjects = &_nodeTextContent
( $Object, "expandObjects" );
2333 $expandObjects && ( $expandObjects =~ s/\s+//g );
2334 my $expandServices = &_nodeTextContent
( $Object, "expandServices" );
2335 $expandServices && ( $expandServices =~ s/\s+//g );
2336 my @kw = &_nodeArrayContent
( $Object, "keywords" );
2337 my $INPUTS = &_nodeRawContent
( $Object, "Input" ); # returns array ref
2338 my $OUTPUTS = &_nodeRawContent
( $Object, "Output" ); # returns array ref
2340 'serviceType' => $serviceType,
2341 'authURI' => $AuthURI,
2342 'servicename' => $servicename,
2343 'expandObjects' => $expandObjects,
2344 'expandServices' => $expandServices,
2345 'authoritative' => $authoritative,
2346 'Category' => $Category,
2347 'inputObjects' => $INPUTS,
2348 'outputObjects' => $OUTPUTS,
2354 sub _extractObjectTypesAndNamespaces
{
2356 # takes a SINGLE simple article and return regular list ($objectURI, [nsURI1, nsURI2, nsURI3])
2360 "\n\n_extractObjectTypesAndNamespaces\nExtracting object types from \n$DOM \n\n"
2362 unless ( ref($DOM) =~ /^XML/ ) {
2363 my $Parser = XML
::LibXML
->new();
2364 my $doc = $Parser->parse_string($DOM);
2365 $DOM = $doc->getDocumentElement();
2367 my $x = $DOM->getElementsByTagName("objectType");
2369 my @child = $x->get_node(1)->childNodes;
2371 $debug && &_LOG
( getNodeTypeName
($_), "\t", $_->toString, "\n" );
2372 next unless ( $_->nodeType == TEXT_NODE
);
2373 my $name = $_->toString;
2375 $objectname = $name;
2377 $objectname =~ s/^moby\://
2378 ; # damn XML DOM can't deal with namespaces... so get rid of it if it exists, though this is going to limit us to only MOBY objects again :-(
2379 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'object' );
2380 my ( $exists, $message, $objectURI ) =
2381 $OS->objectExists( term
=> $objectname );
2382 return ( undef, [] ) unless $objectURI;
2383 my $ns = $DOM->getElementsByTagName("Namespace");
2385 my $nonamespaces = $ns->size();
2386 $OS = MOBY
::OntologyServer
->new( ontology
=> 'namespace' );
2388 for ( my $n = 1 ; $n <= $nonamespaces ; ++$n ) {
2389 my @child = $ns->get_node($n)->childNodes;
2391 $debug && &_LOG
( getNodeTypeName
($_), "\t", $_->toString, "\n" );
2392 next unless ( $_->nodeType == TEXT_NODE
);
2393 my $name = $_->toString;
2395 my ( $success, $message, $URI ) =
2396 $OS->namespaceExists( term
=> $name );
2398 ?
( push @namespaces, $URI )
2399 : ( push @namespaces, "__MOBY__INVALID__NAMESPACE__" );
2402 return ( $objectURI, \
@namespaces );
2405 =head2 retrieveService
2407 Title : retrieveService
2408 Usage : $WSDL = $MOBY->locateService($inputXML)
2409 Function : get the WSDL descriptions for services with this service name
2410 Returns : XML (see below)
2411 Comment : the WSDL that you get back is invalid w.r.t. the object structure
2412 It will always be so.
2413 It should be used only to create stubs for the connection to the service.
2416 <Service authURI="authority.uri.here" serviceName="myServ"/>
2419 outputXML (by category):
2421 moby: <Service lsid='urn:lsid:...'><![CDATA[WSDL document here]]</Service>
2426 sub retrieveService
{
2427 my ( $pkg, $payload ) = @_;
2428 my ( $AuthURI, $serviceName, $InputXML, $OutputXML, $SecondaryXML ) =
2429 &_retrieveServicePayload
($payload);
2430 unless ( $AuthURI && $serviceName ) { return "<Services/>" }
2431 my $SI = MOBY
::service_instance
->new(
2432 authority_uri
=> $AuthURI,
2433 servicename
=> $serviceName
2435 my $servlsid = $SI->lsid;
2437 return "<Services/>" unless ($SI);
2438 if ( $SI->category eq 'moby' ) {
2440 &_getServiceWSDL
( $SI, $InputXML, $OutputXML, $SecondaryXML );
2442 if ( $wsdl =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
2445 $wsdls .= "<Service lsid='$servlsid'><![CDATA[$wsdl]]></Service>\n";
2448 #$debug && &_LOG("WSDL_________________$wsdls\n____________________");
2454 sub _retrieveServicePayload
{
2456 my $Parser = XML
::LibXML
->new();
2457 my $doc = $Parser->parse_string($payload);
2458 my $x = $doc->getElementsByTagName("Service");
2460 my $serviceName = "";
2461 my $l = $x->size(); # might be a Collection object with multiple simples...
2462 for ( my $n = 1 ; $n <= $l ; ++$n ) {
2464 $x->get_node($n)->getAttributeNode("authURI")
2465 ; # may or may not have a name
2466 if ($authURI) { $authURI = $authURI->getValue() }
2468 $x->get_node($n)->getAttributeNode("serviceName")
2469 ; # may or may not have a name
2470 if ($serviceName) { $serviceName = $serviceName->getValue() }
2472 my $INPUT = $doc->getElementsByTagName("Input");
2474 if ( $INPUT->get_node(1) ) {
2475 $InputXML = $INPUT->get_node(1)->toString;
2477 my $OUTPUT = $doc->getElementsByTagName("Output");
2479 if ( $OUTPUT->get_node(1) ) {
2480 $OutputXML = $OUTPUT->get_node(1)->toString;
2482 my $SECONDARY = $doc->getElementsByTagName("Output");
2483 my $SecondaryXML = "";
2484 if ( $SECONDARY->get_node(1) ) {
2485 $SecondaryXML = $SECONDARY->get_node(1)->toString;
2487 return ( $authURI, $serviceName, $InputXML, $OutputXML, $SecondaryXML );
2490 =head2 retrieveResourceURLs
2492 Title : retrieveResourceURLs
2493 Usage : $urls = $MOBY->retrieveResourceURLs
2494 Function : to retrieve the location(s) of the RDF versions of the various
2497 Returns : XML (see below). The "name" attribute indicates which ontology
2498 is described by the URL (Service, Object, Namespace, ServiceInstance, Full),
2499 and the "url" attribute provides a URL that, when called with an
2500 HTTP GET, will return RDF-XML describing that ontology.
2503 <Resource name="Service" url="http://mobycentral.org/RESOURCES/MOBY-S/Services/>
2504 <Resource name="Object" url="..."/>
2505 <Resource name="Namespace" url="...X..."/>
2506 <Resource name="Namespace" url="...Y..."/>
2511 sub retrieveResourceURLs
{
2513 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
2514 my $central = $CONFIG->{mobycentral
}->{resourceURL
};
2515 my $service = $CONFIG->{mobyservice
}->{resourceURL
};
2516 my $namespace = $CONFIG->{mobynamespace
}->{resourceURL
};
2517 my $object = $CONFIG->{mobyobject
}->{resourceURL
};
2518 my $all = $CONFIG->{mobycentral
}->{allResources
};
2520 my $message ="<resourceURLs>";
2521 $message .="<Resource name='ServiceInstance' url='$central'/>" if $central;
2522 $message .="<Resource name='Object' url='$object'/>" if $object;
2523 $message .="<Resource name='Service' url='$service'/>" if $service;
2524 $message .="<Resource name='Namespace' url='$namespace'/>" if $namespace;
2525 $message .="<Resource name='Full' url='$all'/>" if $all;
2526 $message .="</resourceURLs>";
2531 =head2 retrieveServiceProviders
2533 Title : retrieveServiceProviders
2534 Usage : $uris = $MOBY->retrieveServiceProviders()
2535 Function : get the list of all provider's AuthURI's
2536 Returns : XML (see below)
2540 <serviceProvider name="authority.info.here"/>
2547 sub retrieveServiceProviders
{
2548 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
2549 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
2553 my $result = $adaptor->get_all_authorities();
2555 my $providers = "<serviceProviders>\n";
2556 foreach my $prov (@
$result) {
2557 $providers .= "<serviceProvider name='".($prov->{authority_uri
})."'/>\n";
2559 $providers .= "</serviceProviders>\n";
2563 =head2 retrieveServiceNames
2565 Title : retrieveServiceNames
2566 Usage : $names = $MOBY->retrieveServiceNames()
2567 Function : get a (redundant) list of all registered service names
2568 (N.B. NOT service types!)
2569 Returns : XML (see below)
2573 <serviceName name="serviceName" authURI='authority.info.here' lsid = 'urn:lsid...'/>
2580 sub retrieveServiceNames
{
2581 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
2582 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
2586 my $result = $adaptor->get_service_names();
2587 my $names = "<serviceNames>\n";
2588 foreach my $row (@
$result) {
2589 my $name = $row->{servicename
};
2590 my $auth = $row->{authority_uri
};
2591 my $lsid = $row->{lsid
};
2592 $names .= "<serviceName name='$name' authURI='$auth' lsid='$lsid'/>\n";
2594 $names .= "</serviceNames>\n";
2598 =head2 retrieveServiceTypes
2600 Title : retrieveServiceTypes
2601 Usage : $types = $MOBY->retrieveServiceTypes()
2602 Function : get the list of all registered service types
2603 Returns : XML (see below)
2607 <serviceType name="serviceName" lsid="urn:lsid...">
2608 <Description><![CDATA[free text description here]]></Description>
2609 <contactEmail>your@email.here</contactEmail>
2610 <authURI>authority.uri.here</authURI>
2618 sub retrieveServiceTypes
{
2620 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'service' );
2621 my %types = %{ $OS->retrieveAllServiceTypes() };
2622 my $types = "<serviceTypes>\n";
2623 while ( my ( $serv, $descr ) = each %types ) { #UNCOMMENT
2624 my ($desc, $lsid, $contact, $auth) = @
$descr;
2625 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
2628 $types .="<serviceType name='$serv' lsid='$lsid'>\n<Description><![CDATA[$desc]]></Description>\n<contactEmail>$contact</contactEmail>\n<authURI>$auth</authURI>\n</serviceType>\n"; #UNCOMMENT
2630 $types .= "</serviceTypes>\n";
2634 =head2 retrieveRelationshipTypes
2636 Title : retrieveRelationshipTypes
2637 Usage : $types = $MOBY->retrieveRelationshipTypes($xml)
2638 Function : get the list of all registered relationship types in the given ontology
2639 Returns : XML (see below)
2640 Args : input XML (ontologies are 'object', 'service', 'namespace', 'relationship')
2642 Input XML : <Ontology>OntologyName</Ontology>
2645 <relationshipType relationship="ontologyterm" authority="biomoby.org">
2646 <Description><![CDATA[free text description here]]></Description>
2650 </relationshipTypes>
2655 sub retrieveRelationshipTypes
{
2656 my ( $pkg, $payload ) = @_;
2657 my $Parser = XML
::LibXML
->new();
2658 my $doc = $Parser->parse_string($payload);
2659 my $ontology = &_nodeTextContent
( $doc, "Ontology" );
2660 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'relationship' );
2661 my %types = %{ $OS->getRelationshipTypes( ontology
=> $ontology ) };
2662 my $types = "<relationshipTypes>\n";
2663 while ( my ( $lsid, $authdesc ) = each %types ) {
2664 my $name = $authdesc->[0];
2665 my $auth = $authdesc->[1];
2666 my $desc = $authdesc->[2];
2667 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
2670 $types .="<relationshipType relationship='$name' authority='$auth' lsid='$lsid'>\n<Description><![CDATA[$desc]]></Description>\n</relationshipType>\n";
2672 $types .= "</relationshipTypes>\n";
2676 =head2 retrieveObjectNames
2678 Title : retrieveObjectNames
2679 Usage : $names = $MOBY->retrieveObjectNames()
2680 Function : get the list of all registered Object types
2681 Returns : XML (see below)
2685 <Object name="objectName" lsid="urn:lsid:...">
2686 <Description><![CDATA[free text description here]]></Description>
2694 sub retrieveObjectNames
{
2696 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'object' );
2697 my %types = %{ $OS->retrieveAllObjectTypes() };
2698 my $obj = "<objectNames>\n";
2699 while ( my ( $name, $descr ) = each %types ) {
2700 my ($desc, $lsid) = @
$descr;
2701 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
2704 $obj .="<Object name='$name' lsid='$lsid'>\n<Description><![CDATA[$desc]]></Description>\n</Object>\n";
2706 $obj .= "</objectNames>\n";
2710 =head2 retrieveObjectDefinition
2712 Title : retrieveObjectDefinition
2713 Usage : $registerObjectXML = $MOBY->retrieveObjectDefinition($inputXML)
2714 Function : get the full description of an object, as registered
2715 Returns : see input XML for registerObjectClass
2717 <retrieveObjectDefinition>
2718 <obqjectType>ExistingObjectClassname</objectType>
2719 </retrieveObjectDefinition>
2722 <retrieveObjectDefinition>
2723 <objectType lsid="urn:lsid:...">NewObjectType</objectType>
2724 <Description><![CDATA[
2725 human readable description
2728 <Relationship relationshipType="urn:lsid...">
2729 <objectType articleName="SomeName" lsid="urn:lsid...">ExistingObjectType</objectType>
2733 <authURI>owner.URI.here</authURI>
2734 <contactEmail>owner@their.address.com</contactEmail>
2735 </retrieveObjectDefinition>
2741 sub retrieveObjectDefinition
{
2742 my ( $pkg, $payload ) = @_;
2743 my $Parser = XML
::LibXML
->new();
2744 my $doc = $Parser->parse_string($payload);
2745 my $term = &_nodeTextContent
( $doc, "objectType" );
2746 return "<retrieveObjectDefinition/>" unless $term;
2747 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'object' );
2749 $OS->retrieveObject( node
=> $term )
2750 ; # will return undef if this term does not exist, and does not look like an LSID
2751 return "<retrieveObjectDefinition/>" unless $def;
2752 my %def = %{ $OS->retrieveObject( type
=> $term ) };
2754 if ( $def{description
} =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
2755 $def{description
} = $1;
2758 $response = "<retrieveObjectDefinition>
2759 <objectType lsid='$def{objectLSID}'>$def{objectType}</objectType>
2760 <Description><![CDATA[$def{description}]]></Description>
2761 <authURI>$def{authURI}</authURI>
2762 <contactEmail>$def{contactEmail}</contactEmail>\n";
2763 my %relationships = %{ $def{Relationships
} };
2765 while ( my ( $rel, $objdefs ) = each %relationships ) {
2766 $response .= "<Relationship relationshipType='$rel'>\n";
2767 foreach my $def ( @
{$objdefs} ) {
2768 my ( $lsid, $articlename,$type, $def, $auth, $contac ) = @
{$def};
2769 $articlename = "" unless defined $articlename;
2771 "<objectType articleName='$articlename' lsid='$lsid'>$type</objectType>\n";
2773 $response .= "</Relationship>\n";
2775 $response .= "</retrieveObjectDefinition>\n";
2779 =head2 retrieveNamespaces
2781 Title : retrieveNamespaces
2782 Usage : $ns = $MOBY->retrieveNamespaces()
2783 Function : get the list of all registered Object types
2784 Returns : XML (see below)
2788 <Namespace name="namespace" lsid="urn:lsid:...">
2789 <Description><![CDATA[free text description here]]></Description>
2790 <contactEmail>email@address.here</contactEmail>
2791 <authURI>authority.uri.here</authURI>
2799 sub retrieveNamespaces
{
2801 my $OS = MOBY
::OntologyServer
->new( ontology
=> 'namespace' );
2802 my %types = %{ $OS->retrieveAllNamespaceTypes() };
2803 my $ns = "<Namespaces>\n";
2804 while ( my ( $namespace, $descr ) = each %types ) {
2805 my ($desc, $lsid, $auth, $contact) = @
$descr;
2806 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
2809 # $ns .= "<Namespace name='$namespace' lsid='$lsid'>\n<Description><![CDATA[$desc]]></Description>\n</Namespace>\n"; #COMMENT/REMOVE
2810 $ns .= "<Namespace name='$namespace' lsid='$lsid'>\n<Description><![CDATA[$desc]]></Description>\n<contactEmail>$contact</contactEmail>\n<authURI>$auth</authURI>\n</Namespace>\n";#UNCOMMENT
2812 $ns .= "</Namespaces>";
2816 =head2 retrieveObject
2819 Title : retrieveObject
2820 Usage : $objects = $MOBY->retrieveObject($inputXML)
2821 Function : get the object xsd
2822 Returns : XML (see below)
2823 Args : $name - object name (from ontology) or "all" to get all objects
2827 <objectType>ObjectType | all</objectType>
2832 <Object name="namespace">
2833 <Schema><XSD schema fragment here></Schema>
2841 sub retrieveObject
{
2842 my ( $pkg, $payload ) = @_;
2843 my $response = "<Objects>\n";
2844 $response .= "<NOT_YET_IMPLEMENTED/>\n";
2845 $response .= "</Objects>\n";
2850 sub _retrieveObjectPayload
{
2852 my $Parser = XML
::LibXML
->new();
2853 my $doc = $Parser->parse_string($payload);
2854 my $Object = $doc->getDocumentElement();
2855 my $obj = $Object->nodeName;
2856 return undef unless ( $obj eq 'retrieveObject' );
2857 my $type = &_nodeTextContent
( $Object, "objectType" );
2861 =head2 Relationships
2863 Title : Relationships
2864 Usage : $ns = $MOBY->Relationships()
2865 Function : get the fist level of relationships for the given term
2866 Returns : output XML (see below)
2867 Args : Input XML (see below). relationshipTypes are optional.
2868 If included, it will limit the response to only those
2869 relationship types, otherwise you get all by default.
2871 NOTE: the expandRelationships flag in the official API is not yet implemented.
2872 NOTE: THIS CURRENTLY ONLY FUNCTIONS PROPERLY FOR ISA RELATIONSHIPS since the
2873 expected behaviour with HAS and HASA relationships isn't yet defined.
2877 <objectType>$term</objectType>
2878 <expandRelationship>1|0</expandRelationship>
2879 <relationshipType>$relationship_term</relationshipType>
2880 ... more relationship types
2885 <serviceType>$term</serviceType>
2886 <expandRelationship>1|0</expandRelationship>
2887 <relationshipType>$relationship_term</relationshipType>
2888 ... more relationship types
2895 <Relationship relationshipType="RelationshipOntologyTerm">
2896 <objectType lsid='urn:lsid...'>ExistingObjectType</objectType>
2897 <objectType lsid='urn:lsid...'>ExistingObjectType</objectType>
2899 <Relationship relationshipType="AnotherRelationshipTerm">
2907 <Relationship relationshipType="RelationshipOntologyTerm">
2908 <serviceType lsid='urn:lsid...'>ExistingServiceType</serviceType>
2909 <serviceType lsid='urn:lsid...'>ExistingServiceType</serviceType>
2911 <Relationship relationshipType="AnotherRelationshipTerm">
2920 my ( $pkg, $payload ) = @_;
2922 my $Parser = XML
::LibXML
->new();
2923 my $doc = $Parser->parse_string($payload);
2924 my $x = $doc->getElementsByTagName("relationshipType"); # this is ignored - it is always ISA
2926 my $exp = $doc->getElementsByTagName("expandRelationship");
2927 my $expl = $exp->size();
2928 my $expand_relationship = &_nodeTextContent
( $doc, 'expandRelationship' );
2929 $expand_relationship =~ s/\s//g;
2930 $expand_relationship ||= 0;
2934 for ( my $n = 1 ; $n <= $l ; ++$n ) {
2935 my @child = $x->get_node($n)->childNodes;
2937 next unless ( $_->nodeType == TEXT_NODE
);
2938 my $name .= $_->toString;
2940 $reltypes{$name} = 1;
2941 $relationship = $name; # THIS WILL ALWYAS BE ISA
2944 my $term = &_nodeTextContent
( $doc, "objectType" );
2945 $ontology = "object"
2946 if $term; # pick up the ontology "object" that we used here if we got an object term
2948 &_nodeTextContent
( $doc, "serviceType" ); # if we didn't get anything using objectType try serviceType
2949 return undef unless $term; # and bail out if we didn't succeed
2950 $ontology ||= "service"; # if we have now succeeded and haven't already taken the ontology then it must be the service ontology
2951 $debug && &_LOG
("Ontology was $ontology; Term was $term\n");
2952 my $OS = MOBY
::OntologyServer
->new( ontology
=> $ontology );
2954 # WE WOULD PREFER TO LOOP OVER EACH KEY IN %RELTYPE HERE, BUT HARD CODED TO JUST ISA
2955 $relationship ||='isa';
2956 my %rels = %{ $OS->Relationships(
2958 expand
=> $expand_relationship,
2959 relationship
=> $relationship, # ISA always
2961 )}; # %rels = $rels{relationship} = [lsid, lsid,lsid]
2962 my $response = "<Relationships>\n";
2963 my $OSrel = MOBY
::OntologyServer
->new( ontology
=> 'relationship' );
2965 # this routine is kinda stupid now...
2966 foreach ( keys %reltypes ) { # for each of our desired types
2967 my $rellsid = $OSrel->getRelationshipURI( $ontology, $_ ); # get the LSID
2968 delete $reltypes{$_}; # remove the non-LSID version from the hash
2969 $reltypes{$rellsid} = 1; # set the LSID as valid
2972 # now for each of the relationship types that we were returned
2973 foreach ( keys %rels ) {
2974 my $rellsid = $OSrel->getRelationshipURI( $ontology, $_ );
2975 next unless $rellsid;
2976 if ( keys %reltypes ) {
2977 next unless $reltypes{ $rellsid}; # next unless it is one ofthe relationship types we requested
2979 next unless $rels{$rellsid};
2980 my @lsids_articles = @
{$rels{$rellsid}};
2981 next unless scalar @lsids_articles;
2983 # THE ISA RELATIONSHIP IS NOW HARD!
2985 $response .= "<Relationship relationshipType='$relationship' lsid='$rellsid'>\n";
2986 foreach my $lsid_article ( @lsids_articles ) {
2987 my $lsid = $lsid_article->{lsid
};
2988 my $term = $lsid_article->{term
};
2989 my $articleName = $lsid_article->{articleName
};
2990 $response .= "<${ontology}Type lsid='$lsid' ";
2991 $response .= "articleName='$articleName'" if $articleName;
2992 $response .= ">$term</${ontology}Type>\n";
2994 $response .= "</Relationship>\n";
2996 $response .= "</Relationships>\n";
3003 Usage : $SQL = $MOBY->DUMP_MySQL; ($central,$object,$service,$namespace,$relat) = @{$SQL};
3004 Function : return a mysql dump of each of the current MOBY Central databases
3005 Returns : an array of SQL strings that can be used to recreate the database locally
3012 my $config = MOBY
::Config
->new();
3014 'mobycentral', 'mobyobject',
3015 'mobyservice', 'mobynamespace',
3019 foreach my $dbsection (@dbsections) {
3020 my $dbname = ${ ${$config}{$dbsection} }{'dbname'};
3021 my $username = ${ ${$config}{$dbsection} }{'username'};
3022 my $password = ${ ${$config}{$dbsection} }{'password'};
3023 my $host = ${ ${$config}{$dbsection} }{'url'};
3024 my $port = ${ ${$config}{$dbsection} }{'port'};
3026 "mysqldump -h $host -P $port -u $username --password=$password $dbname|"
3028 || die "can't open $dbname for dumping";
3033 my $dbdump = ( join "", @dbdump );
3034 push @response, $dbdump;
3038 *DUMP
= \
&DUMP_MySQL
; # alias it for backward compatibility
3039 *DUMP
= \
&DUMP_MySQL
; # alias it for backward compatibility
3042 # $CONFIG ||= MOBY::Config->new; # exported by Config.pm
3043 # my $adaptor = $CONFIG->getDataAdaptor( datasource => 'mobycentral' );
3045 # # from a given term, traverse the ontology
3046 # # and flatten it into a list of parent terms
3047 # my ( $dbh, $type, $term, $seen ) = @_;
3049 # my $result = $adaptor->get_parent_terms(relationship_type_id => $type,
3052 # foreach my $row (@$result) {
3053 # my $term = $row->{term};
3054 # next if ${$seen}{$term};
3055 # &_flatten( $dbh, $type, $term, $seen );
3056 # ${$seen}{$term} = 1;
3063 my $Parser = XML
::LibXML
->new();
3064 my $doc = $Parser->parse_string($payload);
3065 my $Object = $doc->getDocumentElement();
3066 my $obj = $Object->nodeName;
3067 return undef unless ( $obj eq 'ISA' );
3068 my $type = &_nodeTextContent
( $Object, "objectType" );
3080 =head1 Internal Object Methods
3085 =head2 _getValidServices
3087 Title : _getValidServices
3088 Usage : %valid = $MOBY->_getValidServices($sth_hash, $query, $max_return)
3089 Function : execute the query in $query to return a non-redundant list of matching services
3095 #sub _getValidServices {
3096 # my ($sth_hash, $query, $max_return ) = @_;
3097 # my %sth = %{$sth_hash};
3098 # $debug && &_LOG("QUERY: \n$query\n\n");
3099 # my $this_query = $dbh->prepare($query);
3100 # $this_query->execute;
3103 # $response = "<Services>\n";
3105 # while ( my ( $serviceName, $objectOUT, $AuthURI, $desc, $type, $cat ) =
3106 # $this_query->fetchrow_array() )
3109 # && &_LOG("$serviceName, $objectOUT, $AuthURI,$desc, $type, $cat\n");
3111 # if $seen{ "$AuthURI" . "||"
3112 # . "$serviceName" }; # non-redundant list please
3113 # $seen{ "$AuthURI" . "||" . "$serviceName" } = 1;
3115 # "<Service authURI='$AuthURI' serviceName='$serviceName'>\n";
3116 # $response .= "<Category>$cat</Category>\n";
3117 # $response .= "<serviceType>$type</serviceType>\n";
3118 # $response .= "<outputObject>$objectOUT</outputObject>\n";
3119 # if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
3122 # $response .= "<Description><![CDATA[$desc]]></Description>\n";
3123 # $response .= "</Service>\n";
3124 # if ($max_return) { --$max_return; last unless $max_return }
3126 # $response .= "</Services>\n";
3127 # $debug && &_LOG("\nFINAL RESPONSE IS \n$response\n\n");
3131 =head2 _getServiceWSDL
3133 Title : _getServiceWSDL
3134 Usage : @valid = $MOBY->_getValidServices($dbh, $sth_hash, $query)
3135 Function : execute the query in $query to return a non-redundant list of matching services
3136 Returns : list of response strings in wsdl
3141 sub _getServiceWSDL
{
3142 my ( $SI, $InputXML, $OutputXML, $SecondaryXML ) = @_;
3144 # the lines below causes no end of grief. It is now in a variable.
3145 #open (WSDL, "./MOBY/Central_WSDL_SandR.wsdl") || die "can't open WSDL file for search and replace\n";
3146 #my $wsdl = join "", (<WSDL>);
3147 my $wsdl = $WSDL_TEMPLATE;
3152 my $serviceName = $SI->servicename;
3153 my $AuthURI = $SI->authority_uri;
3154 my $desc = $SI->description;
3155 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
3159 my $IN = "NOT_YET_DEFINED_INPUTS";
3160 my $OUT = "NOT_YET_DEFINED_OUTPUTS";
3161 my $INxsd = &_getInputXSD
( $InputXML, $SecondaryXML );
3162 my $OUTxsd = &_getOutputXSD
($OutputXML);
3163 $INxsd ||= "<NOT_YET_IMPLEMENTED_INPUT_XSD/>";
3164 $OUTxsd ||= "<NOT_YET_IMPLEMENTED_OUTPUT_XSD/>";
3165 $wsdl =~ s/MOBY__SERVICE__NAME__/$serviceName/g; # replace all of the goofy portbindingpottype crap
3166 $wsdl =~s/\<\!\-\-\s*MOBY__SERVICE__DESCRIPTION\s*\-\-\>/Authority: $AuthURI - $desc/g; # add a sensible description
3167 $wsdl =~ s/MOBY__SERVICE__URL/$URL/g; # the URL to the service
3168 #if (scalar @in){my ($IN, $INxsd) = @{shift @in}};
3169 #if (scalar @out){my ($OUT, $OUTxsd) = @{shift @out}};
3170 # $wsdl =~ s/MOBY__INPUT__OBJECT__NAME/$IN/g; # SINGLE input object (for now)
3171 # $wsdl =~ s/MOBY__OUTPUT__OBJECT__NAME/$OUT/g; # SINGLE output object (for now)
3172 # $wsdl =~ s/\<\!\-\-\s*MOBY__INPUT__OBJECT__XSD\s*\-\-\>/$INxsd/g; # XSD stright from the database
3173 # $wsdl =~ s/\<\!\-\-\s*MOBY__OUTPUT__OBJECT__XSD\s*\-\-\>/$OUTxsd/g; # XSD straight from the database
3174 $wsdl =~ s/MOBY__SERVICE__NAME/$serviceName/g; # finally replace the actual subroutine call
3178 #sub _getCGIService {
3179 # my ( $dbh, $sth_hash, $id, $serviceName, $AuthURI, $URL, $desc, $category )
3181 # my %sth = %{$sth_hash};
3183 # # "Select OE.term, O.xsd, SP.type
3184 # # from Object as O, OntologyEntry as OE, ServiceParameter as SP, Service as S
3185 # # where O.ontologyentry_id = OE.id
3186 # # AND SP.ontologyentry_id = OE.id
3187 # # and SP.service_id = ?
3188 # my $sth = $dbh->prepare( $sth{get_server_parameters} );
3189 # $sth->execute($id);
3190 # my ( $Object, $sprintf, $in ) = $sth->fetchrow_array();
3191 # if ( $sprintf =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
3194 # return "<GETstring><![CDATA[$sprintf]]></GETstring>";
3199 sub _nodeTextContent
{
3201 # will get text of **all** child $node from the given $DOM
3202 # regardless of their depth!!
3203 my ( $DOM, $node ) = @_;
3204 $debug && &_LOG
( "_nodeTextContent received DOM: ",
3205 $DOM->toString, "\nsearching for node $node\n" );
3206 my $x = $DOM->getElementsByTagName($node);
3207 return undef unless $x->get_node(1);
3208 my @child = $x->get_node(1)->childNodes;
3212 && &_LOG
( $_->nodeType, "\t", $_->toString, "\n" );
3214 #next unless $_->nodeType == TEXT_NODE;
3215 $content .= $_->textContent;
3220 sub _nodeCDATAContent
{
3222 # will get text of **all** child $node from the given $DOM
3223 # regardless of their depth!!
3224 my ( $DOM, $node ) = @_;
3225 $debug && &_LOG
( "_nodeTextContent received DOM: ",
3226 $DOM->toString, "\nsearching for node $node\n" );
3227 my $x = $DOM->getElementsByTagName($node);
3228 return undef unless $x->get_node(1);
3229 my @child = $x->get_node(1)->childNodes;
3233 && &_LOG
( $_->nodeType, "\t", $_->toString, "\n" );
3235 #next unless $_->nodeType == TEXT_NODE;
3236 if ( $_->toString =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
3240 $content .= $_->textContent;
3247 sub _nodeRawContent
{
3249 # will get raw child nodes of $node from the given $DOM
3250 my ( $DOM, $nodename ) = @_;
3252 $debug && &_LOG
( "_nodeRawContent received DOM: ",
3253 $DOM->toString, "\nsearching for node $nodename\n" );
3254 my $x = $DOM->getElementsByTagName($nodename);
3255 my $node = $x->get_node(1);
3256 return [] unless $node;
3257 foreach my $child ( $node->childNodes ) {
3258 next unless $child->nodeType == ELEMENT_NODE
;
3259 push @content, $child;
3265 sub _nodeArrayContent
{
3267 # will get array content of all child $node from given $DOM
3268 # regardless of depth!
3269 # e.g. the following XML:
3271 # <objectType>first</objectType>
3272 # <objectType>second</objectType>
3274 #will return the list "first", "second"
3275 my ( $DOM, $node ) = @_;
3276 $debug && &_LOG
( "_nodeArrayContext received DOM: ",
3277 $DOM->toString, "\nsearching for node $node\n" );
3279 my $x = $DOM->getElementsByTagName($node);
3280 return @result unless $x->get_node(1);
3281 my @child = $x->get_node(1)->childNodes;
3283 next unless $_->nodeType == ELEMENT_NODE
;
3284 my @child2 = $_->childNodes;
3287 #print getNodeTypeName($_), "\t", $_->toString,"\n";
3288 next unless $_->nodeType == TEXT_NODE
;
3289 next unless ( length( $_->toString ) > 0 );
3290 push @result, $_->toString;
3293 $debug && _LOG
("_nodeArrayContent resulted in @result\n");
3298 sub _nodeArrayExtraContent
{
3300 # will get array content of all child $node from given $DOM
3301 # regardless of depth!
3302 # e.g. the following XML:
3304 # <objectType articleName="thisone">first</objectType>
3305 # <objectType articleName="otherone">second</objectType>
3307 #will return the list
3308 # ['first',{'articleName' => 'thisone'}],
3309 # ['second',{'articleName' => 'otherone'},...
3310 my ( $DOM, $node, @attrs ) = @_;
3311 $debug && &_LOG
( "_nodeArrayExtraContext received DOM: ",
3312 $DOM->toString, "\nsearching for node $node\n" );
3315 my $x = $DOM->getElementsByTagName($node);
3316 my @child = $x->get_node(1)->childNodes;
3318 next unless $_->nodeType == ELEMENT_NODE
;
3319 foreach my $attr (@attrs) {
3320 $debug && &_LOG
( "_nodeArrayExtraContext received DOM: ",
3321 $DOM->toString, "\nsearching for attributre $attr\n" );
3323 $_->getAttributeNode($attr); # may or may not have a name
3324 if ($article) { $article = $article->getValue() }
3325 $att_value{$attr} = $article;
3327 my @child2 = $_->childNodes;
3330 #print getNodeTypeName($_), "\t", $_->toString,"\n";
3331 next unless $_->nodeType == TEXT_NODE
;
3332 push @result, [ $_->toString, \
%att_value ];
3335 $debug && &_LOG
(@result);
3339 sub _serviceListResponse
{
3343 # this routine is using service instances by their database ID, rather than their LSID
3344 # this is BAD BAD BAD
3345 $CONFIG ||= MOBY
::Config
->new; # exported by Config.pm
3346 my $adaptor = $CONFIG->getDataAdaptor( datasource
=> 'mobycentral' );
3350 my $OSobj = MOBY
::OntologyServer
->new( ontology
=> 'object' );
3351 my $OSns = MOBY
::OntologyServer
->new( ontology
=> 'namespace' );
3352 my $OSserv = MOBY
::OntologyServer
->new( ontology
=> 'service' );
3355 # this routine is using service instances by their database ID, rather than their LSID
3356 # this is BAD BAD BAD
3359 my $result = $adaptor->query_service_instance(service_instance_id
=> $_);
3360 my $row = shift(@
$result);
3361 my $category = $row->{category
};
3362 my $url = $row->{url
};
3363 my $servicename = $row->{servicename
};
3364 my $service_type_uri = $row->{service_type_uri
};
3365 my $authority_uri = $row->{authority_uri
};
3366 my $desc = $row->{description
};
3367 my $authoritative = $row->{authoritative
};
3368 my $email = $row->{contact_email
};
3369 my $signatureURL = $row->{signatureURL
};
3370 my $lsid = $row->{lsid
};
3372 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
3376 $signatureURL ||= "";
3377 next unless ( $servicename && $authority_uri );
3378 my $service_type = $OSserv->getServiceCommonName($service_type_uri);
3380 $output .= "\t<Service authURI='$authority_uri' serviceName='$servicename' lsid='$lsid'>\n";
3381 $output .= "\t<serviceType>$service_type</serviceType>\n";
3382 $output .= "\t<authoritative>$authoritative</authoritative>\n";
3383 $output .= "\t<Category>$category</Category>\n";
3384 $output .= "\t<Description><![CDATA[$desc]]></Description>\n";
3385 $output .= "\t<contactEmail>$email</contactEmail>\n";
3386 $output .= "\t<signatureURL>$signatureURL</signatureURL>\n";
3387 $output .= "\t<URL>$url</URL>\n";
3388 $output .= "\t<Input>\n";
3390 $result = $adaptor->query_simple_input(service_instance_lsid
=> $lsid);
3392 foreach my $row (@
$result)
3394 my $objURI = $row->{object_type_uri
};
3395 my $nsURI = $row->{namespace_type_uris
};
3396 my $article = $row->{article_name
};
3398 my $objName = $OSobj->getObjectCommonName($objURI);
3400 my @nsURIs = split ",", $nsURI;
3402 $output .= "\t\t<Simple articleName='$article'>\n";
3403 $output .= "\t\t\t<objectType lsid='$objURI'>$objName</objectType>\n";
3404 foreach my $ns (@nsURIs) {
3405 my $NSname = $OSns->getNamespaceCommonName($ns);
3406 $output .= "\t\t\t<Namespace lsid='$ns'>$NSname</Namespace>\n" if $NSname;
3408 $output .= "\t\t</Simple>\n";
3410 $result = $adaptor->query_collection_input(service_instance_lsid
=> $lsid);
3412 foreach my $row (@
$result)
3414 my $collid = $row->{collection_input_id
};
3415 my $articlename = $row->{article_name
};
3417 $output .= "\t\t<Collection articleName='$articlename'>\n";
3419 my $result2 = $adaptor->query_simple_input(service_instance_lsid
=> undef, collection_input_id
=> $collid);
3420 foreach my $row2 (@
$result2)
3422 my $objURI = $row2->{object_type_uri
};
3423 my $nsURI = $row2->{namespace_type_uris
};
3424 my $article = $row2->{article_name
};
3426 my $objName = $OSobj->getObjectCommonName($objURI);
3428 my @nsURIs = split ",", $nsURI;
3430 $output .= "\t\t\t<Simple articleName='$article'>\n";
3431 $output .= "\t\t\t\t<objectType lsid='$objURI'>$objName</objectType>\n";
3432 foreach my $ns (@nsURIs) {
3433 my $NSname = $OSns->getNamespaceCommonName($ns);
3434 $output .= "\t\t\t\t<Namespace lsid='$ns'>$NSname</Namespace>\n"
3437 $output .= "\t\t\t</Simple>\n";
3439 $output .= "\t\t</Collection>\n";
3441 $output .= "\t</Input>\n";
3442 $output .= "\t<Output>\n";
3444 $result = $adaptor->query_simple_output(service_instance_lsid
=> $lsid, collection_output_id
=> undef);
3446 foreach my $row (@
$result)
3448 my $objURI = $row->{object_type_uri
};
3449 my $nsURI = $row->{namespace_type_uris
};
3450 my $article = $row->{article_name
};
3452 my $objName = $OSobj->getObjectCommonName($objURI);
3454 my @nsURIs = split ",", $nsURI;
3456 $output .= "\t\t<Simple articleName='$article'>\n";
3457 $output .= "\t\t\t<objectType lsid='$objURI'>$objName</objectType>\n";
3458 foreach my $ns (@nsURIs) {
3459 my $NSname = $OSns->getNamespaceCommonName($ns);
3460 $output .= "\t\t\t<Namespace lsid='$ns'>$NSname</Namespace>\n" if $NSname;
3462 $output .= "\t\t</Simple>\n";
3465 $result = $adaptor->query_collection_output(service_instance_lsid
=> $lsid);
3466 foreach my $row (@
$result)
3468 my $collid = $row->{collection_output_id
};
3469 my $articlename = $row->{article_name
};
3470 $output .= "\t\t<Collection articleName='$articlename'>\n";
3472 my $result2 = $adaptor->query_simple_output(service_instance_lsid
=> undef, collection_output_id
=> $collid);
3473 foreach my $row2 (@
$result2 )
3475 my $objURI = $row2->{object_type_uri
};
3476 my $nsURI = $row2->{namespace_type_uris
};
3477 my $article = $row2->{article_name
};
3478 my $objName = $OSobj->getObjectCommonName($objURI);
3480 my @nsURIs = split ",", $nsURI;
3482 $output .= "\t\t\t<Simple articleName='$article'>\n";
3483 $output .= "\t\t\t\t<objectType lsid='$objURI'>$objName</objectType>\n";
3484 foreach my $ns (@nsURIs) {
3485 my $NSname = $OSns->getNamespaceCommonName($ns);
3486 $output .= "\t\t\t\t<Namespace lsid='$ns'>$NSname</Namespace>\n"
3489 $output .= "\t\t\t</Simple>\n";
3491 $output .= "\t\t</Collection>\n";
3493 $output .= "\t</Output>\n";
3494 $output .= "\t<secondaryArticles>\n";
3495 $result = $adaptor->query_secondary_input(service_instance_lsid
=> $lsid);
3496 foreach my $row (@
$result)
3497 { my($default_value, $maximum_value, $minimum_value, $enum_value, $datatype, $article_name) = ("","","","","","");
3498 $default_value = $row->{default_value
};
3499 $maximum_value = $row->{maximum_value
};
3500 $minimum_value = $row->{minimum_value
};
3501 $enum_value = $row->{enum_value
};
3502 $datatype = $row->{datatype
};
3503 $article_name = $row->{article_name
};
3505 $output .= "\t\t\t<Parameter articleName='$article_name'>\n";
3506 $output .= "\t\t\t\t<datatype>$datatype</datatype>\n";
3507 $output .= "\t\t\t\t<default>$default_value</default>\n";
3508 $output .= "\t\t\t\t<max>$maximum_value</max>\n";
3509 $output .= "\t\t\t\t<min>$minimum_value</min>\n";
3510 my @enums = split ",", $enum_value;
3512 if ( scalar(@enums) ) {
3513 foreach my $enum (@enums) {
3514 $output .= "\t\t\t\t<enum>$enum</enum>\n";
3518 $output .= "\t\t\t\t<enum></enum>\n";
3520 $output .= "\t\t\t</Parameter>\n";
3522 $output .= "\t\t</secondaryArticles>\n";
3523 $output .= "\t</Service>\n";
3525 return "<Services>\n$output\n</Services>\n";
3529 my ( $message, $id ) = @_;
3533 my $reg = &Registration
(
3536 message
=> "$message",
3544 my ( $message, $id, $RDF ) = @_;
3545 my $reg = &Registration
(
3548 message
=> "$message",
3556 sub _getOntologyServer
{ # may want to make this more complex
3558 my $OS = MOBY
::OntologyServer
->new(%args);
3565 return unless $debug;
3566 #print join "\n", @_;
3569 open LOG
, ">>/tmp/CentralRegistryLogOut.txt"
3570 or die "can't open mobycentral error logfile $!\n";
3571 print LOG
join "\n", @_;
3572 print LOG
"\n---\n";
3578 # --------------------------------------------------------------------------------------------------------
3584 $WSDL_TEMPLATE = <<END;
3585 <?xml version="1.0"?>
3586 <wsdl:definitions name="MOBY_Central_Generated_WSDL"
3587 targetNamespace="http://biomoby.org/Central.wsdl"
3588 xmlns:tns="http://biomoby.org/Central.wsdl"
3589 xmlns:xsd1="http://biomoby.org/CentralXSDs.xsd"
3590 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
3591 xmlns:xsd="http://www.w3.org/1999/XMLSchema"
3592 xmlns="http://schemas.xmlsoap.org/wsdl/"
3593 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
3596 <wsdl:message name="MOBY__SERVICE__NAME__Input">
3597 <wsdl:part name="data" type="xsd:string"/>
3600 <wsdl:message name="MOBY__SERVICE__NAME__Output">
3601 <wsdl:part name="body" type="xsd:string"/>
3604 <wsdl:portType name="MOBY__SERVICE__NAME__PortType">
3605 <wsdl:operation name="MOBY__SERVICE__NAME">
3606 <wsdl:input message="tns:MOBY__SERVICE__NAME__Input"/>
3607 <wsdl:output message="tns:MOBY__SERVICE__NAME__Output"/>
3611 <wsdl:binding name="MOBY__SERVICE__NAME__Binding" type="tns:MOBY__SERVICE__NAME__PortType">
3612 <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
3613 <wsdl:operation name="MOBY__SERVICE__NAME"><!-- in essense, this is the name of the subroutine that is called -->
3614 <soap:operation soapAction='http://biomoby.org/#MOBY__SERVICE__NAME' style='rpc'/>
3616 <soap:body use="encoded" namespace="http://biomoby.org/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
3619 <soap:body use="encoded"/>
3624 <wsdl:service name="MOBY__SERVICE__NAME__Service">
3625 <wsdl:documentation><!-- MOBY__SERVICE__DESCRIPTION --></wsdl:documentation> <!-- service description goes here -->
3626 <wsdl:port name="MOBY__SERVICE__NAME__Port" binding="tns:MOBY__SERVICE__NAME__Binding">
3627 <soap:address location="MOBY__SERVICE__URL"/> <!-- URL to service scriptname -->
3638 name : _getInputXSD($InputXML, $SecondaryXML)
3639 function: to get an XSD describing the input to a MOBY Service,
3640 e.g. to use in a WSDL document
3641 args : (see _serviceListResponse code above for full details of XML)
3642 $InputXML - the <Input>...</Input> block of a findService
3645 $SecondaryXML - the <secondaryArticles>...<sescondaryArticles>
3646 fragment of a findService response message
3648 returns : XSD fragment of XML (should not return an XML header!)
3649 notes : the structure of an Input block is as follows:
3651 <!-- one or more Simple or Collection articles -->
3654 the structure of a secondaryArticle block is as follows:
3655 <sescondaryArticles>
3656 <!-- one or more Parameter blocks -->
3657 </secondaryArticles>
3664 <Simple articleName="NameOfArticle">
3665 <objectType>ObjectOntologyTerm</objectType>
3666 <Namespace>NamespaceTerm</Namespace>
3667 <Namespace>...</Namespace><!-- one or more... -->
3670 =item * Collection note that articleName of the contained Simple objects is not required, and is ignored.
3673 <Collection articleName="NameOfArticle">
3674 <Simple>......</Simple> <!-- Simple parameter type structure -->
3675 <Simple>......</Simple> <!-- DIFFERENT Simple parameter type
3676 (used only when multiple Object Classes
3677 appear in a collection) -->
3683 <Parameter articleName="NameOfArticle">
3684 <datatype>INT|FLOAT|STRING</datatype>
3685 <default>...</default> <!-- any/all of these -->
3686 <max>...</max> <!-- ... -->
3687 <min>...</min> <!-- ... -->
3688 <enum>...<enum> <!-- ... -->
3689 <enum>...<enum> <!-- ... -->
3697 my ( $Input, $Secondary ) = @_;
3704 name : _getOutputXSD($OutputXML)
3705 function: to get an XSD describing the output from a MOBY Service
3706 e.g. to use in a WSDL document
3707 args : (see _serviceListResponse code above for full details)
3708 $InputXML - the <Input>...</Input> block of a findService
3711 $SecondaryXML - the <secondaryArticles>...<sescondaryArticles>
3712 fragment of a findService response message
3714 returns : XSD fragment of XML (should not return an XML header!)
3715 notes : the structure of an Output block is as follows:
3717 <!-- one or more Simple or Collection articles -->
3724 <Simple articleName="NameOfArticle">
3725 <objectType>ObjectOntologyTerm</objectType>
3726 <Namespace>NamespaceTerm</Namespace>
3727 <Namespace>...</Namespace><!-- one or more... -->
3730 =item * Collection note that articleName of the contained Simple objects is not required, and is ignored.
3733 <Collection articleName="NameOfArticle">
3734 <Simple>......</Simple> <!-- Simple parameter type structure -->
3735 <Simple>......</Simple> <!-- DIFFERENT Simple parameter type
3736 (used only when multiple Object Classes
3737 appear in a collection) -->