You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bulk-processor/lib/NGCP/BulkProcessor/RestConnector.pm

660 lines
17 KiB

package NGCP::BulkProcessor::RestConnector;
use strict;
## no critic
use Scalar::Util 'blessed';
use URI;
use LWP::UserAgent qw();
use NGCP::BulkProcessor::Logging qw(
getlogger
restdebug
restinfo);
use NGCP::BulkProcessor::LogError qw(
resterror
restwarn
restrequesterror
restresponseerror
notimplementederror);
use NGCP::BulkProcessor::Utils qw(threadid);
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
_add_headers
convert_bools
);
#my $logger = getlogger(__PACKAGE__);
sub new {
my $class = shift;
my $self = bless {}, $class;
my $instanceid = shift;
$self->{instanceid} = $instanceid;
$self->{tid} = threadid();
$self->{uri} = undef;
$self->{path} = undef;
$self->{netloc} = undef;
$self->{ua} = undef;
$self->{req} = undef;
$self->{res} = undef;
$self->{requestdata} = undef;
$self->{responsedata} = undef;
return $self;
}
sub connectidentifier {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
return undef;
}
sub baseuri {
my $self = shift;
if (@_) {
my $uri = shift;
undef $self->{ua};
undef $self->{uri};
undef $self->{path};
undef $self->{netloc};
if ($uri =~ m!^https?://([^/]+)/?.*$!) {
$self->{netloc} = $1;
$self->{uri} = URI->new($uri);
$self->{path} = $self->{uri}->path();
if (defined $self->{path} and length($self->{path}) > 0) {
$self->{path} .= '/' if $self->{path} !~ m!/$!;
}
$self->{uri}->path_query('');
$self->{uri}->fragment(undef);
restdebug($self,"base URL set to '" . $self->{uri} . "'",getlogger(__PACKAGE__));
} else {
resterror($self,"'" . $uri . "' is not a valid URL",getlogger(__PACKAGE__));
}
}
return (defined $self->{uri} ? $self->{uri}->clone() : undef);
}
sub path {
my $self = shift;
return $self->{path};
}
sub _clearrequestdata {
my $self = shift;
$self->{req} = undef;
$self->{res} = undef;
$self->{requestdata} = undef;
$self->{responsedata} = undef;
}
sub _create_ua {
my $self = shift;
if (!defined $self->{uri}) {
resterror($self,'base URL not set',getlogger(__PACKAGE__));
}
my $ua = LWP::UserAgent->new();
restdebug($self,"ua created",getlogger(__PACKAGE__));
$self->_setup_ua($ua,$self->{netloc});
return $ua;
}
sub _setup_ua {
my $self = shift;
my ($ua,$netloc) = @_;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
return undef;
}
sub _get_ua {
my $self = shift;
if (!defined $self->{ua}) {
$self->{ua} = $self->_create_ua();
}
return $self->{ua};
}
sub _ua_request {
my $self = shift;
my ($req)= @_;
my $res = undef;
eval {
$res = $self->_get_ua()->request($req);
};
if ($@) {
restrequesterror($self,'error executing rest request: ' . $@,$req,$self->{requestdata},getlogger(__PACKAGE__));
}
return $res;
}
sub _add_headers {
my ($req,$headers) = @_;
if (defined $headers) {
foreach my $headername (keys %$headers) {
$req->header($headername => $headers->{$headername});
}
}
}
sub _encode_request_content {
my $self = shift;
my ($data) = @_;
return $data;
}
sub _decode_response_content {
my $self = shift;
my ($data) = @_;
return $data;
}
sub _add_post_headers {
my $self = shift;
my ($req,$headers) = @_;
_add_headers($req,$headers);
}
sub _encode_post_content {
my $self = shift;
my ($data) = @_;
return $self->_encode_request_content($data);
}
sub _decode_post_response {
my $self = shift;
my ($data) = @_;
return $self->_decode_response_content($data);
}
sub _get_request_uri {
my $self = shift;
my ($path_query) = @_;
if (!defined $self->{uri}) {
resterror($self,'base URL not set',getlogger(__PACKAGE__));
}
if (defined $path_query) {
if (blessed($path_query) and $path_query->isa('URI')) {
$path_query = $path_query->path_query();
if (defined $self->{path} and length($self->{path}) > 0) {
$path_query =~ s!^$self->{path}!!;
}
}
} else {
$path_query = '';
}
if (defined $self->{path} and length($self->{path}) > 0) {
#$path_query =~ s!^$self->{path}!!;
$path_query =~ s!^/!!;
$path_query = $self->{path} . $path_query;
}
my $uri = $self->{uri}->clone();
$uri->path_query($path_query);
return $uri;
}
sub _log_request() {
my $self = shift;
my ($req) = @_;
if ($req) {
restdebug($self,$req->method . ' ' . $req->uri,getlogger(__PACKAGE__));
}
}
sub _log_response() {
my $self = shift;
my ($res) = @_;
if ($res) {
restdebug($self,$res->code . ' ' . $res->message,getlogger(__PACKAGE__));
}
}
sub _post {
my $self = shift;
my ($path_query,$data,$headers) = @_;
$self->_clearrequestdata();
$self->{requestdata} = $data;
$self->{req} = HTTP::Request->new('POST',$self->_get_request_uri($path_query));
$self->_add_post_headers($self->{req},$headers);
$self->_log_request($self->{req});
eval {
$self->{req}->content($self->_encode_post_content($data));
};
if ($@) {
restrequesterror($self,'error encoding POST request content: ' . $@,$self->{req},$data,getlogger(__PACKAGE__));
}
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_post_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding POST response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub _post_raw {
my $self = shift;
my ($path_query_request,$data,$headers) = @_;
$self->_clearrequestdata();
$self->{requestdata} = $data;
if (blessed($path_query_request) and $path_query_request->isa('HTTP::Request')) {
$self->{req} = $path_query_request;
$self->_log_request($self->{req});
} else {
$self->{req} = HTTP::Request->new('POST',$self->_get_request_uri($path_query_request));
_add_headers($self->{req},$headers);
$self->_log_request($self->{req});
$self->{req}->content($data);
}
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_post_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding POST response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub post {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _add_get_headers {
my $self = shift;
my ($req,$headers) = @_;
_add_headers($req,$headers);
}
sub _decode_get_response {
my $self = shift;
my ($data) = @_;
return $self->_decode_response_content($data);
}
sub _get {
my $self = shift;
my ($path_query,$headers) = @_;
$self->_clearrequestdata();
$self->{req} = HTTP::Request->new('GET',$self->_get_request_uri($path_query));
$self->_add_get_headers($self->{req},$headers);
$self->_log_request($self->{req});
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_get_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding GET response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub _get_raw {
my $self = shift;
my ($path_query,$headers) = @_;
$self->_clearrequestdata();
$self->{req} = HTTP::Request->new('GET',$self->_get_request_uri($path_query));
_add_headers($self->{req},$headers);
$self->_log_request($self->{req});
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
return $self->{res};
}
sub get {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _add_head_headers {
my $self = shift;
my ($req,$headers) = @_;
_add_headers($req,$headers);
}
sub _decode_head_response {
my $self = shift;
my ($data) = @_;
return $self->_decode_response_content($data);
}
sub _head {
my $self = shift;
my ($path_query,$headers) = @_;
$self->_clearrequestdata();
$self->{req} = HTTP::Request->new('HEAD',$self->_get_request_uri($path_query));
$self->_add_head_headers($self->{req},$headers);
$self->_log_request($self->{req});
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_head_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding HEAD response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub head {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _add_patch_headers {
my $self = shift;
my ($req,$headers) = @_;
_add_headers($req,$headers);
}
sub _encode_patch_content {
my $self = shift;
my ($data) = @_;
return $self->_encode_request_content($data);
}
sub _decode_patch_response {
my $self = shift;
my ($data) = @_;
return $self->_decode_response_content($data);
}
sub _patch {
my $self = shift;
my ($path_query,$data,$headers) = @_;
$self->_clearrequestdata();
$self->{requestdata} = $data;
$self->{req} = HTTP::Request->new('PATCH',$self->_get_request_uri($path_query));
$self->_add_patch_headers($self->{req},$headers);
$self->_log_request($self->{req});
eval {
$self->{req}->content($self->_encode_patch_content($data));
};
if ($@) {
restrequesterror($self,'error encoding PATCH request content: ' . $@,$self->{req},$data,getlogger(__PACKAGE__));
}
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_patch_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding PATCH response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub patch {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _add_put_headers {
my $self = shift;
my ($req,$headers) = @_;
_add_headers($req,$headers);
}
sub _encode_put_content {
my $self = shift;
my ($data) = @_;
return $self->_encode_request_content($data);
}
sub _decode_put_response {
my $self = shift;
my ($data) = @_;
return $self->_decode_response_content($data);
}
sub _put {
my $self = shift;
my ($path_query,$data,$headers) = @_;
$self->_clearrequestdata();
$self->{requestdata} = $data;
$self->{req} = HTTP::Request->new('PUT',$self->_get_request_uri($path_query));
$self->_add_put_headers($self->{req},$headers);
$self->_log_request($self->{req});
eval {
$self->{req}->content($self->_encode_put_content($data));
};
if ($@) {
restrequesterror($self,'error encoding PUT request content: ' . $@,$self->{req},$data,getlogger(__PACKAGE__));
}
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_put_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding PUT response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub put {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _add_delete_headers {
my $self = shift;
my ($req,$headers) = @_;
_add_headers($req,$headers);
}
sub _decode_delete_response {
my $self = shift;
my ($data) = @_;
return $self->_decode_response_content($data);
}
sub _delete {
my $self = shift;
my ($path_query,$headers) = @_;
$self->_clearrequestdata();
$self->{req} = HTTP::Request->new('DELETE',$self->_get_request_uri($path_query));
$self->_add_delete_headers($self->{req},$headers);
$self->_log_request($self->{req});
$self->{res} = $self->_ua_request($self->{req});
$self->_log_response($self->{res});
eval {
$self->{responsedata} = $self->_decode_delete_response($self->{res}->decoded_content());
};
if ($@) {
restresponseerror($self,'error decoding DELETE response content: ' . $@,$self->{res},getlogger(__PACKAGE__));
}
return $self->{res};
}
sub delete {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _get_page_num_query_param {
my $self = shift;
my ($page_num) = @_;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _get_page_size_query_param {
my $self = shift;
my ($page_size) = @_;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _get_total_count_expected_query_param {
my $self = shift;
my ($total_count_expected) = @_;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub _get_sf_query_param {
my $self = shift;
my ($sf) = @_;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub get_collection_page_query_uri {
my $self = shift;
my $collection_path_query = shift;
my $page_size;
my $page_num;
my $total_count_expected;
my $sf;
if (ref $_[0]) {
my $p = shift;
$page_size = $p->{page_size};
$page_num = $p->{page_num};
$total_count_expected = 1;
$sf = shift;
} else {
($page_size,$page_num) = @_;
$total_count_expected = 0;
$sf = undef;
}
#my ($collection_path_query,$page_size,$page_num) = @_;
#if ($page_size <= 0) {
# resterror($self,"positive collection page size required",getlogger(__PACKAGE__));
#}
#if ($page_size < 0) {
# resterror($self,"positive collection page size required",getlogger(__PACKAGE__));
#}
my $page_uri = $self->_get_request_uri($collection_path_query);
my $page_size_query_param = $self->_get_page_size_query_param($page_size);
my $page_num_query_param = $self->_get_page_num_query_param($page_num);
my $total_count_expected_query_param = $self->_get_total_count_expected_query_param($total_count_expected);
my $sf_query_param;
$sf_query_param = $self->_get_sf_query_param($sf) if defined $sf;
my @query_params = ();
push(@query_params,$page_uri->query()) if $page_uri->query();
push(@query_params,$page_size_query_param) if defined $page_size_query_param && length($page_size_query_param) > 0;
push(@query_params,$page_num_query_param) if defined $page_num_query_param && length($page_num_query_param) > 0;
push(@query_params,$total_count_expected_query_param) if defined $total_count_expected_query_param && length($total_count_expected_query_param) > 0;
push(@query_params,$sf_query_param) if defined $sf_query_param && length($sf_query_param) > 0;
$page_uri->query(join('&',@query_params));
return $page_uri;
}
sub extract_collection_items {
my $self = shift;
my ($data,$page_size,$page_num,$params) = @_;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub instanceidentifier {
my $self = shift;
$self->{instanceid} = shift if @_;
return $self->{instanceid};
}
sub request {
my $self = shift;
return $self->{req};
}
sub response {
my $self = shift;
return $self->{res};
}
sub requestdata {
my $self = shift;
$self->{requestdata} = shift if @_;
return $self->{requestdata};
}
sub responsedata {
my $self = shift;
$self->{responsedata} = shift if @_;
return $self->{responsedata};
}
sub get_defaultcollectionpagesize {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub get_firstcollectionpagenum {
my $self = shift;
notimplementederror((ref $self) . ': ' . (caller(0))[3] . ' not implemented',getlogger(__PACKAGE__));
}
sub convert_bools {
my %unrecognized;
local *_convert_bools = sub {
my $ref_type = ref($_[0]);
if (!$ref_type) {
# Nothing.
}
elsif ($ref_type eq 'HASH') {
_convert_bools($_) for values(%{ $_[0] });
}
elsif ($ref_type eq 'ARRAY') {
_convert_bools($_) for @{ $_[0] };
}
elsif (
$ref_type eq 'JSON::PP::Boolean' # JSON::PP
|| $ref_type eq 'Types::Serialiser::Boolean' # JSON::XS
) {
$_[0] = $_[0] ? 1 : 0;
}
else {
++$unrecognized{$ref_type};
}
};
&_convert_bools;
carp("Encountered an object of unrecognized type $_")
for sort values(%unrecognized);
}
1;