1 #$Id: Central.pm,v 1.133 2006/02/08 22:47:28 fgibbons Exp $
2 package MOBY
::Client
::Central
;
5 #use SOAP::Lite + trace; # for debugging
9 use MOBY
::MobyXMLConstants
;
10 use MOBY
::Client
::ServiceInstance
;
11 use MOBY
::Client
::Registration
;
12 use MOBY
::Client
::SimpleArticle
;
13 use MOBY
::Client
::CollectionArticle
;
14 use MOBY
::Client
::SecondaryArticle
;
15 use MOBY
::Client
::OntologyServer
;
16 use vars
qw($AUTOLOAD @ISA $MOBY_server $MOBY_uri);
20 MOBY::Client::Central - a client side wrapper for MOBY Central
26 use MOBY::Client::Central;
27 my $Central = MOBY::Client::Central->new();
29 my ($Services, $REG) = $Central->findService(
31 [DNASequence => ['NCBI_gi', 'NCBI_Acc']],
36 print "Service discovery failed with the following errror: ";
40 foreach my $SERVICE(@{$Services}){
41 print "Service Name: ", $SERVICE->name, "\n";
42 print "Service Provider: ", $SERVICE->authority,"\n";
50 Client side "wrapper" for communicating with
51 the MOBY::Central registry.
53 Used to do various read-only transactions with MOBY-Central. Parses
54 MOBY::Central XML output into Perlish lists, hashes, and objects. This should
55 be sufficient for most or all MOBY Client activities written in Perl.
63 Mark Wilkinson (markw@illuminae.com)
65 BioMOBY Project: http://www.biomoby.org
76 Usage : my $MOBY = MOBY::Client::Central->new(Registries => \%regrefs)
77 Function : connect to one or more MOBY-Central
78 registries for searching
79 Returns : MOBY::Client::Central object
81 ENV & PROXY : you can set environment variables to change the defaults.
82 By default, a call to 'new' will initialize MOBY::Client::Central
83 to connect to the MOBY Central registry at:
84 http://mobycentral.cbr.nrc.ca/cgi-bin/MOBY05/mobycentral.pl
85 If you wish to chose another registry by default, or if you need
86 to set up additional connection details (e.g. PROXY) then you may
87 set the following environment variables to whatever you
89 MOBY_SERVER (default http://mobycentral.cbr.nrc.ca/cgi-bin/MOBY05/mobycentral.pl)
90 MOBY_URI (default http://mobycentral.cbr.nrc.ca/MOBY/Central)
91 MOBY_PROXY (no default)
93 Args : Registries - optional.
98 PROXY => $proxy_server},
102 PROXY => $proxy_server},
104 - by default this becomes
106 URL => 'http://mobycentral.cbr.nrc.ca/cgi-bin/MOBY05/mobycentral.pl',
107 URI => 'http://mobycentral.cbr.nrc.ca/MOBY/Central'}
109 Discussion: Each registry must have a different
110 NAME. If you have more than one
111 registry with the same NAME, only
112 one will be used. You can NAME them
113 however you please - this is for
114 internal reference only. You will
115 make subsequent calls on one or more
116 of these registries by NAME, or by
117 default on all registries.
118 Notes : BE CAREFUL WITH OBJECT/SERVICE
119 REGISTRATION!! YOU WILL REGISTER
120 IN EVERY MOBY-CENTRAL YOU HAVE
121 NAMED! If you do not host a MOBY::Central
122 database locally, or don't know
123 better,then don't use any arguments
124 at all, and everything should work
131 open( OUT, ">/tmp/CentralLogOut.txt" )
132 || die "cant open logfile CentralLogOut.txt $!\n";
139 #___________________________________________________________
141 my %_attr_data = # DEFAULT ACCESSIBILITY
143 Connections => [ undef, 'read/write' ],
144 default_MOBY_servername => [ 'mobycentral', 'read/write' ],
145 default_MOBY_server => [
146 'http://mobycentral.icapture.ubc.ca/cgi-bin/MOBY05/mobycentral.pl',
150 [ 'http://mobycentral.icapture.ubc.ca/MOBY/Central', 'read/write' ],
151 default_MOBY_proxy => [ undef, 'read/write' ],
152 default_MOBY_type => [ 'soap', 'read/write' ],
153 Registries => [ undef, 'read/write' ],
154 multiple_registries => [ undef, 'read/write' ],
156 # SWITCH TO THESE FOR A LOCAL MOBY CENTRAL REGISTRY
157 #default_MOBY_server => ['http://localhost/cgi-bin/MOBY-Central.pl', 'read/write'],
158 #default_MOBY_uri => ['http://localhost/MOBY/Central', 'read/write'],
161 #_____________________________________________________________
162 # METHODS, to operate on encapsulated class data
163 # Is a specified object attribute accessible in a given mode
165 my ( $self, $attr, $mode ) = @_;
166 return 0 unless ( $mode && $_attr_data{$attr} );
167 $_attr_data{$attr}[1] =~ /$mode/;
170 # Classwide default value for a specified object attribute
172 my ( $self, $attr ) = @_;
173 $_attr_data{$attr}[0];
176 # List of names of all specified object attributes
182 my ( $self, $desired ) = @_;
184 while ( my ( $name, $type, $connect ) =
185 ( @{ $self->Connections->[0] } ) )
187 return ( $type, $connect ) if $name eq $desired;
191 my ( $name, $type, $connect ) = @{ $self->Connections->[0] };
192 return ( $type, $connect );
194 return ( undef, undef );
200 # this method replaces the former calls directly
201 # to teh SOAP_Connection, to give more flexibility
202 # in how that call is made
203 # most subroutines in here do the following:
204 # $return = $self->SOAP_connection->call(registerObjectClass => ($message))->paramsall;
205 # or $payload = $self->SOAP_connection($reg)->call('Relationships' => ($m))->paramsall;
206 # so intercept that and figure out if we are actually making a SOAP call or not
207 # and determine which registry it is
208 my ( $self, $reg, $method, @params ) = @_;
209 $reg = $self->default_MOBY_servername if $reg eq "default";
210 $reg = $self->default_MOBY_servername if !$reg;
211 my ( $type, $connect ) = $self->Connection($reg);
212 return "<result>EXECUTION ERROR - registry $reg not found</result>"
213 unless ( $type && $connect );
214 my $param = join "", @params; # must be a single message!
215 if ( lc($type) eq "get" ) {
217 #print STDERR "executing CGI call\n";
219 my $ua = LWP::UserAgent->new;
221 $param =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
222 my $paramstring = "?action=$method";
223 $paramstring .= ";payload=$param" if $param;
224 my $req = HTTP::Request->new( GET => $connect . $paramstring );
225 my $res = $ua->request($req);
226 if ( $res->is_success ) {
227 return $res->content;
231 "<result>EXECUTION ERROR - unsuccessful call to MOBY Central registry named '$reg'</result>";
236 #print STDERR "executing SOAP call\n";
237 my @payload = $connect->call( $method => $param )->paramsall;
243 my ( $caller, %args ) = @_;
244 my $caller_is_obj = ref($caller);
245 return $caller if $caller_is_obj;
246 my $class = $caller_is_obj || $caller;
248 my $self = bless {}, $class;
249 foreach my $attrname ( $self->_standard_keys ) {
250 if ( exists $args{$attrname} ) {
251 $self->{$attrname} = $args{$attrname};
253 elsif ($caller_is_obj) {
254 $self->{$attrname} = $caller->{$attrname};
257 $self->{$attrname} = $self->_default_for($attrname);
260 $self->Connections( [] ); # initialize;
262 # if user has set up preferred servers, then use those by default
263 $self->default_MOBY_server( $ENV{MOBY_SERVER} ) if $ENV{MOBY_SERVER};
264 $self->default_MOBY_uri( $ENV{MOBY_URI} ) if $ENV{MOBY_URI};
265 $self->default_MOBY_type( $ENV{MOBY_TYPE} ) if $ENV{MOBY_TYPE};
266 $self->default_MOBY_proxy( $ENV{MOBY_PROXY} ) if $ENV{MOBY_PROXY};
267 if ( $self->Registries ) {
269 my %reg = %{ $self->Registries };
270 while ( my ( $name, $acc ) = each %reg ) {
271 $regno++; # count how many registries we have in total
272 my $url = $acc->{URL} ? $acc->{URL} : $self->default_MOBY_server;
273 my $uri = $acc->{URI} ? $acc->{URI} : $self->default_MOBY_uri;
274 my $type = $acc->{TYPE} ? $acc->{TYPE} : $self->default_MOBY_type;
275 my $proxy = $acc->{PROXY} ? $acc->{PROXY} : $self->default_MOBY_proxy;
277 if ( lc($type) eq "get" ) {
278 push @{ $self->Connections }, [ $name, $type, $url ];
283 @soapargs = ( $url, proxy => [ 'http' => $proxy ] );
288 push @{ $self->Connections },
291 SOAP::Lite->proxy(@soapargs)->uri($uri)->on_fault(
293 my ( $soap, $res ) = @_;
295 ? ("\nConnection to MOBY Central at '$uri' died because:\n\t" . $res->faultstring)
296 : ("Failed with status:" . $soap->transport->status),
297 "\n ERROR ERROR ERROR\n";
302 } # Done iterating over multiple registries
303 $self->multiple_registries( $regno - 1 )
304 ; # one is not "multiple", it is just a change in default -> set to "false" if only one
306 else { # no registries specified
307 $self->multiple_registries(0);
308 if ( lc( $self->default_MOBY_type ) eq "get" ) {
309 push @{ $self->Connections },
311 $self->default_MOBY_servername, $self->default_MOBY_type,
312 $self->default_MOBY_server
318 $self->default_MOBY_servername => {
319 URL => $self->default_MOBY_server,
320 URI => $self->default_MOBY_uri
325 if ( $self->default_MOBY_proxy ) {
327 $self->default_MOBY_server,
328 proxy => [ 'http' => $self->default_MOBY_proxy ]
332 @soapargs = ( $self->default_MOBY_server );
334 push @{ $self->Connections },
336 $self->default_MOBY_servername,
337 $self->default_MOBY_type,
338 SOAP::Lite->proxy(@soapargs)->uri( $self->default_MOBY_uri )
341 my ( $soap, $res ) = @_;
343 ? ("\nConnection to default MOBY Central died because:\n\t" . $res->faultstring)
344 : ("Failed with status:" . $soap->transport->status),
345 "\n ERROR ERROR ERROR\n";
351 return undef unless $self->Connection(); # gotta have at least one...
355 =head2 registerObject a.k.a registerObjectClass
357 Usage : $REG = $MOBY->registerObject(%args)
358 Usage : $REG = $MOBY->registerObjectClass(%args)
359 Function : register a new type of MOBY Object
360 Returns : MOBY::Registration object
361 Args : objectType => "the name of the Object"
362 description => "a human-readable description of the object"
363 contactEmail => "your@email.address"
364 authURI => "URI of the registrar of this object"
366 relationshipType1 => [
368 articleName => ArticleName1},
370 articleName => ArticleName2}
372 relationshipType2 => [
374 articleName => ArticleName3}
380 sub registerObjectClass {
381 my ( $self, %a ) = @_;
382 return $self->registerObject(%a);
386 my ( $self, %a ) = @_;
387 return $self->errorRegXML(
388 "Function not allowed when querying multiple registries")
389 if $self->multiple_registries;
390 return $self->errorRegXML(
391 "Contact email address (contactEmail parameter) is required for object registration"
393 if ( !$a{contactEmail} );
394 my $term = $a{'objectType'} || "";
395 my $desc = $a{'description'} || "";
396 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
399 my $contactEmail = $a{'contactEmail'} || "";
400 my $authURI = $a{'authURI'} || "";
401 my %Relationships = %{ $a{'Relationships'} };
402 my $clobber = $a{'Clobber'} ? $a{'Clobber'} : 0;
403 my $message = "<registerObjectClass>
404 <objectType>$term</objectType>
405 <Description><![CDATA[$desc]]></Description>
406 <authURI>$authURI</authURI>
407 <contactEmail>$contactEmail</contactEmail>
408 <Clobber>$clobber</Clobber>\n";
410 while ( my ( $type, $objlistref ) = each %Relationships ) {
411 $message .= "<Relationship relationshipType='$type'>\n";
412 foreach my $objnamepair ( @{$objlistref} ) {
413 my $object = $objnamepair->{object};
414 my $article = $objnamepair->{articleName};
415 return $self->errorRegXML(
416 "Object name missing from one of your $type relationships")
420 "<objectType articleName='$article'>$object</objectType>\n";
422 $message .= "</Relationship>\n";
424 $message .= "</registerObjectClass>";
426 # my $return = $self->SOAP_connection->call(registerObjectClass => ($message))->paramsall;
427 my ($return) = $self->_call( 'default', 'registerObjectClass', $message );
428 return ( $self->parseRegXML($return) );
431 =head2 deregisterObject a.k.a. deregisterObjectClass
433 Usage : $REG = $MOBY->deregisterObject(%args)
434 Usage : $REG = $MOBY->deregisterObjectClass(%args)
435 Function : deregister a MOBY Object
436 Returns : MOBY::Registration object
437 Args : objectType => $objectName (from Object ontology)
442 sub deregisterObjectClass {
443 my ( $self, %a ) = @_;
444 return $self->deregisterObject(%a);
447 sub deregisterObject {
448 my ( $self, %a ) = @_;
449 return $self->errorRegXML(
450 "Function not allowed when querying multiple registries")
451 if $self->multiple_registries;
452 my $id = $a{'objectType'} || "";
454 <deregisterObjectClass>
455 <objectType>$id</objectType>
456 </deregisterObjectClass>";
458 # my $return = $self->SOAP_connection->call(deregisterObjectClass => ($message))->paramsall;
459 my ($return) = $self->_call( 'default', 'deregisterObjectClass', $message );
460 return ( $self->parseRegXML($return) );
465 =head2 registerServiceType
467 Usage : $REG = $MOBY->registerServiceType(%args)
468 Function : register a new MOBY Service type
469 Returns : MOBY::Registration object
470 Args : serviceType => $serviceType
471 description => "human readable description"
472 Relationships => {$relationshipType1 => \@services,
473 $relationshipType2 => \@services}
474 contactEmail => "your@email.address.here"
475 authURI => "your.authority.info"
479 sub registerServiceType {
480 my ( $self, %a ) = @_;
481 return $self->errorRegXML(
482 "Function not allowed when querying multiple registries")
483 if $self->multiple_registries;
484 my $type = $a{'serviceType'} || "";
485 my $desc = $a{'description'};
486 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
490 my $email = $a{'contactEmail'} || "";
491 my $auth = $a{'authURI'} || "";
492 my %Relationships = %{ $a{'Relationships'} };
494 <registerServiceType>
495 <serviceType>$type</serviceType>
496 <Description><![CDATA[$desc]]></Description>
497 <contactEmail>$email</contactEmail>
498 <authURI>$auth</authURI>\n";
500 while ( my ( $type, $servlistref ) = each %Relationships ) {
501 $message .= "<Relationship relationshipType='$type'>\n";
502 foreach my $servicetype ( @{$servlistref} ) {
503 $message .= "<serviceType>$servicetype</serviceType>\n";
505 $message .= "</Relationship>\n";
507 $message .= "</registerServiceType>";
509 # my $return = $self->SOAP_connection->call(registerServiceType => ($message))->paramsall;
510 my ($return) = $self->_call( 'default', 'registerServiceType', $message );
511 return ( $self->parseRegXML($return) );
514 =head2 deregisterServiceType
516 Usage : $REG = $MOBY->deregisterServiceType(%args)
517 Function : deregister a deprecated MOBY Service Type
518 Returns : MOBY::Registration object
519 Args : serviceType => $serviceType (from ontology)
524 sub deregisterServiceType {
525 my ( $self, %a ) = @_;
526 return $self->errorRegXML(
527 "Function not allowed when querying multiple registries")
528 if $self->multiple_registries;
529 my $id = $a{'serviceType'} || "";
531 <deregisterServiceType>
532 <serviceType>$id</serviceType>
533 </deregisterServiceType>";
535 # my $return = $self->SOAP_connection->call(deregisterServiceType => ($message))->paramsall;
536 my ($return) = $self->_call( 'default', 'deregisterServiceType', $message );
537 return ( $self->parseRegXML($return) );
540 =head2 registerNamespace
542 Usage : $REG = $MOBY->registerNamespace(%args)
543 Function : register a new Namespace
544 Returns : MOBY::Registration object
545 Args : namespaceType => $namespaceType (required)
546 authURI => your.authority.URI (required)
547 description => "human readable description of namespace" (required)
548 contactEmail => "your@address.here" (required)
553 sub registerNamespace {
554 my ( $self, %a ) = @_;
555 return $self->errorRegXML(
556 "Function not allowed when querying multiple registries")
557 if $self->multiple_registries;
558 my $type = $a{'namespaceType'} || "";
559 my $authURI = $a{'authURI'} || "";
560 my $desc = $a{'description'};
561 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
565 my $contact = $a{'contactEmail'} || "";
568 <namespaceType>$type</namespaceType>
569 <Description><![CDATA[$desc]]></Description>
570 <authURI>$authURI</authURI>
571 <contactEmail>$contact</contactEmail>
572 </registerNamespace>";
574 # my $return = $self->SOAP_connection->call(registerNamespace => ($message))->paramsall;
575 my ($return) = $self->_call( 'default', 'registerNamespace', $message );
576 return ( $self->parseRegXML($return) );
579 =head2 deregisterNamespace
581 Usage : $REG = $MOBY->deregisterNamespace(%args)
582 Function : deregister a deprecated MOBY Namespace
583 Returns : MOBY::Registration object
584 Args : namespaceType => $mynamespaceType (from ontology)
589 sub deregisterNamespace {
590 my ( $self, %a ) = @_;
591 return $self->errorRegXML(
592 "Function not allowed when querying multiple registries")
593 if $self->multiple_registries;
594 my $id = $a{'namespaceType'} || "";
596 <deregisterNamespace>
597 <namespaceType>$id</namespaceType>
598 </deregisterNamespace>";
600 # my $return = $self->SOAP_connection->call(deregisterNamespace => ($message))->paramsall;
601 my ($return) = $self->_call( 'default', 'deregisterNamespace', $message );
602 return ( $self->parseRegXML($return) );
605 =head2 registerService
607 Usage : $REG = $MOBY->registerService(%args)
608 Function : register a new MOBY Service instance
609 Returns : MOBY::Registration object
610 Common Required Args :
612 serviceName => $serviceName,
613 serviceType => $serviceType,
615 contactEmail => "your@mail.address",
616 description => $human_readable_description,
617 category => "moby" | "cgi" | "wsdl" (currently only moby and wsdl supported)
618 URL => $URL_TO_SERVICE (or URL to WSDL document for wsdl-type services)
620 input: listref; (articleName may be undef)
622 [articleName1,[objType1 => \@namespaces]], # Simple
623 [articleName2, [[objType2 => \@namespaces]]], # collection of one object type
624 [articleName3,[[objType3 => \@namespaces],
625 [objType4 => \@namespaces]]] # collection of multiple object types
629 output: listref; (articleName may be undef)
631 [articleName1,[objType1 => \@namespaces]], # Simple
632 [articleName2,[[objType2 => \@namespaces]]], # collection of one object type
633 [articleName3,[[objType3 => \@namespaces],
634 [objType4 => \@namespaces]]] # collection of multiple object types
638 secondary => {parametername1 => {
656 sub registerService {
657 my ( $self, %a ) = @_;
658 return $self->errorRegXML(
659 "Function not allowed when querying multiple registries")
660 if $self->multiple_registries;
661 my $name = $a{serviceName} || "";
662 my $type = $a{serviceType} || "";
663 my $authURI = $a{authURI} || "";
664 my $email = $a{contactEmail} || "";
665 my $URL = $a{URL} || "";
666 my $desc = $a{description} || "";
668 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
671 my $signatureURL = $a{signatureURL} || "";
672 my $Category = lc( $a{category} );
676 #____________call RDFagent__________________________________________________
677 if ( $signatureURL ne "" ) {
680 foreach $sign_req ( $name, $type, $authURI, $email, $URL, $desc,
683 if ( $sign_req ne "" ) {
689 # print "call Agent\n";
692 <Category></Category>
693 <serviceName></serviceName>
694 <serviceType></serviceType>
695 <Description></Description>
696 <signatureURL>$signatureURL</signatureURL>
699 <contactEmail></contactEmail>
702 $self->_call( 'default', 'registerService', $message );
703 return ( $self->parseRegXML($return) );
708 #____________________________________________________________________________________________
709 return $self->errorRegXML(
710 "Only 'moby' and 'wsdl' Service Categories are currently allowed - you gave me $Category"
712 unless ( ( $Category eq 'moby' ) || ( $Category eq 'wsdl' ) );
713 return $self->errorRegXML(
714 "All Fields Required: serviceName, serviceType, authURI, contactEmail, URL, description, Category, input, output, secondary"
725 <Category>$Category</Category>
726 <serviceName>$name</serviceName>
727 <serviceType>$type</serviceType>
728 <Description><![CDATA[$desc]]></Description>
729 <signatureURL>$signatureURL</signatureURL>
731 <authURI>$authURI</authURI>
732 <contactEmail>$email</contactEmail>";
734 if ( $Category eq "moby" || $Category eq 'soap' ) {
736 if ( $a{'secondary'} && ( ref( $a{'secondary'} ) eq 'HASH' ) ) {
737 %SEC = %{ $a{secondary} };
739 elsif ( $a{'secondary'} && ( ref( $a{'secondary'} ) ne 'HASH' ) ) {
740 return $self->errorRegXML(
741 "invalid structure of secondary parameters. Expected hashref."
744 my %funkyhash = ( Input => $a{input}, Output => $a{output} );
745 while ( my ( $inout, $param ) = each %funkyhash ) {
746 my $inout_lc = lc($inout);
747 my @ALLARTICLES = @{$param};
748 $message .= "<${inout_lc}Objects><${inout}>\n";
751 # [articleName1,[objType1 => \@namespaces]], # Simple
752 # [articleName2, [[objType2 => \@namespaces]]], # collection of one object type
753 # [articleName3,[[objType3 => \@namespaces],
754 # [objType4 => \@namespaces]]] # collection of multiple object types (THIS IS NOW ILLEGAL!)
756 foreach my $article (@ALLARTICLES) {
757 my ( $articleName, $def ) = @{$article};
760 unless ( ref($def) eq 'ARRAY') { # $def = [objType => \@ns] or $def=[[objType => \@ns]]
761 return $self->errorRegXML("invalid structure of $inout objects, expected SINGLE arrayref for article $articleName as required by the 0.86 API");
764 if ( ( ref $def->[0] ) eq 'ARRAY' ) { # collection $def->[0] = [objType => \@ns]
765 # def= [[objType2 => [ns3, ns4...]], ...]
766 $message .= "<Collection articleName='$articleName'>\n";
767 if (scalar(@{$def->[0]} > 2)){
768 return $self->errorRegXML("invalid structure of $inout objects. Collections may not have more than one Simple content type as per API version 0.86");
770 @objectdefs = @{$def};
771 if (scalar(@objectdefs) > 1){
772 return $self->errorRegXML("invalid structure of $inout objects. Collections may not have more than one Simple content type as per API version 0.86");
774 } else { # Simple $def->[0] = objType
775 # def = [objType1 => [ns1, ns2...]],
776 @objectdefs = ($def);
778 foreach my $objectdef (@objectdefs) {
779 if ( ref( $def->[0] ) eq 'ARRAY' ) {
780 $message .= "<Simple>\n";
783 $message .= "<Simple articleName='$articleName'>\n";
785 my ( $type, $Namespaces ) = @{$objectdef};
787 $message .= "<objectType>$type</objectType>\n";
788 unless ( ref($Namespaces) eq 'ARRAY' ) {
789 return $self->errorRegXML(
790 "invalid structure of $inout namespaces for object $type in article $articleName; expected arrayref"
793 foreach my $ns ( @{$Namespaces} ) {
794 $message .= "<Namespace>$ns</Namespace>\n";
796 $message .= "</Simple>\n";
798 if ( ref( $def->[0] ) eq 'ARRAY' ) {
799 $message .= "</Collection>\n";
802 $message .= "</${inout}></${inout_lc}Objects>\n";
805 # secondary => {parametername1 => {datatype => TYPE,
806 # default => DEFAULT,
809 # enum => [one, two]},
810 # parametername2 => {datatype => TYPE,
811 # default => DEFAULT,
814 # enum => [one, two]}
817 $message .= "<secondaryArticles>\n";
818 while ( my ( $param, $desc ) = each %SEC ) {
819 unless ( ref($desc) eq 'HASH' ) {
820 return $self->errorRegXML( "invalid structure of secondary article $param; expected hashref of limitations"
824 my $default = defined($data{default})?$data{default}:"";
825 my $max = defined($data{max})?$data{max}:"";
826 my $min = defined($data{min})?$data{min}:"";
827 my $datatype = $data{datatype} || "";
828 my $enums = $data{enum} || [];
830 return $self->errorRegXML("a secondaryArticle must contain at least a datatype value in secondary article $param"
833 unless ( $datatype =~ /Integer|Float|String|DateTime/ )
835 return $self->errorRegXML("a secondaryArticle must have a datatype of Integer, Float, String, or DateTime"
838 unless ( ref($enums) eq 'ARRAY' ) {
839 return $self->errorRegXML("invalid structure of enum limits in secondary article $param; expected arrayref"
842 my @enums = @{$enums};
843 $message .= "<Parameter articleName='$param'>\n";
844 $message .= "<default>$default</default>\n";
845 $message .= "<datatype>$datatype</datatype>\n";
846 $message .= "<max>$max</max>\n";
847 $message .= "<min>$min</min>\n";
849 $message .= "<enum>$_</enum>\n";
851 $message .= "</Parameter>\n";
853 $message .= "</secondaryArticles>\n";
854 $message .= "</registerService>";
857 return $self->errorRegXML(
858 "only 'moby' and 'wsdl' service types are allowed to be registered at this time."
862 #elsif ($Category eq "cgi") {
863 # my $IN = $a{input};
866 # <Input><![CDATA[$IN]]></Input>
868 # </registerService>";
871 # </registerService>";
873 #unless ($message =~ /\<\/registerService/){ return MOBY::Registration->new(
875 # error_messsage => "missing parameters or other failure leading to incorrectly formatted XML",
876 # registration_id => "0")};
877 # print STDERR $message;
878 $debug && &_LOG(" message\n\n$message\n\n");
880 # my $return = $self->SOAP_connection->call(registerService => ($message))->paramsall;
881 my ($return) = $self->_call( 'default', 'registerService', $message );
883 # return ( $self->parseRegXML( $return ) );
884 #_______call a new version RDFbuilder (by Eddie Kawas) _________________________________________
885 my $reg = $self->parseRegXML($return);
887 # if ($reg->success == 1){
888 # require LWP::UserAgent;
890 # my $ua = LWP::UserAgent->new;
891 # my $url='http://mobycentral.cbr.nrc.ca:8090/servlets/forms/getSignatureResponse?domain='.$authURI.'&serviceName='.$name;
893 # my $response = $ua->get($url);
894 # my $rdf = $response->content;
900 #_______________________________________________________________________________________________
904 =head2 registerServiceWSDL
906 Usage : Needs documentation
910 sub registerServiceWSDL {
911 my ( $self, %a ) = @_;
912 return $self->errorRegXML(
913 "Function not allowed when querying multiple registries")
914 if $self->multiple_registries;
917 # my $return = $self->SOAP_connection->call(registerServiceWSDL => ($message))->paramsall;
918 my ($return) = $self->_call( 'default', 'registerServiceWSDL', $message );
920 return ( $self->parseRegXML($return) );
923 =head2 deregisterService
925 Usage : $REG = $MOBY->deregisterService(%args)
926 Function : deregister a registered MOBY Service
927 Returns : MOBY::Registration object
928 Args : serviceName => $serviceID, authURI => $authority
933 sub deregisterService {
934 my ( $self, %a ) = @_;
935 return $self->errorRegXML(
936 "Function not allowed when querying multiple registries")
937 if $self->multiple_registries;
938 my $name = $a{'serviceName'};
939 my $auth = $a{'authURI'};
940 ( defined($name) && defined($auth) ) || return (
945 <message><![CDATA[you did not pass a valid service Identifier]]></message>
946 </MOBYRegistration>" )
950 <serviceName>$name</serviceName>
951 <authURI>$auth</authURI>
952 </deregisterService>";
954 # my $return = $self->SOAP_connection->call(deregisterService => ($message))->paramsall;
955 my ($return) = $self->_call( 'default', 'deregisterService', $message );
956 return ( $self->parseRegXML($return) );
961 Usage : ($ServiceInstances, $RegObject) = $MOBY->findService(%args)
962 Function : Find services that match certain search criterion
963 Returns : ON SUCCESS: arrayref of MOBY::Client::ServiceInstance objects, and undef
964 ON FAILURE: undef, and a MOBY::Registration object indicating the reason for failure
966 Registry => which registry do you want to search (optional)
967 serviceName => $serviceName, (optional)
968 serviceType => $serviceType, (optional)
969 authURI => $authURI, (optional)
970 authoritative => 1, (optional)
971 category => "moby" | "cgi" | "soap" (currently only moby supported) (optional)
972 expandObjects => 1, (optional)
973 expandServices => 1, (optional)
974 URL => $URL_TO_SERVICE (optional)
975 keywords => [kw1, kw2, kw3] (optional)
977 [objType1 => [ns1, ns2...]], # Simple
978 [[objType2 => [ns3, ns4...]]], # collection of one object type
979 [[objType3 => [ns3, ns4...]],
980 [objType4 => [ns5, ns6...]]], # collection of multiple object types
982 output =>[ (optional)
983 [objType1 => [ns1, ns2...]], # Simple
984 [[objType2 => [ns3, ns4...]]], # collection of one object type
985 [[objType3 => [ns3, ns4...]],
986 [objType4 => [ns5, ns6...]]], # collection of multiple object types
993 my ( $self, %a ) = @_;
994 my $reg = ( $a{Registry} ) ? $a{Registry} : $self->default_MOBY_servername;
995 my $id = $a{'serviceID'};
996 my $servicename = $a{'serviceName'} || "";
997 my $authoritative = $a{'authoritative'} || 0;
998 my $serviceType = $a{'serviceType'} || "";
999 my $authURI = $a{'authURI'} || "";
1000 my $category = $a{'category'} || "moby";
1001 my $exObj = $a{'expandObjects'} || 0;
1002 my $exServ = $a{'expandServices'} || 0;
1003 my $kw = $a{'keywords'} || [];
1004 ref($kw) eq 'ARRAY' || return (
1007 "invalid structure of keywords. Expected arrayref"
1011 my $message = "<findService>\n";
1012 defined($authoritative)
1013 && ( $message .= "<authoritative>$authoritative</authoritative>\n" );
1014 $category && ( $message .= "<Category>$category</Category>\n" );
1015 $serviceType && ( $message .= "<serviceType>$serviceType</serviceType>\n" );
1016 $servicename && ( $message .= "<serviceName>$servicename</serviceName>\n" );
1017 $authURI && ( $message .= "<authURI>$authURI</authURI>\n" );
1019 && ( $message .= "<expandObjects>$exObj</expandObjects> \n" );
1021 && ( $message .= "<expandServices>$exServ</expandServices>\n" );
1023 if ( scalar(@kw) ) {
1024 $message .= " <keywords>\n";
1025 foreach my $kwd (@kw) {
1026 $message .= "<keyword>$kwd</keyword>\n";
1028 $message .= "</keywords>\n";
1031 #$a{input} = [[]] unless (defined $a{input});
1032 #$a{output} = [[]] unless (defined $a{output});
1033 if ( defined $a{input} && ( ref( $a{input} ) ne 'ARRAY' ) ) {
1037 "invalid structure of input objects, expected arrayref for input"
1041 if ( defined $a{output} && ( ref( $a{output} ) ne 'ARRAY' ) ) {
1045 "invalid structure of output objects, expected arrayref for output"
1050 $funkyhash{Input} = $a{input} if ( defined $a{input} );
1051 $funkyhash{Output} = $a{output} if ( defined $a{output} );
1054 # [objType1 => [ns1, ns2...]], # Simple
1055 # [[objType2 => [ns3, ns4...]]], # collection of one object type
1056 # [[objType3 => [ns3, ns4...]],
1057 # [objType4 => [ns5, ns6...]]], # collection of multiple object types
1059 while ( my ( $inout, $param ) = each %funkyhash ) {
1060 die "no inout parameter from teh funkyhash" unless defined $inout;
1061 die "no param parameter from teh funkyhash" unless defined $param;
1062 die "param parameter should be a listref"
1063 unless ( ref($param) eq 'ARRAY' );
1064 my $inout_lc = lc($inout);
1065 my @PARAM = @{$param};
1066 $message .= "<${inout_lc}Objects><${inout}>\n";
1067 foreach my $param (@PARAM) {
1068 unless ( ref($param) eq 'ARRAY' ) {
1072 "invalid structure of $inout objects, expected arrayref of class and \@namespaces"
1076 my ( $class, $namespaces ) = @{$param};
1077 die "no class part of param " unless defined $class;
1079 #warn "no namespace part of the param" unless defined $namespaces;
1081 if ( ref $class eq 'ARRAY' ) { # collection
1082 $message .= "<Collection>\n";
1083 @objectdefs = $class;
1086 @objectdefs = ($param);
1088 foreach my $objectdef (@objectdefs) {
1089 $message .= "<Simple>\n";
1090 my ( $type, $Namespaces ) = @{$objectdef};
1091 die "type is missing from objectdef " unless $type;
1092 $message .= "<objectType>$type</objectType>\n";
1093 if ( defined($Namespaces)
1094 && ( ref($Namespaces) ne 'ARRAY' ) )
1099 "invalid structure of $inout namespaces for object $type; expected arrayref"
1103 foreach my $ns ( @{$Namespaces} ) {
1105 $message .= "<Namespace>$ns</Namespace>\n";
1107 $message .= "</Simple>\n";
1109 if ( ref($class) eq 'ARRAY' ) {
1110 $message .= "</Collection>\n";
1113 $message .= "</${inout}></${inout_lc}Objects>\n";
1115 $message .= "</findService>\n";
1117 # my $return = $self->SOAP_connection($reg)->call('findService' => ($message))->paramsall;
1118 my ($return) = $self->_call( $reg, 'findService', $message );
1119 return ( $self->_parseServices( $reg, $return ), undef );
1122 =head2 retrieveService
1124 Usage : $WSDL = $MOBY->retrieveService($ServiceInstance)
1125 Function : get the WSDL definition of the service with this name/authority URI
1126 Returns : a WSDL string
1127 Args : The ServiceInstance object for that service (from findService call)
1131 sub retrieveService {
1132 my ( $self, $SI ) = @_;
1133 return undef unless $SI && $SI->isa('MOBY::Client::ServiceInstance');
1134 my $auth = $SI->authority;
1135 my $name = $SI->name;
1136 my $reg = $SI->registry;
1137 return undef unless ( $auth && $name && $self->Connection($reg) );
1140 " . ( $SI->XML ) . "
1141 </retrieveService>";
1143 my ($return) = $self->_call( $reg, 'retrieveService', $message );
1144 my $parser = XML::LibXML->new();
1145 my $doc = $parser->parse_string($return);
1146 my $de = $doc->getDocumentElement;
1147 my @child = $de->childNodes;
1150 $debug && &_LOG( getNodeTypeName($_), "\t", $_->toString, "\n" );
1151 if ( $_->nodeType == TEXT_NODE ) {
1152 $content .= $_->nodeValue; #else try $_->textContent
1155 $content .= $_->toString;
1158 $content =~ s/^\n//gs;
1159 $content =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
1165 =head2 retrieveResourceURLs
1167 Usage : $names = $MOBY->retrieveResourceURLs()
1168 Function : get a hash of the URL's for each of the MOBY ontologies
1169 Returns : hashref to the following hash
1170 $names{Ontology} = [URL1, URL2,...]
1175 sub retrieveResourceURLs {
1176 my ($self, %args) = shift;
1177 my $reg = $args{registry};
1178 $reg = $reg ? $reg : $self->default_MOBY_servername;
1179 return undef unless ( $self->Connection($reg) );
1180 my ($return) = $self->_call( $reg, 'retrieveResourceURLs', "" );
1181 my $parser = XML::LibXML->new();
1182 my $doc = $parser->parse_string($return);
1183 my $root = $doc->getDocumentElement;
1184 my $urls_list = $root->childNodes;
1186 for ( my $x = 1 ; $x <= $urls_list->size() ; $x++ ) {
1187 next unless $urls_list->get_node($x)->nodeType == ELEMENT_NODE;
1188 my $ontology = $urls_list->get_node($x)->getAttributeNode('name')->getValue;
1189 my $url = $urls_list->get_node($x)->getAttributeNode('url')->getValue;
1190 push @{ $urls{$ontology} }, $url
1196 =head2 retrieveServiceNames
1198 Usage : $names = $MOBY->retrieveServiceNames(%args)
1199 Function : get a (redundant) list of all registered service names
1200 (N.B. NOT service types!)
1201 Returns : hashref to the following hash
1202 $names{$AuthURI} = [serviceName_1, serviceName_2, serviceName3...]
1203 Args : registry => $reg_name: name of registry you wish to retrieve from (optional)
1204 as_lsid => $boolean: return service names as their corresponding LSID's (default off)
1208 sub retrieveServiceNames {
1209 my ($self, %args) = @_;
1210 my $reg = $args{registry};
1211 my $aslsid = $args{as_lsid};
1213 $reg = $reg ? $reg : $self->default_MOBY_servername;
1214 return undef unless ( $self->Connection($reg) );
1216 # my $return = $self->SOAP_connection($reg)->call('retrieveServiceNames' => (@_))->paramsall;
1217 my ($return) = $self->_call( $reg, 'retrieveServiceNames', "" );
1218 my $parser = XML::LibXML->new();
1219 my $doc = $parser->parse_string($return);
1220 my $root = $doc->getDocumentElement;
1221 my $names_list = $root->childNodes;
1223 for ( my $x = 1 ; $x <= $names_list->size() ; $x++ ) {
1224 next unless $names_list->get_node($x)->nodeType == ELEMENT_NODE;
1226 $names_list->get_node($x)->getAttributeNode('name')->getValue;
1228 $names_list->get_node($x)->getAttributeNode('authURI')->getValue;
1229 my $lsid = $names_list->get_node($x)->getAttributeNode('lsid');
1231 $lsid = $lsid->getValue;
1236 push @{ $servicenames{$auth} }, $aslsid?$lsid:$name;
1238 return \%servicenames;
1241 =head2 retrieveServiceProviders
1243 Usage : @URIs = $MOBY->retrieveServiceProviders([$reg_name])
1244 Function : get the list of all provider's AuthURI's
1245 Returns : list of service provider URI strings
1246 Args : $reg_name: name of registry you wish to retrieve from (optional)
1250 sub retrieveServiceProviders {
1253 $reg = $reg ? $reg : $self->default_MOBY_servername;
1254 return undef unless ( $self->Connection($reg) );
1256 # my $return = $self->SOAP_connection($reg)->call('retrieveServiceProviders' => (@_))->paramsall;
1257 my ($return) = $self->_call( $reg, 'retrieveServiceProviders', "" );
1258 my $parser = XML::LibXML->new();
1259 my $doc = $parser->parse_string($return);
1260 my $root = $doc->getDocumentElement;
1261 my $providers = $root->childNodes;
1262 my @serviceproviders;
1263 for ( my $x = 1 ; $x <= $providers->size() ; $x++ ) {
1264 next unless $providers->get_node($x)->nodeType == ELEMENT_NODE;
1265 push @serviceproviders,
1266 $providers->get_node($x)->getAttributeNode('name')->getValue;
1268 return @serviceproviders;
1271 =head2 retrieveServiceTypes
1273 Usage : $types = $MOBY->retrieveServiceTypes(%args)
1274 Function : get the list of all registered service types
1275 Returns : hashref of $types{$type} = $definition
1276 Args : registry => $reg_name: name of registry you wish to retrieve from (optional)
1277 as_lsid => $boolean: return the $type as its corresponding LSID (defualt off)
1281 sub retrieveServiceTypes {
1282 my ($self, %args) = shift;
1283 my $reg = $args{registry};
1284 my $as_lsid = $args{as_lsid};
1286 $reg = $reg ? $reg : $self->default_MOBY_servername;
1287 return undef unless ( $self->Connection($reg) );
1289 # my $return = $self->SOAP_connection($reg)->call('retrieveServiceTypes' => (@_))->paramsall;
1290 my ($return) = $self->_call( $reg, 'retrieveServiceTypes', "" );
1291 my $parser = XML::LibXML->new();
1292 my $doc = $parser->parse_string($return);
1293 my $root = $doc->getDocumentElement;
1294 my $types = $root->childNodes;
1296 for ( my $x = 1 ; $x <= $types->size() ; $x++ ) {
1297 next unless $types->get_node($x)->nodeType == ELEMENT_NODE;
1298 my $type = $types->get_node($x)->getAttributeNode('name')->getValue;
1299 my $lsid = $types->get_node($x)->getAttributeNode('lsid');
1301 $lsid = $lsid->getValue;
1307 my $elem ( $types->get_node($x)->getElementsByTagName('Description') )
1309 $desc = $elem->firstChild->toString;
1310 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1314 $desc =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
1315 $servicetypes{$as_lsid?$lsid:$type} = $desc;
1317 return \%servicetypes;
1321 =head2 retrieveServiceTypesFull
1323 Usage : $types = $MOBY->retrieveServiceTypesFull(%args)
1324 Function : get all details of all service types
1325 Returns : hashref of $types{$type} = {definition => "definition",
1326 authURI => "authority.uri.here",
1327 contactEmail => "email@addy.here"}
1328 Args : registry => $reg_name: name of registry you wish to retrieve from (optional)
1329 as_lsid => $boolean: return the $type as its corresponding LSID (defualt off)
1334 sub retrieveServiceTypesFull {
1335 my ($self, %args) = shift;
1336 my $reg = $args{registry};
1337 my $as_lsid = $args{as_lsid};
1339 $reg = $reg ? $reg : $self->default_MOBY_servername;
1340 return undef unless ( $self->Connection($reg) );
1342 # my $return = $self->SOAP_connection($reg)->call('retrieveServiceTypes' => (@_))->paramsall;
1343 my ($return) = $self->_call( $reg, 'retrieveServiceTypes', "" );
1344 my $parser = XML::LibXML->new();
1345 my $doc = $parser->parse_string($return);
1346 my $root = $doc->getDocumentElement;
1347 my $types = $root->childNodes;
1349 for ( my $x = 1 ; $x <= $types->size() ; $x++ ) {
1350 next unless $types->get_node($x)->nodeType == ELEMENT_NODE;
1351 my $type = $types->get_node($x)->getAttributeNode('name')->getValue;
1352 my $lsid = $types->get_node($x)->getAttributeNode('lsid');
1354 $lsid = $lsid->getValue;
1358 my ($desc, $auth, $email);
1360 my $elem ( $types->get_node($x)->getElementsByTagName('Description') )
1362 $desc = $elem->firstChild->toString;
1363 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1368 my $elem ( $types->get_node($x)->getElementsByTagName('authURI') )
1370 $auth = $elem->firstChild->toString;
1371 if ( $auth =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1376 my $elem ( $types->get_node($x)->getElementsByTagName('contactEmail') )
1378 $email = $elem->firstChild->toString;
1379 if ( $email =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1383 $desc =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs; # somehow these CDATA elements are nested sometimes???
1384 $servicetypes{$as_lsid?$lsid:$type} = {Description => $desc, authURI => $auth, contactEmail => $email};
1386 return \%servicetypes;
1390 =head2 retrieveObjectNames
1392 Usage : $names = $MOBY->retrieveObjectNames(%args)
1393 Function : get the list of all registered Object types
1394 Returns : hashref of hash:
1395 $names{$name} = $definition
1396 Args : registry => $reg_name: name of registry you wish to retrieve from (optional)
1397 as_lsid => $boolean: return $name as its correspnding LSID (optional default off)
1401 sub retrieveObjectNames {
1402 my ($self, %args) = @_;
1403 my $reg = $args{registry};
1404 my $as_lsid = $args{as_lsid};
1405 $reg = $reg ? $reg : $self->default_MOBY_servername;
1406 return undef unless ( $self->Connection($reg) );
1407 my ($return) = $self->_call( $reg, 'retrieveObjectNames', "" );
1408 my $parser = XML::LibXML->new();
1409 my $doc = $parser->parse_string($return);
1410 my $root = $doc->getDocumentElement;
1411 my $obnames = $root->childNodes;
1413 for ( my $x = 1 ; $x <= $obnames->size() ; $x++ ) {
1414 next unless $obnames->get_node($x)->nodeType == ELEMENT_NODE;
1415 my $name = $obnames->get_node($x)->getAttributeNode('name')->getValue;
1416 my $lsid = $obnames->get_node($x)->getAttributeNode('lsid');
1418 $lsid = $lsid->getValue;
1424 $obnames->get_node($x)->getElementsByTagName('Description') )
1426 $desc = $elem->firstChild->toString;
1427 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1431 $desc =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
1432 $objectnames{$as_lsid?$lsid:$name} = $desc;
1434 return \%objectnames;
1438 =head2 retrieveObjectDefinition
1440 Usage : $DEF = $MOBY->retrieveObjectDefinition(objectType => $objectType)
1441 Function : retrieve the $XML that was used to register an object and its relationships
1442 Returns : hashref, identical to the hash sent during Object registration, plus
1443 an additional XML hash key that contains the actual XML containing
1444 the object definition as sent by MOBY Central (used for a visual
1445 overview, rather than parsing all of the hash keys)
1446 objectType => "the name of the Object"
1447 objectLSID => "urn:lsid:..."
1448 description => "a human-readable description of the object"
1449 contactEmail => "your@email.address"
1450 authURI => "URI of the registrar of this object"
1452 relationshipType1 => [
1454 articleName => ArticleName1,
1457 articleName => ArticleName2,
1460 relationshipType2 => [
1462 articleName => ArticleName3,
1466 XML => <....XML of object registration.../>
1468 Args : objectType => the name or LSID URI for an object
1472 sub retrieveObjectDefinition {
1473 my ( $self, %a ) = @_;
1474 my $id = $a{objectType};
1475 return $self->errorRegXML(
1476 "Function not allowed when querying multiple registries")
1477 if $self->multiple_registries;
1479 return \%def unless $id;
1481 <retrieveObjectDefinition>
1482 <objectType>$id</objectType>
1483 </retrieveObjectDefinition>";
1485 $self->_call( 'default', 'retrieveObjectDefinition', $message );
1486 return \%def unless $return;
1487 my ( $term, $lsid, $desc, $relationships, $email, $authURI ) =
1488 &_ObjectDefinitionPayload($return);
1489 $def{objectType} = $term;
1490 $def{objectLSID} = $lsid;
1491 $def{description} = $desc;
1492 $def{contactEmail} = $email;
1493 $def{authURI} = $authURI;
1494 $def{Relationships} = $relationships;
1495 $def{XML} = $return;
1499 sub _ObjectDefinitionPayload {
1501 my $Parser = XML::LibXML->new();
1502 my $doc = $Parser->parse_string($payload);
1503 my $Object = $doc->getDocumentElement();
1504 my $obj = $Object->nodeName;
1505 return undef unless ( $obj eq 'retrieveObjectDefinition' );
1506 my $term = &_nodeTextContent( $Object, "objectType" );
1507 my $lsid = &_nodeAttributeValue( $Object, "objectType", "lsid");
1508 my $desc = &_nodeCDATAContent( $Object, "Description" );
1509 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1512 my $authURI = &_nodeTextContent( $Object, "authURI" );
1513 my $email = &_nodeTextContent( $Object, "contactEmail" );
1516 my $x = $doc->getElementsByTagName("Relationship");
1517 my $no_relationships = $x->size();
1518 for ( my $n = 1 ; $n <= $no_relationships ; ++$n ) { #get_node starts at one
1519 my $relationshipType =
1520 $x->get_node($n)->getAttributeNode('relationshipType')
1521 ; # may or may not have a name
1522 if ($relationshipType) {
1523 $relationshipType = $relationshipType->getValue();
1527 "FAILED! must include a relationshipType in every relationship\n";
1529 my @child = $x->get_node($n)->childNodes;
1531 next unless $_->nodeType == ELEMENT_NODE;
1533 $_->getAttributeNode('articleName'); # may or may not have a name
1535 $_->getAttributeNode('lsid'); # may or may not have a name
1536 if ($article) { $article = $article->getValue() }
1537 if ($rlsid) { $rlsid = $rlsid->getValue() }
1539 my @child2 = $_->childNodes;
1542 #print getNodeTypeName($_), "\t", $_->toString,"\n";
1543 next unless $_->nodeType == TEXT_NODE;
1544 push @{ $relationships{$relationshipType} },
1545 { object => $_->toString,
1546 articleName => $article,
1551 return ( $term, $lsid, $desc, \%relationships, $email, $authURI );
1556 =head2 retrieveNamespaces
1558 Usage : $ns = $MOBY->retrieveNamespaces(%args)
1559 Function : get the list of all registered Namespace types
1560 Returns : hashref of hash:
1561 $ns{$namespace} = $definition
1562 Args : registry => $reg_name: name of registry you wish to retrieve from (optional)
1563 as_lsid => $boolean: retrieve $namespace as its corresponding LSID (default off)
1567 sub retrieveNamespaces {
1568 my ($self, %args) = shift;
1569 my $reg = $args{registry};
1570 $reg = $reg ? $reg : $self->default_MOBY_servername;
1571 return undef unless ( $self->Connection($reg) );
1572 my $as_lsid = $args{as_lsid};
1574 my ($return) = $self->_call( $reg, 'retrieveNamespaces', "" );
1575 my $parser = XML::LibXML->new();
1576 my $doc = $parser->parse_string($return);
1577 my $root = $doc->getDocumentElement;
1578 my $namesp = $root->childNodes;
1580 for ( my $x = 1 ; $x <= $namesp->size() ; $x++ ) {
1581 next unless $namesp->get_node($x)->nodeType == ELEMENT_NODE;
1582 my $ns = $namesp->get_node($x)->getAttributeNode('name')->getValue;
1583 my $lsid = $namesp->get_node($x)->getAttributeNode('lsid');
1585 $lsid = $lsid->getValue;
1591 $namesp->get_node($x)->getElementsByTagName('Description') )
1593 $desc = $elem->firstChild;
1594 $desc = $desc ? $desc->toString : "";
1596 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1600 # $desc =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
1601 $namespaces{$as_lsid?$lsid:$ns} = $desc;
1603 return \%namespaces;
1606 =head2 retrieveNamespacesFull
1608 Usage : $ns = $MOBY->retrieveNamespaces(%args)
1609 Function : get all details about all namespaces
1610 Returns : hashref of hash:
1611 $ns{$namespace} = {Definition => $definition,
1612 authURI => $authority,
1613 contactEmail => $email}
1614 Args : registry => $reg_name: name of registry you wish to retrieve from (optional)
1615 as_lsid => $boolean: retrieve $namespace as its corresponding LSID (default off)
1619 sub retrieveNamespacesFull {
1620 my ($self, %args) = shift;
1621 my $reg = $args{registry};
1622 $reg = $reg ? $reg : $self->default_MOBY_servername;
1623 return undef unless ( $self->Connection($reg) );
1624 my $as_lsid = $args{as_lsid};
1626 my ($return) = $self->_call( $reg, 'retrieveNamespaces', "" );
1627 my $parser = XML::LibXML->new();
1628 my $doc = $parser->parse_string($return);
1629 my $root = $doc->getDocumentElement;
1630 my $namesp = $root->childNodes;
1632 for ( my $x = 1 ; $x <= $namesp->size() ; $x++ ) {
1633 next unless $namesp->get_node($x)->nodeType == ELEMENT_NODE;
1634 my $ns = $namesp->get_node($x)->getAttributeNode('name')->getValue;
1635 my $lsid = $namesp->get_node($x)->getAttributeNode('lsid');
1637 $lsid = $lsid->getValue;
1641 my ($desc, $auth, $email);
1643 $namesp->get_node($x)->getElementsByTagName('Description') )
1645 $desc = $elem->firstChild;
1646 $desc = $desc ? $desc->toString : "";
1648 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1653 $namesp->get_node($x)->getElementsByTagName('authURI') )
1655 $auth = $elem->firstChild;
1656 $auth = $auth ? $auth->toString : "";
1658 if ( $auth =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1663 $namesp->get_node($x)->getElementsByTagName('contactEmail') )
1665 $email = $elem->firstChild;
1666 $email = $email ? $email->toString : "";
1668 if ( $email =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1672 $namespaces{$as_lsid?$lsid:$ns} = {Description => $desc, authURI => $auth, contactEmail => $email};
1674 return \%namespaces;
1678 =head2 retrieveObject
1680 Usage : $objects = $MOBY->retrieveObjectNames(%args)
1681 Function : get the object xsd
1682 Returns : hashref of hash:
1683 $objects{$name} = $W3C_XML_Schema_string
1684 Args : registry => $reg - name of MOBY Central you want to use (must pass undef otherwise)
1685 objectType => $name - object name (from ontology) or undef to get all objects
1686 as_lsid => $boolean - return $name as its corresponding LSID (default off)
1690 sub retrieveObject {
1691 my ($self, %args) = shift;
1692 my ($reg) = $args{registry};
1693 my $type = $args{objectType};
1694 my $as_lsid = $args{as_lsid};
1697 <objectType>$type</objectType>
1699 $reg = $reg ? $reg : $self->default_MOBY_servername;
1700 return undef unless ( $self->Connection($reg) );
1702 my ($return) = $self->_call( $reg, 'retrieveObject', $message );
1703 my $parser = XML::LibXML->new();
1704 my $doc = $parser->parse_string($return);
1705 my $root = $doc->getDocumentElement;
1706 my $objects = $root->childNodes;
1708 for ( my $x = 1 ; $x <= $objects->size() ; $x++ ) {
1709 next unless $objects->get_node($x)->nodeType == ELEMENT_NODE;
1710 my $name = $objects->get_node($x)->getAttributeNode('name')->getValue;
1711 my $lsid = $objects->get_node($x)->getAttributeNode('lsid');
1713 $lsid = $lsid->getValue;
1718 for my $elem ( $objects->get_node($x)->getElementsByTagName('Schema') )
1720 $desc = $elem->firstChild->nodeValue;
1721 if ( $desc =~ /<!\[CDATA\[((?>[^\]]+))\]\]>/ ) {
1725 $desc =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
1726 $objects{$name} = $desc;
1731 =head2 Relationships
1733 Usage : $def = $MOBY->Relationships(%args)
1734 Function : traverse and return the relationships in the ontology
1735 Returns : hashref of
1737 $hash{'isa'}=[{lsid => $lsid, term => 'termy'},...]
1739 $hash{relationship_type}=[{lsid => $lsid, articleName => 'thingy', term => 'termy'},...]
1740 Args : EITHER serviceType => $term_or_lsid
1741 OR objectType => $term_or_lsid
1742 Relationships => \@relationship_types (optional, 'all' if parameter is missing)
1743 Registry => $registry_name (optional)
1744 expandRelationships => [1/0] (optional)
1749 my ( $self, %args ) = @_;
1750 my $object = $args{'objectType'};
1751 my $service = $args{'serviceType'};
1752 my $expand = $args{'expandRelationships'};
1753 $expand = $args{'expandRelationship'}
1754 unless defined($expand); # be forgiving of typos
1756 @relationships = @{ $args{'Relationships'} }
1757 if ( $args{'Relationships'}
1758 && ( ref( $args{'Relationships'} ) eq 'ARRAY' ) );
1759 push @relationships, 'isa' unless $relationships[0]; # need to have at least one relationship
1760 my $reg = $args{'Registry'};
1763 return {} unless ( $object || $service );
1768 <objectType>$object</objectType>\n";
1769 foreach (@relationships) {
1770 $m .= "<relationshipType>$_</relationshipType>\n";
1772 $m .= "<expandRelationship>1</expandRelationship>\n" if $expand;
1773 $m .= "</Relationships>";
1774 $reg = $reg ? $reg : $self->default_MOBY_servername;
1775 return undef unless ( $self->Connection($reg) );
1777 #$payload = $self->SOAP_connection($reg)->call('Relationships' => ($m))->paramsall;
1778 ($payload) = $self->_call( $reg, 'Relationships', $m );
1783 <serviceType>$service</serviceType>\n";
1784 foreach (@relationships) {
1785 $m .= "<relationshipType>$_</relationshipType>\n";
1787 $m .= "<expandRelationship>1</expandRelationship>\n" if $expand;
1788 $m .= "</Relationships>";
1789 $reg = $reg ? $reg : $self->default_MOBY_servername;
1790 return undef unless ( $self->Connection($reg) );
1792 # $payload = $self->SOAP_connection($reg)->call('Relationships' => ($m))->paramsall;
1793 ($payload) = $self->_call( $reg, 'Relationships', $m );
1795 return &_relationshipsPayload($payload);
1799 sub _relationshipsPayload {
1801 return undef unless $payload;
1804 my $Parser = XML::LibXML->new();
1805 my $doc = $Parser->parse_string($payload);
1806 my $x = $doc->getElementsByTagName("Relationship");
1807 my $no_relationships = $x->size();
1808 for ( my $n = 1 ; $n <= $no_relationships ; ++$n ) {
1809 my $relationshipType = $x->get_node($n)->getAttributeNode('relationshipType'); # may or may not have a name
1810 if ($relationshipType) {
1811 $relationshipType = $relationshipType->getValue();
1813 return "FAILED! must include a relationshipType in every relationship\n";
1815 my @child = $x->get_node($n)->childNodes;
1816 foreach my $child(@child) {
1817 my ($lsid, $article, $term) = ("", "", "");
1818 next unless $child->nodeType == ELEMENT_NODE;
1819 my $lsidattr = $child->getAttributeNode('lsid'); # may or may not have a name
1821 $lsid = $lsidattr->getValue();
1823 my $ARTattr = $child->getAttributeNode('articleName'); # may or may not have a name
1825 $article = $ARTattr->getValue();
1828 $info{lsid} = $lsid;
1829 ($info{articleName} = $article) if $article;
1830 my @child2 = $child->childNodes;
1831 foreach my $child2(@child2) {
1832 next unless $child2->nodeType == TEXT_NODE;
1833 $info{term} = $child2->toString;
1834 push @{ $relationships{$relationshipType} }, \%info;
1838 return \%relationships;
1843 Usage : $def = $MOBY->ISA($class1, $class2)
1844 Function : a pre-canned use of the Relationships function
1845 to quickly get an answer to whether class1 ISA class2
1847 Args : $class1 - an Object ontology term or LSID
1848 $class2 - an Object ontology term or LSID
1853 my ( $self, $class1, $class2 ) = @_;
1855 if ( ( $class1 eq $class2 )
1856 || ( "moby:$class1" eq $class2 )
1857 || ( $class1 eq "moby:$class2" ) );
1858 my $lsid1 = $self->ObjLSID($class1);
1859 my $lsid2 = $self->ObjLSID($class2);
1860 return 0 unless $lsid1 && $lsid2;
1862 unless ( @lsids = $self->ISA_CACHE($lsid1) ) {
1863 my $resp = $self->Relationships(
1864 objectType => $lsid1,
1865 expandRelationship => 1,
1866 Relationships => ['isa']
1868 my $lsids = $resp->{'isa'};
1869 map {push @lsids, $self->ObjLSID($_->{lsid})} @$lsids; # convert to LSID
1870 $self->ISA_CACHE( $lsid1, [@lsids] );
1871 $self->ISA_CACHE( $class1, [@lsids] );
1873 while ( shift @hold ) {
1874 $self->ISA_CACHE( $_, [@hold] );
1875 if ( $_ =~ /^urn:lsid:biomoby.org.\w+\.(\S+)/ ) {
1876 $self->ISA_CACHE( $1, [@lsids] );
1881 return 1 if $_ eq $lsid2;
1888 Usage : ($mobycentral, $mobyobject, $mobyservice, $mobynamespace, $mobyrelationship) = $MOBY->DUMP(['registry'])
1889 Function : DUMP the mysql for the current MOBY Central database
1891 Args : $reg - name of MOBY Central you want to use if not default
1900 $reg = $reg ? $reg : $self->default_MOBY_servername;
1901 return undef unless ( $self->Connection($reg) );
1903 # return $self->SOAP_connection($reg)->call('DUMP')->paramsall;
1904 my ($SQLs) = $self->_call( $reg, 'DUMP_MySQL', "" );
1906 $mobycentral, $mobyobject, $mobyservice,
1907 $mobynamespace, $mobyrelationship
1911 $mobycentral, $mobyobject, $mobyservice,
1912 $mobynamespace, $mobyrelationship
1915 *DUMP_MySQL = \&DUMP;
1916 *DUMP_MySQL = \&DUMP;
1918 sub _parseServices {
1919 my ( $self, $Registry, $XML ) = @_;
1920 my $Parser = XML::LibXML->new();
1921 my $doc = $Parser->parse_string($XML);
1922 my $Object = $doc->getDocumentElement();
1923 my $Services = $Object->getElementsByTagName("Service");
1924 my $num = $Services->size();
1926 for ( my $x = 1 ; $x <= $num ; $x++ ) {
1927 my $Service = $Services->get_node($x);
1928 my $AuthURI = $Service->getAttributeNode('authURI')->getValue;
1929 my $servicename = $Service->getAttributeNode('serviceName')->getValue;
1930 my $lsid = $Service->getAttributeNode('lsid');
1932 $lsid = $lsid->getValue;
1936 my $Type = &_nodeTextContent( $Service, 'serviceType' );
1937 my $authoritative = &_nodeTextContent( $Service, 'authoritative' );
1938 my $contactEmail = &_nodeTextContent( $Service, 'contactEmail' );
1939 my $URL = &_nodeTextContent( $Service, 'URL' );
1941 #my $Output = &_nodeTextContent($Service, 'outputObject');
1942 my $Description = &_nodeCDATAContent( $Service, 'Description' );
1943 $Description =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
1944 my $cat = &_nodeTextContent( $Service, 'Category' );
1947 foreach my $inout ( "Input", "Output" ) {
1949 $Service->getElementsByTagName($inout)
1950 ; # there should only be one, but... who knows what
1951 for my $in ( 1 .. $xPuts->size() ) {
1952 my $current = $xPuts->get_node($in);
1953 foreach my $child ( $current->childNodes )
1954 { # child nodes will be either "Simple" or "Complex" tagnames
1955 next unless $child->nodeType == ELEMENT_NODE;
1957 if ( $child->nodeName eq "Simple" ) {
1959 MOBY::Client::SimpleArticle->new( XML_DOM => $child );
1961 elsif ( $child->nodeName eq "Collection" ) {
1963 MOBY::Client::CollectionArticle->new(
1964 XML_DOM => $child );
1969 if ( $inout eq "Input" ) {
1970 push @INPUTS, $THIS;
1973 push @OUTPUTS, $THIS;
1980 $Service->getElementsByTagName("secondaryArticles")
1981 ; # there should only be one, but... who knows what
1982 for my $in ( 1 .. $secs->size() ) {
1983 my $current = $secs->get_node($in);
1984 foreach my $param ( $current->childNodes )
1985 { # child nodes will be "Parameter" tag names
1987 unless $param->nodeType == ELEMENT_NODE
1988 && $param->nodeName eq "Parameter";
1991 MOBY::Client::SecondaryArticle->new( XML_DOM => $param );
1992 push @SECONDARIES, $THIS;
1995 my $Instance = MOBY::Client::ServiceInstance->new(
1996 authority => $AuthURI,
1997 authoritative => $authoritative,
2000 contactEmail => $contactEmail,
2001 name => $servicename,
2005 output => \@OUTPUTS,
2006 secondary => \@SECONDARIES,
2007 description => $Description,
2008 registry => $Registry,
2009 XML => $Service->toString,
2011 push @Services, $Instance;
2016 # my ($e, $m, $lsid) = $OS->objectExists(term => $_);
2023 my ( $self, $term ) = @_;
2024 return undef unless $term;
2026 if ( $lsid = $self->LSID_CACHE($term) ) {
2030 my $os = MOBY::Client::OntologyServer->new;
2031 my ( $s, $m, $tlsid ) = $os->objectExists( term => $term );
2033 $self->LSID_CACHE( $term, $tlsid ); # link both the term
2034 $self->LSID_CACHE( $tlsid, $tlsid ); # and the lsid to itself
2045 Usage : $lsid = $MOBY->LSID_CACHE($term, $lsid)
2046 Function : get/set LSID from the cache
2047 Returns : lsid as a scalar
2048 Args : the term for which you have/want an lsid,
2049 and optionally the lsid to set.
2054 my ( $self, $term, $lsid ) = @_;
2055 if ( $term && $lsid ) {
2056 $self->{LSID_CACHE}->{$term} = $lsid;
2057 return $self->{LSID_CACHE}->{$term};
2060 return $self->{LSID_CACHE}->{$term};
2069 Usage : @lsids = $MOBY->ISA_CACHE($lsid, \@isas)
2070 Function : get/set the ISA relationships in the cache
2071 Returns : list of ISA relationships. The ISA list
2072 is IN ORDER from, excluding the term itself, to
2073 root Object. Base Object returns an empty list.
2074 Args : The LSID for which you have/want the ISA parentage,
2075 and optionally the parentage listref to set.
2076 Note : WHAT COMES BACK ARE LSIDs!!!
2081 my ( $self, $desiredterm, $isas ) = @_;
2082 my $term = $desiredterm;
2083 return (undef) if $isas && ( ref($isas) ne 'ARRAY');
2084 if ( $term && $isas ) {
2087 my $lsid = $self->ObjLSID($_);
2088 next unless ($lsid =~ /^urn\:lsid/);
2089 push @isalsids, $lsid;
2091 $self->{ISA_CACHE}->{$desiredterm} = [(@isalsids)]; # can't assign a listreference or it will empty itself!
2092 while ( my $term = shift(@isalsids) ) { # traverse down and flatten the list
2093 $self->{ISA_CACHE}->{$term} = [(@isalsids)];
2095 return @{ $self->{ISA_CACHE}->{$desiredterm} };
2097 elsif ( $term && $self->{ISA_CACHE}->{$desiredterm} ) {
2098 return @{ $self->{ISA_CACHE}->{$desiredterm} };
2109 # <success>$success</success>
2110 # <message><![CDATA[$message]]></message>
2111 #</MOBYRegistration>
2112 my ( $self, $xml ) = @_;
2113 my $Parser = XML::LibXML->new();
2116 my $doc = $Parser->parse_string($xml);
2117 my $Object = $doc->getDocumentElement();
2118 my $obj = $Object->nodeName;
2119 return undef unless ( $obj eq 'MOBYRegistration' );
2120 my $id = &_nodeTextContent( $Object, 'id' );
2121 my $success = &_nodeTextContent( $Object, 'success' );
2122 my $message = &_nodeCDATAContent( $Object, 'message' );
2124 #print STDERR "******$message******\n";
2125 my $RDF = &_nodeRawContent( $Object, 'RDF' );
2126 my $reg = MOBY::Client::Registration->new(
2127 success => $success,
2128 message => $message,
2129 registration_id => $id,
2137 my ( $self, $message ) = @_;
2138 my $reg = MOBY::Client::Registration->new(
2140 message => $message,
2141 registration_id => -1,
2146 sub _nodeCDATAContent {
2148 # will get text of **all** child $node from the given $DOM
2149 # regardless of their depth!!
2150 my ( $DOM, $node ) = @_;
2151 my $x = $DOM->getElementsByTagName($node);
2152 unless ( $x->get_node(1) ) { return }
2153 my @child = $x->get_node(1)->childNodes;
2157 #print getNodeTypeName($_), "\t", $_->toString,"\n";
2159 unless ( ( $_->nodeType == TEXT_NODE )
2160 || ( $_->nodeType == CDATA_SECTION_NODE ) );
2161 $content = $_->textContent;
2164 $content =~ s/<!\[CDATA\[((?>[^\]]+))\]\]>/$1/gs;
2168 sub _nodeTextContent {
2170 # will get text of **all** child $node from the given $DOM
2171 # regardless of their depth!!
2172 my ( $DOM, $node ) = @_;
2173 my $x = $DOM->getElementsByTagName($node);
2174 unless ( $x->get_node(1) ) { return }
2175 my @child = $x->get_node(1)->childNodes;
2179 #print getNodeTypeName($_), "\t", $_->toString,"\n";
2181 unless ( ( $_->nodeType == TEXT_NODE )
2182 || ( $_->nodeType == CDATA_SECTION_NODE ) );
2183 $content = $_->textContent;
2188 sub _nodeAttributeValue {
2190 my ( $DOM, $node, $attr ) = @_;
2191 return "" unless $attr;
2192 my $x = $DOM->getElementsByTagName($node);
2193 unless ( $x->get_node(1) ) { return "" }
2194 my $n = $x->get_node(1);
2195 my $nodemap = $n->attributes($attr); # XML::LibXML::NamedNodeMap - the worst documented (i.e. undocumented) piece of code ever written! You have to read the source to figure out the interface...
2196 my $attrnode = $nodemap->getNamedItem($attr);
2197 my $attrval = $attrnode?($attrnode->value):"";
2201 sub _nodeRawContent {
2203 # will get XML of **all** child $node from the given $DOM
2204 # regardless of their depth!!
2205 my ( $DOM, $node ) = @_;
2206 my $x = $DOM->getElementsByTagName($node);
2207 unless ( $x->get_node(1) ) { return }
2208 my @child = $x->get_node(1)->childNodes;
2212 #print getNodeTypeName($_), "\t", $_->toString,"\n";
2213 # next unless $_->nodeType == TEXT_NODE;
2214 $content .= $_->toString;
2219 sub _nodeArrayContent {
2221 # will get array content of all child $node from given $DOM
2222 # regardless of depth!
2223 my ( $DOM, $node ) = @_;
2224 $debug && &_LOG( "_nodeArrayContext received DOM: ",
2225 $DOM->toString, "\nsearching for node $node\n" );
2227 my $x = $DOM->getElementsByTagName($node);
2228 my @child = $x->get_node(1)->childNodes;
2230 next unless $_->nodeType == ELEMENT_NODE;
2231 my @child2 = $_->childNodes;
2234 #print getNodeTypeName($_), "\t", $_->toString,"\n";
2236 unless ( ( $_->nodeType == TEXT_NODE )
2237 || ( $_->nodeType == CDATA_SECTION_NODE ) );
2238 push @result, $_->textContent;
2246 my ( $self, $newval ) = @_;
2247 $AUTOLOAD =~ /.*::(\w+)/;
2249 if ( $self->_accessible( $attr, 'write' ) ) {
2250 *{$AUTOLOAD} = sub {
2251 if ( defined $_[1] ) { $_[0]->{$attr} = $_[1] }
2252 return $_[0]->{$attr};
2253 }; ### end of created subroutine
2254 ### this is called first time only
2255 if ( defined $newval ) {
2256 $self->{$attr} = $newval;
2258 return $self->{$attr};
2260 elsif ( $self->_accessible( $attr, 'read' ) ) {
2261 *{$AUTOLOAD} = sub {
2262 return $_[0]->{$attr};
2263 }; ### end of created subroutine
2264 return $self->{$attr};
2267 # Must have been a mistake then...
2268 croak "No such method: $AUTOLOAD";
2273 return unless $debug;
2274 open LOG, ">>/tmp/CentralLogOut.txt" or die "can't open logfile $!\n";
2275 print LOG join "\n", @_;
2276 print LOG "\n---\n";