package MOBY::service_instance;
use SOAP::Lite;
use strict;
use Carp;
use vars qw($AUTOLOAD @ISA);
use MOBY::central_db_connection;
use MOBY::OntologyServer;
use MOBY::authority;
use MOBY::Config;
use vars qw /$VERSION/;
$VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /: (\d+)\.(\d+)/;
#@ISA = qw(MOBY::central_db_connection); # can't do this yet...
=head1 NAME
MOBY::service_instance - a lightweight connection to the
service_instance table in the database
=head1 SYNOPSIS
use MOBY::service_instance;
my $Instance = MOBY::service_instance->new(
authority => $AUTHORITY,
servicename => 'marksFabulousService',
service_type => $SERVICE_TYPE,
category => 'moby',
url => "http://www.illuminae.com/mobyservice.pl",
contact_email => "markw@illuminae.com",
authoritative => 1,
inputs => \@inputs,
output => \@outputs,
description => 'retrieves random sequences from a database');
print $Instance->service_instance_id;
print $Instance->authority->authority_common_name;
=cut
=head1 DESCRIPTION
representation of the service_instance table. Can write to the database
=head1 AUTHORS
Mark Wilkinson (mwilkinson@mrl.ubc.ca)
=cut
{
# Encapsulated:
# DATA
#___________________________________________________________
#ATTRIBUTES
my %_attr_data = # DEFAULT ACCESSIBILITY
(
service_instance_id => [ undef, 'read/write' ],
category => [ undef, 'read/write' ],
servicename => [ undef, 'read/write' ],
_authority => [ undef, 'read/write' ], # the authority object
service_type => [ undef, 'read/write' ],
service_type_uri => [ undef, 'read/write' ],
authority => [ undef, 'read/write' ],
authority_uri => [ undef, 'read/write' ],
signatureURL => [ undef, 'read/write' ],
url => [ undef, 'read/write' ],
inputs => [ undef, 'read/write' ],
outputs => [ undef, 'read/write' ],
secondaries => [ undef, 'read/write' ],
contact_email => [ undef, 'read/write' ],
authoritative => [ 0, 'read/write' ],
description => [ undef, 'read/write' ],
registry => [ 'MOBY_Central', 'read/write' ],
lsid => [ undef, 'read/write' ],
test => [ 0, 'read/write' ]
, # toggles create or test_existence behaviour
);
#_____________________________________________________________
# METHODS, to operate on encapsulated class data
# Is a specified object attribute accessible in a given mode
sub _accessible {
my ( $self, $attr, $mode ) = @_;
$_attr_data{$attr}[1] =~ /$mode/;
}
# Classwide default value for a specified object attribute
sub _default_for {
my ( $self, $attr ) = @_;
$_attr_data{$attr}[0];
}
# List of names of all specified object attributes
sub _standard_keys {
keys %_attr_data;
}
sub service_name
{ # give them a break if they chose service_name or servicename as the parameter
my ( $self, $val ) = @_;
if ( defined $val ) {
if ( defined $self->{servicename} ) {
return
undef # you are not allowed to change it once it has been set!
} else {
$self->{servicename} = $val;
}
}
return $self->{servicename};
}
sub category {
my ( $self, $val ) = @_;
if ( ( defined $val ) && $self->category ) { return undef }
( defined $val ) && ( $self->{category} = $val );
return $self->{category};
}
sub service_type {
my ( $self, $val ) = @_;
if ( defined $val && $self->service_type ) { return undef }
( defined $val ) && ( $self->{service_type} = $val );
return $self->{service_type};
}
sub url {
my ( $self, $val ) = @_;
if ( defined $val && $self->url ) { return undef }
( defined $val ) && ( $self->{url} = $val );
return $self->{url};
}
sub signatureURL {
my ( $self, $val ) = @_;
if ( defined $val && $self->signatureURL ) { return undef }
( defined $val ) && ( $self->{signatureURL} = $val );
return $self->{signatureURL};
}
sub contact_email {
my ( $self, $val ) = @_;
if ( defined $val && $self->contact_email ) { return undef }
( defined $val ) && ( $self->{contact_email} = $val );
return $self->{contact_email};
}
sub description {
my ( $self, $val ) = @_;
if ( defined $val && $self->description ) { return undef }
( defined $val ) && ( $self->{description} = $val );
return $self->{description};
}
sub dbh {
$CONFIG ||= MOBY::Config->new; # exported by Config.pm
my $adaptor =
$CONFIG->getDataAdaptor( datasource => 'mobycentral' )->dbh;
}
sub adaptor {
$CONFIG ||= MOBY::Config->new; # exported by Config.pm
my $adaptor = $CONFIG->getDataAdaptor( datasource => 'mobycentral' );
}
}
sub new {
my ( $caller, %args ) = @_;
my $caller_is_obj = ref($caller);
return $caller if $caller_is_obj;
my $class = $caller_is_obj || $caller;
my $proxy;
my ($self) = bless {}, $class;
foreach my $attrname ( $self->_standard_keys ) {
if ( exists $args{$attrname} ) {
$self->{$attrname} = $args{$attrname};
} elsif ($caller_is_obj) {
$self->{$attrname} = $caller->{$attrname};
} else {
$self->{$attrname} = $self->_default_for($attrname);
}
}
return undef unless $self->authority_uri;
return undef unless $self->servicename;
if( $self->lsid){
my $l = $self->lsid; # but is LSID valid format?
return undef unless $l =~ m'^[uU][rR][nN]:[lL][sS][iI][dD]:[A-Za-z0-9][\w\(\)\+\,\-\.\=\@\;\$\"\!\*\']*:[A-Za-z0-9][\w\(\)\+\,\-\.\=\@\;\$\"\!\*\']*:[A-Za-z0-9][\w\(\)\+\,\-\.\=\@\;\$\"\!\*\']*:\d\d\d\d-\d\d\-\d\dT\d\d\-\d\d\-\d\d(Z|[\+|-]\d\d\d\d){1,1}$';
}
if ( $self->test ) { return $self->service_instance_exists } # returns boolean
$self->authority( $self->_get_authority() ); # as MOBY::authority object
if ( $self->service_type ) {
my $OE = MOBY::OntologyServer->new( ontology => 'service' );
my ( $success, $message, $servicetypeURI ) =
$OE->serviceExists( term => $self->service_type );
unless (
$success || ( ( $self->service_type =~ /urn:lsid/i ) && !( $self->service_type =~ /urn:lsid:biomoby.org/i ) )
)
{
return undef;
}
( $self->service_type =~ /urn:lsid/ )?
$self->service_type_uri( $self->service_type )
: $self->service_type_uri($servicetypeURI);
}
my $existing_services = $self->adaptor->query_service_instance(servicename => $self->servicename,
authority_uri => $self->authority_uri);
my $existing_service = shift(@$existing_services);
if ($existing_service->{servicename}) { # if service exists, then instantiate it from the database retrieval we just did
$self->servicename( $existing_service->{'servicename'} );
$self->authoritative( $existing_service->{'authoritative'} );
$self->service_instance_id( $existing_service->{'service_instance_id'} );
$self->category( $existing_service->{'category'} );
$self->service_type( $existing_service->{'service_type_uri'} );
$self->url( $existing_service->{'url'} );
$self->contact_email( $existing_service->{'contact_email'} );
$self->description( $existing_service->{'description'} );
$self->authority( $existing_service->{'authURI'} );
$self->signatureURL( $existing_service->{'signatureURL'} );
$self->lsid( $existing_service->{'lsid'} );
$self->{__exists__} = 1; # this service already existed
} elsif (!($existing_service->{servicename}) # if it doesn't exist
&& (defined $self->category) # and you have given me things I need to create it
&& ( defined $self->service_type )
&& ( defined $self->url )
&& ( defined $self->contact_email )
&& ( defined $self->description )
) { # then create it de novo if we have enough information
# create a timestamp for the LSID
my ($sec,$min,$hour,$mday,$month,$year, $wday,$yday,$dst) =gmtime(time);
my $date = sprintf ("%04d-%02d-%02dT%02d-%02d-%02dZ",$year+1900,$month+1,$mday,$hour,$min,$sec);
#create LSID for service and register it in the DB
my $_config ||= MOBY::Config->new;
unless ($self->lsid){
# create an LSID if one wasnt passed in
my $LSID_Auth = $_config->{mobycentral}->{lsid_authority};
my $LSID_NS = $_config->{mobycentral}->{lsid_namespace};
$LSID_Auth ||="biomoby.org";
$LSID_NS ||="serviceinstance";
# TODO - # MOBY Central should validate the format of authority uri and servicename when it starts up, sice we are using them to construct LSID's
my $service_lsid = "urn:lsid:$LSID_Auth:$LSID_NS:"
. $self->authority_uri . ","
. $self->servicename.":"."$date"; # LSID with timestamp
$self->lsid($service_lsid);
}
my $id = $self->adaptor->insert_service_instance(
category => $self->category,
servicename => $self->servicename,
service_type_uri => $self->service_type_uri,
authority_uri => $self->authority_uri,
url => $self->url,
contact_email => $self->contact_email,
authoritative => $self->authoritative,
description => $self->description,
signatureURL => $self->signatureURL,
lsid => $self->lsid
);
return undef unless $id;
$self->service_instance_id($id);
$self->{__exists__} = 1; # this service now exists
} else { # if it doesn't exist, and you havne't given me anyting I need to create it, then bail out
return undef;
}
return $self;
}
sub DELETE_THYSELF {
my ($self) = @_;
my $dbh = $self->dbh;
unless ( $self->{__exists__} ) {
return undef;
}
$CONFIG ||= MOBY::Config->new;
my $adaptor = $CONFIG->getDataAdaptor( datasource => 'mobycentral' );
#********FIX this should really be delete_input and delete_output
# the routines below know too much about the database (e.g. that
# the delete_simple_input routines are broken into two parts - by LSID and
# by collecion ID... BAD BAD BAD
$adaptor->delete_simple_input(service_instance_lsid => $self->lsid);
$adaptor->delete_simple_output(service_instance_lsid => $self->lsid);
my $result = $adaptor->query_collection_input(service_instance_lsid => $self->lsid);
foreach my $row (@$result) {
my $id = $row->{collection_input_id};
$adaptor->delete_simple_input(collection_input_id => $id);
}
$result = $adaptor->query_collection_output(service_instance_lsid => $self->lsid);
foreach my $row (@$result) {
my $id = $row->{collection_output_id};
$adaptor->delete_simple_output(collection_output_id => $id);
}
$adaptor->delete_collection_input(service_instance_lsid => $self->lsid);
$adaptor->delete_collection_output(service_instance_lsid => $self->lsid);
$adaptor->delete_secondary_input(service_instance_lsid => $self->lsid);
$adaptor->delete_service_instance(service_instance_lsid => $self->lsid);
return 1;
}
sub authority_id {
my ($self) = @_;
return $self->authority->authority_id;
}
sub service_instance_exists {
my ($self) = @_;
$CONFIG ||= MOBY::Config->new;
my $adaptor = $CONFIG->getDataAdaptor( datasource => 'mobycentral' );
my $dbh = $self->dbh;
my $authority;
my $result = $adaptor->query_service_existence(authority_uri => $self->authority_uri, servicename => $self->servicename);
return $result
}
sub _get_authority
{ # there's somethign fishy here... the authority.pm object already knows about authority_id and authorty_uri, doens't it?
my ($self) = @_;
my $dbh = $self->dbh;
my $authority;
$CONFIG ||= MOBY::Config->new;
my $adaptor = $CONFIG->getDataAdaptor( datasource => 'mobycentral' );
my $result = $adaptor->query_authority(authority_uri => $self->authority_uri);
#*********FIX we should nver need to know the authority ID in this level of code!
if ( @$result[0]) {
my $row = shift(@$result);
#my $id = $row->{authority_id};
my $name = $row->{authority_common_name};
my $uri = $row->{authority_uri};
my $email = $row->{contact_email};
$authority = MOBY::authority->new(
dbh => $self->dbh,
# authority_id => $id,
authority_uri => $uri,
contact_email => $email,
);
} else {
$authority = MOBY::authority->new(
dbh => $self->dbh,
authority_uri => $self->authority_uri,
contact_email => $self->contact_email,
);
}
return $authority;
}
sub add_simple_input {
my ( $self, %a ) = @_;
# validate here... one day...
my $simple = MOBY::simple_input->new(
object_type_uri => $a{'object_type_uri'},
namespace_type_uris => $a{'namespace_type_uris'},
article_name => $a{'article_name'},
service_instance_id => $self->service_instance_id,
service_instance_lsid => $self->lsid,
collection_input_id => $a{'collection_input_id'}
);
push @{ $self->{inputs} }, $simple;
return $simple->simple_input_id;
}
sub add_simple_output {
my ( $self, %a ) = @_;
# validate here... one day...
my $simple = MOBY::simple_output->new(
object_type_uri => $a{'object_type_uri'},
namespace_type_uris => $a{'namespace_type_uris'},
article_name => $a{'article_name'},
service_instance_id => $self->service_instance_id,
service_instance_lsid => $self->lsid,
collection_output_id => $a{'collection_output_id'}
);
push @{ $self->{outputs} }, $simple;
return $simple->simple_output_id;
}
sub add_collection_input {
my ( $self, %a ) = @_;
# validate here... one day...
my $coll = MOBY::collection_input->new(
article_name => $a{'article_name'},
service_instance_lsid => $self->lsid,
service_instance_id => $self->service_instance_id, );
push @{ $self->{inputs} }, $coll;
return $coll->collection_input_id;
}
sub add_collection_output {
my ( $self, %a ) = @_;
# validate here... one day...
my $coll = MOBY::collection_output->new(
article_name => $a{'article_name'},
service_instance_lsid => $self->lsid,
service_instance_id => $self->service_instance_id, );
push @{ $self->{outputs} }, $coll;
return $coll->collection_output_id;
}
sub add_secondary_input {
my ( $self, %a ) = @_;
# validate here... one day...
my $sec = MOBY::secondary_input->new(
default_value => $a{'default_value'},
maximum_value => $a{'maximum_value'},
minimum_value => $a{'minimum_value'},
enum_value => $a{'enum_value'},
datatype => $a{'datatype'},
article_name => $a{'article_name'},
description => $a{'description'},
service_instance_id => $self->service_instance_id,
service_instance_lsid => $self->lsid,
);
push @{ $self->{inputs} }, $sec;
return $sec->secondary_input_id;
}
sub AUTOLOAD {
no strict "refs";
my ( $self, $newval ) = @_;
$AUTOLOAD =~ /.*::(\w+)/;
my $attr = $1;
if ( $self->_accessible( $attr, 'write' ) ) {
*{$AUTOLOAD} = sub {
if ( defined $_[1] ) { $_[0]->{$attr} = $_[1] }
return $_[0]->{$attr};
}; ### end of created subroutine
### this is called first time only
if ( defined $newval ) {
$self->{$attr} = $newval;
}
return $self->{$attr};
} elsif ( $self->_accessible( $attr, 'read' ) ) {
*{$AUTOLOAD} = sub {
return $_[0]->{$attr};
}; ### end of created subroutine
return $self->{$attr};
}
# Must have been a mistake then...
croak "No such method: $AUTOLOAD";
}
sub DESTROY { }
1;