#!/usr/bin/perl -w use strict; use lib '/usr/local/apache/cgi-bin/BIO/moby-live/Perl'; use MOBY::Client::Central; use MOBY::Client::Service; use MIME::Base64; use XML::DOM; use Data::Dumper; use CGI qw/:standard/; use vars qw($debug $ERROR_FLAG); $debug = 0; # change to '1' to get debugging messages in /tmp if ($debug) { # refreshes the debugging log open (OUT, ">/tmp/Client05LogOut.txt") || die "cant open logfile\n"; print OUT "Client Initializing\nINC is @INC\n"; close OUT; } if (param('start')) { # user has already started, but needs to turn namespaces and ID's into # objects before presenting the "results" &Begin; &Continue; } elsif (param('continue')) { # user has objects in hand, and has chosen a service for them. # Execute the service and present the results &Execute; &Continue; } elsif (param('reinitialize')) { &Initialize;&Begin;&Continue; } else { &Initialize;&SendOpeningPage } sub Initialize { # set this to wherever your MOBY Central is. At the moment, it is @ # mobycentral.cbr.nrc.ca my $Central = MOBY::Client::Central->new(); my (@ValidNamespaces); my $NameSpaces = $Central->retrieveNamespaces; while (my ($k, $v) = each %{$NameSpaces}) { push @ValidNamespaces, $k."~~~".$v; # name and description } # _LOG("INITIALIZING"); @ValidNamespaces = sort @ValidNamespaces; param('ValidNamespaces', @ValidNamespaces); # _LOG("GOT MOBY CENTRAL DATA @ValidObjects ::: @ValidServices ::: @ValidNamespaces\n"); } sub SendOpeningPage { # send out initialization screen... a bit "flat" at the moment, but we can make it pretty later my ($NameSpaces) = &extractInitializedParams(); # these are the MOBY-Central reported objects, services and namespaces print header, start_html(-title => 'A Simple MOBY Client', -bgcolor => "white"), "
",
h1('MOBY Client Initialization'),"(sample values have been selected for you for demonstration purposes) |
", start_form, "
| OBJECT | CONTENTS |
|---|---|
| "; $response .= checkbox(-name => "CurrentObjects", -value => "$b64Obj", # the actual object, encoded -label => "$name ($obj) : $ns", ); $response .=" | "; my $CRIB = $Object->getElementsByTagName("CrossReference"); # should be only one CRIB per object, so... my $XrefString = ""; if ($CRIB->item(0)){ $XrefString .="Cross References: "; my @XrefsXML; foreach my $child ($CRIB->item(0)->getChildNodes()){ next unless $child->getNodeType == ELEMENT_NODE; my $ns = $child->getAttributeNode("namespace")->getValue(); my $id = $child->getAttributeNode("id")->getValue(); if (($ENV{HTTP_HOST} =~ /localhost/) || ($ENV{HTTP_HOST} =~ /192\.168\.1\./)){ $XrefString .= "$ns : $id, "; } else { $XrefString .= "$ns : $id, "; } } $XrefString .="$XrefString$OBJ |
",
h1('MOBY Service Search')," |
";
if ($ERROR_FLAG){&_sendError("$ERROR_FLAG");$ERROR_FLAG = 0; }
print h3("Chose a service from the list below...\n"),
start_form(-name => "Objects"),
&getAllServices(\@CurrentObjectTypes, \@CurrentNamespaces), # find the valid services for this object/namespace combination
p,"\n",
h3("Select the Objects below that you wish to send to this service
\n"),
p,"\n",
submit("Send Selected Objects to Service")," ",reset," ",
#button(-value=>'All Off', -onClick=>'toggle(form.CurrentObjects);'),
p,
&writeCurrentObjects(@Objects), # allow them to chose which objects to send into this service (checkbox)
p,"\n",
submit("Send Selected Objects to Service")," ",reset," ",
#button(-value=>'All Off', -onClick=>'toggle(form.CurrentObjects);'),
&setInitializedParams, # set the hidden persistence fields
end_form,
end_html;
}
sub extractCurrentObjects {
# objects are passed as base64 encoded, need to decode them back to XML
my @objects = param("CurrentObjects");
&_LOG("CURRENT_OBJECTS__________________\n@objects\n___________________");
return map {decode_base64($_)} @objects;
}
sub extractObjectTypes {
# gets the object names out of the XML
# returns list of object names
my (@Objects) = @_;
my @Types;
foreach (@Objects) {
my $Parser = new XML::DOM::Parser;
my $doc = $Parser->parse($_);
my $Object = $doc->getDocumentElement();
my $object_name = $Object->getTagName;
_LOG("extractObjectTypes: Object was $object_name\n");
my $CRIB = $Object->getElementsByTagName("CrossReference");
$CRIB->item(0) || ($CRIB = $Object->getElementsByTagName("moby:CrossReference"));
# should be only one CRIB per object, so...
if ($CRIB->item(0)){
my @XrefsXML;
my $Xref_list = $CRIB->item(0)->getChildNodes();
foreach (0..$Xref_list->getLength-1){
next unless $Xref_list->item($_)->getNodeType == ELEMENT_NODE;
push @XrefsXML, $Xref_list->item($_)->toString;
}
push @Types, [$object_name, \@XrefsXML];
} else {
push @Types, [$object_name, []];
}
}
return @Types;
}
sub extractNamespaceTypes {
# gets the namespace names out of the XML
# returns list of namespace names
my (@Objects) = @_;
my @namespaces;
foreach (@Objects) {
my $Parser = new XML::DOM::Parser;
my $doc = $Parser->parse($_);
my $Object = $doc->getDocumentElement();
my $ns = $Object->getAttributeNode("namespace");
$ns ||= $Object->getAttributeNode("moby:namespace");
$ns ||="";
if ($ns){_LOG("extractObjectTypes: Namespace was ".$ns->getValue."\n");}
if ($ns){push @namespaces, $ns->getValue;}
else {push @namespaces, undef}
}
return @namespaces;
}
sub getAllServices {
# getAllService that can deal with this type of object in this type
# of namespace. returns HTML - a string to create an *HTML popup
# menu* of valid services!!
my ($objects, $namespace) = @_;
my @objects = @{$objects}; # has the format @([object_type, \@XREF_XML], [...]...)
_LOG("getAllServices: \n\tInitial Object List @objects\n");
my %types;
foreach (@objects){
my ($type, $xrefs) = @{$_};
next unless $type;
$types{$type} = 1;
}
my $response;
my $Central = MOBY::Client::Central->new();
#_LOG("getAllServices: \n\tObjects @types\n\tNamespaces @{$namespace}");
#my @services = $Central->locateServiceByInput(\@types, $namespace);
# I'm not sure why the call commented out above
# used a list ref of types... I'm too tired to think about it.
my %popup_services;
foreach (keys %types){
my ($SI, $Reg) = $Central->findService(input => [[$_, $namespace]], authoritative => 0, expandServices => 1, expandObjects => 1);
if ($Reg){
return "
".($Reg->message).'<\b>
';
}
foreach (@{$SI}) {
my ($URI) = $_->authority;
my ($name) = $_->name;
my ($type) = $_->type;
my $objs = $_->output;
my $output = "(";
foreach my $param(@{$objs}){
if ($param->isSimple){
my $type = (($param->objectType =~ /\:(\S+)$/) && $1);
$type = $param->objectType unless $type;
$output .= "Simple: $type ,";
} else {
$output .= "Collection:[";
foreach my $simp(@{$param->Simples}){
my $type = (($simp->objectType =~ /\:(\S+)$/) && $1);
$type = $simp->objectType unless $type;
$output .= "$type,";
}
chop $output;
$output .="],";
}
}
chop $output;
$output .=") ";
my $desc = $_->description;
$URI ||=""; $name ||=""; $type ||=""; $output ||=""; $desc ||=""; # set default for next print statement or we choke!
$popup_services{"$URI#$name"} = "$type returns $output @"."$URI : $desc";
}
}
$response .= popup_menu(-name => 'SelectedService',
-values => [keys %popup_services],
-labels => \%popup_services,
);
return $response;
}
sub _what_am_i {
my ($ObjectDOM) = @_;
return "TEXT" unless $ObjectDOM;
my $OntologyTerm = $ObjectDOM->getTagName;
_LOG("Found type $OntologyTerm\n");
#my $MC = MOBY::Client::Central->new()
#$relationships = $MC->Relationships(objectType => $OntolgyTerm, Relationships => ["ISA"]);
# this SHOULD be done to traverse the ontology to check whether we have derived Image classes
# but to do this for every object would be painfully slow, so I am
# hard-coding the known image object types for now. THIS IS NOT HOW IT SHOULD BE DONE!!!
return "b64gif" if $OntologyTerm =~ /b64_encoded_gif/;
return "b64jpeg" if $OntologyTerm =~ /b64_encoded_jpeg/;
return "TEXT";
}
sub _sendError{
my ($mess) = @_;
print h1('MOBY Error'),
p,"\n",
"The Client encountered an error.
Message was $mess\n",
p,"\n",
"Below is the current data in-hand. Please make another selection based on the message above