perfSONAR_PS::Datatypes::PingER - this is a pinger message handler object
Index
Code Index:
NAME

perfSONAR_PS::Datatypes::PingER - this is a pinger message handler object
DESCRIPTION

it inherits everything from perfSONAR_PS::Datatypes::Message and only implements request handlers with pinger specifics
SYNOPSIS

use perfSONAR_PS::Datatypes::PingER ;
my ($DOM) = $requestMessage->getElementsByTag('message');
my $message = new perfSONAR_PS::Datatypes::PingER($DOM);
$message = new perfSONAR_PS::Datatypes::PingER({id => '2345',
type = 'SetupdataResponse',
metadata => {'id1' => <obj>},
data=> {'id1' => <obj>}});
####### add data element, namespaces will be added from this object to Message object namespace declaration
$message->addPartById('id1', 'data', new perfSONAR_PS::Datatypes::PingER::data({id=> 'id1', metadataIdRef => 'metaid1' }));
########add metadata element, namespaces will be added from this object to Message object namespace declaration
$message->addPartById('id1', 'metadata', new perfSONAR_PS::Datatypes::PingER::metadata({id=> 'id1' });
my $dom = $message->getDOM(); # get as DOM
print $message->asString(); # print the whole message
METHODS

handle
dispatch method. accepts type of request,response object and MA config hashref as parameters, returns fully built response object,
sets query size limit
method for MetadataKey request, works per event ( single pre-merged md and data pair)
returns filled response message object
############################### From Jason's SNMP MA code ###################################
# MA MetadataKeyRequest Steps
# ---------------------
# Is there a key?
# Y: do queries against key
# return key as md AND d
# N: Is there a chain?
# Y: Is there a key
# Y: do queries against key, add in select stuff to key, return key as md AND d
# N: do md/d queries against md return results with altered key
# N: do md/d queries against md return results
#--------------------------
SetupDataRequest
SetupData request, works per event ( single pre-merged md and data pair)
returns filled response message object
returns filled response
############################### From Jason's SNMP MA code ###################################
# MA SetupdataRequest Steps
# ---------------------
# Is there a key?
# Y: key in db?
# Y: Original MD in db?
# Y: add it, extract data
# N: use sent md, extract data
# N: error out
# N: Is it a select?
# Y: Is there a matching MD?
# Y: Is there a key in the matching md?
# Y: Original MD in db?
# Y: add it, extract data
# N: use sent md, extract data
# N: extract md (for correct md), extract data
# N: Error out
# N: extract md, extract data
#----------------------------------
# Updated from Jason e-mail, 11/27/07
#
# Is there a key?
# Y: key in db?
# Y: chain metadata
# extract data
# N: error out
# N: Is it a select?
# Y: Is there a matching MD?
# Y: Is there a key in the matching md?
# Y: key in db?
# Y: chain metadata
# extract data
# N: error out
# N: chain metadata
# extract data
# N: Error out
# N: chain metadata
# extract data
#
#
AUTHORS

Maxim Grigoriev (FNAL) 2007-2008
use perfSONAR_PS::DB::SQL::PingER;
package perfSONAR_PS::Datatypes::PingER;
{
use strict;
use warnings;
use English qw( -no_match_vars);
use Log::Log4perl qw(get_logger);
use POSIX qw(strftime);
use Data::Dumper;
use Scalar::Util qw(blessed);
use perfSONAR_PS::Datatypes::Namespace;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Key;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data::Key;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data::CommonTime;
use perfSONAR_PS::Datatypes::v2_0::nmwgr::Message::Data::Datum;
use perfSONAR_PS::Datatypes::v2_0::pinger::Message::Parameters;
use perfSONAR_PS::Datatypes::v2_0::pinger::Message::Metadata::Parameters;
use perfSONAR_PS::Datatypes::v2_0::pinger::Message::Metadata::Subject;
use perfSONAR_PS::Datatypes::v2_0::pinger::Message::Data::CommonTime::Datum;
use perfSONAR_PS::Datatypes::v2_0::select::Message::Metadata::Parameters;
use perfSONAR_PS::Datatypes::v2_0::select::Message::Metadata::Subject;
use perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Parameters::Parameter;
use perfSONAR_PS::Datatypes::v2_0::nmwgt::Message::Metadata::Subject::EndPointPair::Dst;
use perfSONAR_PS::Datatypes::v2_0::nmwgt::Message::Metadata::Subject::EndPointPair::Src;
use perfSONAR_PS::Datatypes::v2_0::nmwgt::Message::Metadata::Subject::EndPointPair;
use perfSONAR_PS::Datatypes::NSMap;
use perfSONAR_PS::Datatypes::EventTypes;
use base qw(perfSONAR_PS::Datatypes::Message);
use constant CLASSPATH => 'perfSONAR_PS::Datatypes::PingER';
use constant LOCALNAME => 'message';
#
# internal limit for the number of the data/metadata in the response message
#
our $_sizeLimit = '1000000';
sub handle {
my $self = shift;
my $type = shift;
my $response = shift;
my $maconfig = shift;
my $logger = get_logger( CLASSPATH );
no strict 'refs';
if($self->can($type)) {
$_sizeLimit = $maconfig->{query_size_limit} if $maconfig && ref($maconfig) eq 'HASH' && $maconfig->{query_size_limit};
$logger->debug(" Size limit set to: $_sizeLimit ");
return $type->($self, $response);
} else {
$logger->error(" Handler for $type Not supported");
return undef;
}
use strict;
}
sub MetadataKeyRequest {
my $self = shift;
my $response = shift;
my $logger = get_logger( CLASSPATH );
$logger->debug("MetadataKeyRequest ...");
unless($response && blessed $response && $response->can("getDOM")) {
$logger->error(" Please supply metadata object and not the:" . ref($response));
return " System error, API incomplete";
}
##my $message_params = perfSONAR_PS::Datatypes::v2_0::select::Message::Parameters->new();
##my $message_limit = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Parameters::Parameter->new({name => 'sizeLimit', value => $_sizeLimit});
##$message_params->addParameter($message_limit);
##$response->addParameters($message_params);
#### setting status URI for response
$self->eventTypes->status->operation('metadatakey');
$logger->error(" Please supply array of metadata and not: " . $self->metadata ) unless $self->metadata && ref($self->metadata) eq 'ARRAY';
my $data = $self->data->[0];
my $requestmd = $self->metadata->[0];
my $objects = undef;### iterator returned by backend query
if($requestmd->key && $requestmd->key->id) {
$logger->debug(" Found Key =" . $requestmd->key->id);
$objects = $self->DBO->getMeta([ metaID=> {eq => $requestmd->key->id}], 1);
} elsif(($requestmd->subject) || ($requestmd->parameters)) {
my $query = {query_metaData => []};
$query = $self->buildQuery('eq', $requestmd );
$query = {query_metaData => []} unless $query;
$logger->debug(" Will query = " . Dumper $query);
$objects = $self->DBO->getMeta( $query->{query_metaData}, _mdSetLimit($query->{query_limit}) );
if($EVAL_ERROR) {
$logger->logdie("PingER backend Query failed: " . $EVAL_ERROR);
}
} else {
$logger->warn("Malformed request or missing key or parameters, md=" . $requestmd->id);
$response->addResultResponse({ md => $requestmd, message => 'Malformed request or missing key or parameters', eventType => $self->eventTypes->status->failure});
return;
}
if($objects && ref($objects) eq 'HASH' && %{$objects}) {
foreach my $metaid (keys %{$objects}) {
$logger->debug( "Found metaID " . $metaid );
my $md = $self->_ressurectMd({ md_row => $objects->{$metaid} });
my $md_id = $response->addIDMetadata($md, $self->eventTypes->tools->pinger);
$logger->debug(" MD created: \n " . $md->asString);
my $key = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data::Key->new({id => $metaid });
$logger->debug(" KEY created: \n " . $key->asString );
my $data = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data->new({ id => "data" . $response->dataID, metadataIdRef => "meta$md_id" , key => $key });
$logger->debug(" DATA created: \n " . $data->asString);
$response->addData($data); ##
$logger->debug(" DATA added");
$response->add_dataID;
}
} else {
$response->addResultResponse({ md => $requestmd, message => ' no metadata found ', eventType => $self->eventTypes->status->failure});
}
return 0;
}
sub SetupDataRequest {
my $self = shift;
my $response = shift;
my $logger = get_logger( CLASSPATH );
$logger->debug("SetupdataKeyRequest ...");
unless($response && blessed $response && $response->can("getDOM")) {
$logger->error(" Please supply defined object of metadata and not:" . ref($response));
return "System error, API incomplete";
}
##my $message_params = perfSONAR_PS::Datatypes::v2_0::select::Message::Metadata::Parameters->new();
##my $message_limit = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Parameters::Parameter->new({name => 'sizeLimit', value => $_sizeLimit});
##$message_params->addParameter($message_limit);
##$response->addParameters($message_params);
#### setting status URI for response
$self->eventTypes->status->operation('setupdata');
####
### hashref to hold relation between metaID DB key and meta id
my $metaids = {};
### hashref to contain time selects metadata which will be
### chained to the response metadata with pinger key (to re-use time range selects from request)
my $time_selects = {};
$logger->debug(" Whole message : " . $self->asString);
### single data only ( per event ) set filters array as well
my $data = $self->data->[0];
my $requestmd = $self->metadata->[0];
my @filters = $self->filters?@{$self->filters}:();
unless( $requestmd ) {
$logger->error("Orphaned data - no metadata found for metadataRefid:" . $data->metadataIdRef );
return;
} else {
$logger->debug("Found metadata in request id=" . $requestmd->id . " metadata=" . $requestmd->asString );
}
### objects hashref returned by backend query with metaID as key
my $objects_hashref = {};
# if there is a Key, then get data arrayref
if($requestmd->key && $requestmd->key->id) {
if($self->_retriveDataByKey({md => $requestmd , datas => $objects_hashref, timeselects => $time_selects, metaids => $metaids, response => $response})) {
$response->addResultResponse({md => $requestmd, message => 'no matching data found', eventType => $self->eventTypes->status->failure});
return $response;
}
} elsif($requestmd->subject | $requestmd->parameters) {
my $query = {};
my $md_objects = undef;
eval {
foreach my $supplied_md ( $requestmd, @filters) {
%{$query} = (%{$query} , %{$self->buildQuery('eq', $supplied_md)});
}
$logger->debug(" Will query = " . Dumper $query);
unless($query && $query->{query_metaData} && ref($query->{query_metaData}) eq 'ARRAY' && scalar @{$query->{query_metaData}} >= 1) {
$logger->warn(" Nothing to query about for md=" . $requestmd->id);
$response->addResultResponse({ md => $requestmd, message => 'Nothing to query about(no key or parameters supplied)', eventType => $self->eventTypes->status->failure});
return $response;
}
$md_objects = $self->DBO->getMeta($query->{query_metaData}, _mdSetLimit($query->{query_limit}) );
};
if($EVAL_ERROR) {
$logger->fatal("PingER backend Query failed: " . $EVAL_ERROR);
die " System error, store failed";
}
my $timequery = $self->processTime({timehash => $query->{time}});
if($md_objects && (ref($md_objects) eq 'HASH') && %{$md_objects}) {
foreach my $metaid (sort { $a <=> $b} keys %{$md_objects}) {
my $md = $self->_ressurectMd( { md_row => $md_objects->{$metaid}});
if($self->_retriveDataByKey({key => $metaid, timequery => $timequery, timeselects => $time_selects,
metaids => $metaids, datas => $objects_hashref, response => $response}) ){
$response->addResultResponse({md => $md, message => 'no matching data found', eventType => $self->eventTypes->status->failure});
return $response;
}
}
} else {
$response->addResultResponse({md => $requestmd, message => 'no metadata found', eventType => $self->eventTypes->status->failure});
}
} else {
$response->addResultResponse({md =>$requestmd, message => 'no key and no select in metadata submitted', eventType => $self->eventTypes->status->failure});
}
if($objects_hashref && ref($objects_hashref) eq 'HASH') {
############################################################ here add all those found data elements
foreach my $metaid (keys %{$objects_hashref}) {
if(%{$objects_hashref->{$metaid}}) {
my $data = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data->new({id => "data". $response->dataID, metadataIdRef => "meta" . $metaids->{$metaid}});
foreach my $data_metaid (sort { $a <=> $b} keys %{$objects_hashref->{$metaid}}) {
foreach my $timev (sort { $a <=> $b} keys %{$objects_hashref->{$metaid}->{$data_metaid}}) {
$logger->debug(" What is data row :" . Data::Dumper::Dumper $objects_hashref->{$metaid}->{$data_metaid}->{ $timev });
my $ctime = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Data::CommonTime->new({ type => 'unix', value => $timev});
foreach my $entry (qw/minRtt maxRtt medianRtt meanRtt clp iqrIpd lostPercent maxIpd minIpd meanIpd duplicates outOfOrder/) {
next unless $objects_hashref->{$metaid}->{$data_metaid}->{ $timev }->{$entry};
my $value = $objects_hashref->{$metaid}->{$data_metaid}->{ $timev }->{$entry};
my $datum = perfSONAR_PS::Datatypes::v2_0::pinger::Message::Data::CommonTime::Datum->new({name => $entry , value => $value});
$ctime->addDatum($datum);
}
$data->addCommonTime($ctime);
}
}
$response->addData($data); ##
$response->add_dataID;
}
}
}
return $response;
}
# auxiliary private function
# check if setLimit was requested in the query
# if not then set default
#
sub _mdSetLimit {
my $query = shift;
if($query && ref($query) eq 'ARRAY'
&& $query->[0] && ref($query->[0]) eq 'HASH'
&& $query->[0]->{setLimit} && ref($query->[0]->{setLimit}) eq 'HASH'
&& $query->[0]->{setLimit}->{eq} && $query->[0]->{setLimit}->{eq} >= 1) {
return $query->[0]->{setLimit}->{eq};
}
return $_sizeLimit;
}
#
# auxiliary private function
#
# accepting SQL row or metaID and will create md element for response and return it as object
#
#
sub _ressurectMd {
my ($self, $params) = @_;
my $logger = get_logger( CLASSPATH );
unless($params && ref($params) eq 'HASH' && ($params->{md_row} || $params->{metaID})) {
$logger->error("Parameters missed: md_row or metaID are required parameters");
return ' Parameters missed: md_row , timequery are required parameters';
}
my $md = undef;
if($params->{metaID}) {
eval{
($params->{metaID}, $params->{md_row}) = each %{$self->DBO->getMeta( [ 'metaID' , {'eq' => $params->{metaID}}], 1 )};
};
if($EVAL_ERROR) {
$logger->logdie(" Fatal error while calling Rose::DB object query". $EVAL_ERROR);
}
}
my $metaid = $params->{metaID};
$md = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata->new();
my $key = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Key->new({id => "meta$metaid" });
my $subject = perfSONAR_PS::Datatypes::v2_0::pinger::Message::Metadata::Subject->new({ id => "subj$metaid",
endPointPair => perfSONAR_PS::Datatypes::v2_0::nmwgt::Message::Metadata::Subject::EndPointPair->new({
src => perfSONAR_PS::Datatypes::v2_0::nmwgt::Message::Metadata::Subject::EndPointPair::Src->new({ value => $params->{md_row}->{ip_name_src}, type => 'hostname'}),
dst => perfSONAR_PS::Datatypes::v2_0::nmwgt::Message::Metadata::Subject::EndPointPair::Dst->new({ value => $params->{md_row}->{ip_name_dst}, type => 'hostname'})
})
});
my $pinger_params = perfSONAR_PS::Datatypes::v2_0::pinger::Message::Metadata::Parameters->new({ id => "params$metaid" });
my $param_arrref = [];
no strict 'refs';
foreach my $pparam (qw/count packetSize ttl transport packetInterval protocol/) {
if($params->{md_row}->{$pparam}) {
push @{$param_arrref} , perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Parameters::Parameter->new({name => $pparam , value => $params->{md_row}->{$pparam}});
}
}
use strict;
$md->subject($subject);
if($param_arrref && @{$param_arrref}) {
$pinger_params->parameter($param_arrref);
$md->parameters($pinger_params);
}
$md->key($key);
return $md;
}
# auxiliary private function
#
# _createTimeSelect
#
# creates time range select metadata and store it for reuse in timeselects hashref
#
sub _createTimeSelect {
my ($self, $params) = @_;
my $logger = get_logger( CLASSPATH );
unless($params->{timequery} && (ref($params->{timequery}) eq 'HASH') && $params->{response} && $params->{timeselects} ) {
$logger->error("Parameters missed: timequery, response and timeselects are required parameters");
return ' Parameters missed: timequery, response and timeselects are required parameters';
}
my $id = $params->{timequery}->{eq}?"eq=".$params->{timequery}->{eq}:"lt=".$params->{timequery}->{lt}."_gt=".$params->{timequery}->{gt};
return $params->{timeselects}{$id}{md} if($params->{timeselects}{$id} && $params->{timeselects}{$id}{md});
my $selects = [];
if($params->{timequery}->{eq}) {
push @{$selects} , perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Parameters::Parameter->new({name => 'timeStamp', value => $params->{timequery}->{eq}});
} elsif($params->{timequery}->{gt} && $params->{timequery}->{lt}) {
push @{$selects} , perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Parameters::Parameter->new({name => 'startTime', value => $params->{timequery}->{gt}});
push @{$selects} , perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata::Parameters::Parameter->new({name => 'endTime', value => $params->{timequery}->{lt}});
}
if($selects && @{$selects}) {
my $md = perfSONAR_PS::Datatypes::v2_0::nmwg::Message::Metadata->new();
$md->subject(perfSONAR_PS::Datatypes::v2_0::select::Message::Metadata::Subject->new({id => "subj" . $params->{response}->mdID}));
my $param_selects = perfSONAR_PS::Datatypes::v2_0::select::Message::Metadata::Parameters->new({ id => "params".$params->{response}->mdID, parameter => $selects});
$md->parameters($param_selects);
$logger->debug("--------- Created New time select: ". $md->asString);
$params->{timeselects}{$id}{md} = $params->{response}->addIDMetadata($md, $self->eventTypes->ops->select);
return $params->{timeselects}{$id}{md};
}
return undef;
}
#
# auxiliary private function
#
# this one will find time range from md, find proper list of data tables and will query data tables by metaID key
# parameters - hashref to { md => $metadata_obj, datas => $iterators_attayref, key => $metaKey, timequery => $timequery_hashref, tables => $tables_hashref, response => response}
# return 0 if everything OK, result will be added as data objects arrayref to the {datas} arrayref
# return 1 if something is wrong
#
sub _retriveDataByKey {
my ( $self, $params) = @_;
my $logger = get_logger( CLASSPATH );
unless($params && ref($params) eq 'HASH' && ($params->{key} || ($params->{md} && blessed $params->{md})) &&
$params->{response} && blessed $params->{response} && $params->{metaids} && $params->{datas} && $params->{timeselects}) {
$logger->error("Parameters missed: md,response,iterators,metaids,timeselects are required parameters");
return -1;
}
my $keyid = $params->{key}?$params->{key}:($params->{md} && blessed $params->{md})?$params->{md}->key->id:$logger->(" md or key MUST be provided");
return ' Key parameter missed ' unless $keyid;
$params->{timequery}= $self->processTime( { element => $params->{md} } ) unless $params->{timequery};
unless( $params->{timequery} && ref($params->{timequery} ) eq 'HASH') {
$logger->error("No time range in the query found");
$params->{response}->addResultResponse({ md => $params->{md}, message => 'No time range in the query found' , eventType => $self->eventTypes->status->failure});
return -1;
}
my @timestamp_conditions = map { ('timestamp' => { $_ => $params->{timequery}->{$_} } )} keys %{$params->{timequery}};
my $iterator_local = $self->DBO->getData( [ metaID => {eq => $keyid}, @timestamp_conditions], undef, $_sizeLimit);
if(%{$iterator_local}) {
$params->{datas}->{$keyid} = $iterator_local;
my $idref = $self->_createTimeSelect( $params );
$logger->debug(" Created Time Select ..... ......id=$idref");
my $pinger_md = $self->_ressurectMd({metaID => $keyid});
$pinger_md->metadataIdRef($idref) if $idref;
$params->{metaids}->{$keyid} = $params->{response}->addIDMetadata($pinger_md, $self->eventTypes->tools->pinger);
return 0;
}
return -1;
}
}
1;