# # Copyright (c) 2014 NetApp, Inc., All Rights Reserved. # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # package NACL::ServiceAPI; use strict; use warnings; use NATE v5.3.809; use parent qw(NATE::ServiceAPI); use Params::Validate qw(validate_with BOOLEAN HASHREF OBJECT ARRAYREF SCALAR UNDEF); use Storable qw(nfreeze thaw); sub new { my $class = shift; my %opts = @_; my $autogen = delete($opts{_generate_methods}) // 1; $opts{language} ||= 'perl'; my $lang = $opts{language} = lc($opts{language}); if((!$opts{executable}) && (!$opts{service_class})) { my $service_class = ref($class) || $class; $service_class =~ s/ServiceAPI/Service/; if($lang eq 'python') { $service_class =~ s/\:\:/\./g; $opts{service_class} = $service_class.'.Service'; } elsif($lang eq 'perl') { $opts{service_class} = $service_class } } if(!($opts{type})) { my $type = ref($class) || $class; $type =~ s/ServiceAPI/Service/; $opts{type} = $type; } my $namespace = delete($opts{namespace}) || $opts{type}; my $self = $class->SUPER::new(%opts); #store namespace for custom ServiceAPI methods $self->{_namespace} = $namespace; $autogen && $self->_generate_capabilities(namespace => $namespace); # This will auto-generate the Service's public APIs $self; } #get the namespace used to set up this service sub namespace { my $self = shift; return $self->{_namespace}; } #shortcut to use for custom api methods sub call_server_method { my $self = shift; my %opts = validate_with( params => \@_, spec => { 'method' => { 'type' => SCALAR }, 'namespace' => { 'type' => SCALAR , default => $self->namespace()}, }, 'allow_extra' => 1, ); $self->_core_client_api( _api => $opts{method}, _namespace => $opts{namespace}, @_ ); } sub call_server_method_object { my $self = shift; my %opts = validate_with( params => \@_, spec => { 'method' => { 'type' => SCALAR }, 'namespace' => { 'type' => SCALAR , default => $self->namespace()}, }, 'allow_extra' => 1, ); my $reply = $self->_core_client_api( _api => $opts{method}, _namespace => $opts{namespace}, $self->_freeze_if_can(@_) ); if (ref $reply) { return $self->_thaw_if_can(@{$reply}); } else { return $reply; } } sub _freeze_if_can { my $self = shift; return map { ref $_ ? $self->_freeze($_) : $_ } @_; } sub _thaw_if_can { my $self = shift; return map { Storable::read_magic($_) ? $self->_thaw($_) : $_ } @_; } sub _freeze { my $self = shift; return nfreeze(shift); } sub _thaw { my $self = shift; return thaw(shift); } sub store { my $self = shift; $self->call_server_method_object( method => 'store', @_); } sub retrieve { my $self = shift; my $response = $self->call_server_method_object( method => 'retrieve', request_timeout => -1, #force a response and not an id @_); return $self->_thaw($response); } 1; __END__ =head1 NAME NACL::ServiceAPI - Client Side base class for NACL Services =head1 SYNOPSIS use parent qw(NACL::ServiceAPI); =head1 DESCRIPTION C is used as a base class for talking to all NACL Services. This should not really be used as a standalone class directly. =head1 METHODS =head2 new This is the constructor method that finds the running service(s) and gets prepared to talk to them. =over =item Synopsis use NACL::ServiceAPI::SomeFunctionality; my $api = NACL::ServiceAPI::SomeFunctionality->new(); =back =head2 store EXPERIMENTAL! This will store an arbitrary reference or SOME object types on the service side. Many NACL objects are supported (because it serializes the object using Storable and NACL now generally supports freeze/thaw to serialize objects. Any objects using typeglobs, filehandles, coderefs, etc will fail. In that case, you will have to write your own freeze/thaw methods for those or work around it in some other way. If you want to use store/retrieve you will have to add the methods to your public_api in your service class (not service API!): use constant public_api => ( store => {worker_type => 0}, retrieve => {worker_type => 0}, ); =over =item Synopsis use NACL::ServiceAPI::SomeFunctionality; my $api = NACL::ServiceAPI::SomeFunctionality->new(); $api->store(name => 'volume', value => $volume_object); my $volume = $api->retrieve(name => 'volume'); =back =head2 retrieve EXPERIMENTAL! This will retrieve an arbitrary reference or SOME object types on the service side. Many NACL objects are supported (because it serializes the object using Storable and NACL now generally supports freeze/thaw to serialize objects. Any objects using typeglobs, filehandles, coderefs, etc will fail. In that case, you will have to write your own freeze/thaw methods for those or work around it in some other way. If you want to use store/retrieve you will have to add the methods to your public_api in your service class (not service API!): use constant public_api => ( store => {worker_type => 0}, retrieve => {worker_type => 0}, ); =over =item Synopsis use NACL::ServiceAPI::SomeFunctionality; my $api = NACL::ServiceAPI::SomeFunctionality->new(); $api->store(name => 'volume', value => $volume_object); my $volume = $api->retrieve(name => 'volume'); =back =head1 SEE ALSO This is a derived class of NATE::ServiceAPI. Please see the documentation for more details C : http://web.netapp.com/engineering/nate/releases/last/html/NATE/ServiceAPI.html =head1 AUTHOR/MAINTAINER NACL Development (dl-nacl-dev@netapp.com) =cut