File Coverage

blib/lib/HPPPM/ErrorHandler.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package HPPPM::ErrorHandler;
2              
3 1     1   3201 use strict;
  1         2  
  1         26  
4 1     1   3 use warnings;
  1         1  
  1         16  
5 1     1   167 use Moose;
  0            
  0            
6             use Pod::Usage;
7             use Log::Log4perl;
8             use Data::Dumper;
9             use Getopt::Long;
10             use LWP::UserAgent;
11             use Error::TryCatch;
12             use namespace::autoclean;
13             use English qw( -no_match_vars );
14              
15             our $VERSION = '0.01';
16              
17             has 'input_parsed_xml' => (
18             is => 'rw',
19             isa => 'XML::Simple',
20             );
21              
22             #Checks if the input fields that will be used to construct the SOAP
23             #message have all the reqd. (per operation) types present.Both inputs
24             #fields and the reqd types are mandatory inputs.Returns True if the reqd.
25             #types are present
26              
27             sub _check_reqd_types {
28             my $self = shift;
29             my $fields = shift || confess "No fields to check properties";
30             my $reqd_types = shift || confess "No types to check";
31             my $operation = $self->current_operation();
32             my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
33             my (@present_types, $msg, $present, $reqd);
34              
35             @present_types = grep { exists $fields->{$_} } @{ $reqd_types };
36              
37             return 1 if @present_types == @{ $reqd_types };
38              
39             $reqd = join " ",@{ $reqd_types };
40             $present = join " ",@present_types;
41             $msg = "Properties present donot match the min. no of properties";
42             $msg .= "needed for $operation operation.Properties present:$present";
43             $msg .= " Properties required:$reqd Exiting!";
44              
45             $logger->logconfess($msg);
46             }
47              
48              
49             #Read and return file contents as a single string
50              
51             sub _get_file_content {
52             my $self = shift;
53             my $fname = shift || confess "No filename to read content from";
54             my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
55             my $fields;
56              
57             try {
58             $logger->debug("About to read fields containing req fields");
59              
60             open my $fhandle, "<", $fname
61             || throw new Error::Unhandled -text => $OS_ERROR;
62             local $INPUT_RECORD_SEPARATOR = undef;
63             ($fields = <$fhandle>) =~ s/\\n//g;
64             }
65             catch Error::Unhandled with {
66             print "Unable to read $fname..Exiting! $OS_ERROR";
67             $logger->logcroak("Unable to read $fname $OS_ERROR");
68             }
69              
70             $logger->debug("$fname read! content: $fields");
71            
72             return $fields;
73             }
74              
75              
76             sub validate_read_cmdargs {
77             my $self = shift;
78             my $p = new Getopt::Long::Parser;
79             my ($oper, $fields, $log_cfg, $ret, $logger,
80             $user, $pawd, $help, $oper_exists);
81            
82             $p->getoptions(
83             'operation=s'=> \$oper,
84             'user=s' => \$user,
85             'password=s' => \$pawd,
86             'fields=s' => \$fields,
87             'config=s' => \$log_cfg,
88             'help|?' => \$help,
89             ) || confess pod2usage(-verbose => 2, -noperldoc => 1,
90             -msg => 'Command line options parsing failed!');
91              
92             #validate command line args
93             pod2usage(-verbose => 2, -noperldoc => 1) if $help;
94             confess pod2usage(-verbose => 2, -noperldoc => 1, -msg => 'Insufficient Args!')
95             if ! ($oper || $user || $pawd || $fields || $log_cfg);
96             confess pod2usage(-verbose => 2, -noperldoc => 1, -msg => "$log_cfg missing!")
97             if ! (-f $log_cfg || -s $log_cfg);
98             #Most important, initialize the logger first
99             Log::Log4perl->init($log_cfg);
100             $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
101            
102             $oper_exists = grep { /$oper/ } $self->get_supported_ops();
103             $logger->info("Current operation: $oper") if $oper_exists;
104             $logger->logconfess("Unsupported operation: $oper") if ! $oper_exists;
105            
106             #set current oper, user and password
107             $self->current_operation($oper);
108             $self->user($user);
109             $self->password($pawd);
110            
111             #If $fields points to a file, slurp it
112             $fields = $self->_get_file_content($fields) if( -f $fields and -s $fields );
113              
114             return $fields;
115             }
116              
117              
118             sub validate_inputs {
119             my $self = shift;
120             my $fields = shift || confess "No args to validate";
121             my $ignore_types = shift;
122             my $operation = $self->current_operation();
123             my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
124             my %ops_inputs_reqd = %{$self->ops_inputs_reqd};
125             my (@reqd_types, $ret, $url);
126              
127             #Lookup & localize reqd types needed perform the op
128             @reqd_types = @{ $ops_inputs_reqd{ $operation } };
129             $ret
130             = $self->_check_reqd_types($fields, \@reqd_types);
131             $logger->debug("Reqd. Types for Current Oper Present!") if $ret;
132            
133             return 1;
134             }
135              
136              
137             sub validate_tokens {
138             my $self = shift;
139             my $fields = shift;
140             my $operation = $self->current_operation();
141             my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
142             my %ops_inputs_reqd = %{ $self->ops_inputs_reqd };
143             my (@tokens, $has_tokens, @illegal_tokens, $illegal);
144              
145             $logger->info("No token tag in input fields!")
146             if ! $fields;
147              
148             @tokens = ($fields =~ /\b((?:REQD|REQ|UD|T)\.[A-Z\._0-9]+)\b/gc);
149             @illegal_tokens
150             = grep {! /(^(?:REQD|REQ|UD|T)\.?(?:VP|P)?\.[A-Z_0-9]+?)$/} @tokens;
151             if(@illegal_tokens) {
152             $illegal = join " ",@illegal_tokens;
153             $logger->logconfess("Illegal Token names: $illegal Exiting!");
154             }
155              
156             return 1;
157             }
158              
159              
160             sub check_url_availability {
161             my $self = shift;
162             my $service_url = shift || confess "No url to check availability";
163             my $timeout = shift || 60;
164             my $ua = LWP::UserAgent->new('timeout' => $timeout);
165             my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
166             my ($resp, $msg);
167              
168             try {
169             $resp = $ua->get($service_url);
170             throw new Error::Unhandled -text => $resp->status_line
171             if ! $resp->is_success;
172             }
173             catch Error::Unhandled with {
174             $logger->logcroak($resp->status_line);
175             }
176              
177             return 1;
178             }
179              
180              
181             sub extract {
182             my $self = shift;
183             my $resp = shift || confess "No response to extract from";
184             my $to_extract = shift || confess "Nothing to extract";
185             my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
186             my ($xml_parser, $xml_ref, %details, $key, $code, $string, %tag_vals);
187              
188             $logger->debug("Extracting values in tags ". join ' ', @{ $to_extract });
189             #$resp =~ s/^.+(\<?xml.*)$/$1/i if $resp =~ /^.+(\<?xml.*)$/;
190              
191             try {
192             require XML::Simple
193             || throw new Error::Unhandled -text => 'XML::Simple not found';
194              
195             $xml_parser = XML::Simple->new();
196             $xml_ref = $xml_parser->XMLin($resp);
197              
198             $logger->debug("Extracting tag values using the neat XML Parsing");
199              
200             for my $key (keys %{$xml_ref}) {
201             next if $key !~ /\:body$/i;
202              
203             %details = %{$xml_ref->{$key}};
204             #if ( $key =~ /\:fault$/i ) {
205             # $tag_vals{$_} ||= $details{$_} for @{ $to_extract };
206             #}
207             #($key) = keys %details;
208              
209             $tag_vals{$_} = $details{$key}->{$_} for @{ $to_extract };
210             }
211             }
212             catch Error::Unhandled with {
213             $logger->debug("Extraction Failed...");
214             }
215              
216             if (! %tag_vals ) {
217             $logger->debug("Trying to extract fault with regexp...");
218              
219             for my $tag ( @{ $to_extract } ) {
220             $tag_vals{$tag} = $1
221             if $resp =~ /<$tag>(.+)<\/$tag>/isx;
222             }
223             }
224            
225             $logger->debug("TAGS -> VALUES: ", %tag_vals);
226              
227             return \%tag_vals;
228             }
229              
230             __PACKAGE__->meta->make_immutable;
231              
232             1; # End of HPPPM::ErrorHandler
233              
234             __END__
235              
236             =head1 NAME
237              
238             HPPPM::ErrorHandler - Error Handling Base class for all HPPPM Classes
239              
240             =head1 VERSION
241              
242             Version 0.01
243              
244             =head1 SYNOPSIS
245              
246             Error Handling Base class for all HPPPM Classes.Performs command line parsing,
247             validation of arguments and error extraction.Desginwise, this class is meant to
248             be subclassed and used transparently by HPPPM classes, however it can be
249             instantiated directly.
250              
251             $hpppm = HPPPM::Demand::Management->new();
252              
253             $fields = $hpppm->validate_read_cmdargs(@ARGV);
254             $tags = $hpppm->get_inputs($hpppm->get_current_oper());
255              
256             $inputs = FieldParser::parser($fields, $tags);
257              
258             $ret = $hpppm->validate_inputs($inputs);
259             $ret = $hpppm->validate_tokens($inputs->{'fields'})
260             if grep /^fields$/, @{ $tags };
261              
262              
263             $ret = $hpppm->extract($res, ['faultcode', 'faultstring',
264             'exception:detail', 'id', 'return']);
265              
266              
267             =head1 DESCRIPTION
268              
269             Error Handling Base class for all HPPPM Classes.Performs command line parsing,
270             validation of arguments and error extraction.Desginwise, this class is meant to
271             be subclassed and used transparently by HPPPM classes, however it can be
272             instantiated directly.
273              
274             The class performs validation at various levels:
275              
276             1. Validating the presence of filenames(with data) passed as cmd args.
277              
278             2. Web service operation being performed is legal and supported.
279              
280             3. Before posting Check if the Web Service is up and accessible or not.
281              
282             4. Validate data that will be used to create Web service request(optional).
283              
284             The class also provides in-detail execption extraction.
285              
286              
287             =head1 ATTRIBUTES
288              
289             =head1 METHODS
290              
291             =head2 validate_read_cmdargs
292              
293             perl bin/hpppm_demand.pl -o createRequest -u user -p password -f data/createRequest.data -c cfg/logging.conf
294              
295             -o or --operation is the webservice operation being performed
296             -u or --user user authorized to perform web service operation
297             -p or --password user's password
298             -f or --fields location of file containing input fields that will be used to create
299             the web service request.Instead of a path this can also be a string
300             containing the input fields.A sample data file for each web service
301             operation has been bundled along with distribution under data dir.
302             -c or --logconfig location to the configuration file that drives logging behavior.
303             -h or --help or -? display help.
304              
305             =head2 validate_inputs
306              
307             Checks if the required types need in order to perform
308             the operation successfully are present in the input data or not.
309              
310             =head2 validate_tokens
311              
312             Checks if the operation being performed supports tokens or not. If no
313             tokens are needed the method returns 0.Performs the following checks on
314             tokens as well -All field tokens must be all caps. Token prefixes
315             (REQD, REQ, UD, T, VP, P) must be one of the specified types.All tokens
316             can contain only alphanumeric characters and _ (underscore).Input is
317             input fields and output is Success or Failure
318              
319             =head2 check_url_availability
320              
321             Tests service URL for accessibility.Input is url to test and return
322             Success or Failure
323              
324             =head2 extract
325              
326             Extracts the value(s) which are valid tags in the response received
327             in response to the request posted to the webservice.The value(s)/tag(s)
328             must be passed in as a array ref.The return value is a hash ref with
329             key as the tag and value as its extracted value.
330              
331             =head1 AUTHOR
332              
333             Varun Juyal, <varunjuyal123@yahoo.com>
334              
335             =head1 BUGS
336              
337             Please report any bugs or feature requests to C<bug-hpppm-demand-management at rt.cpan.org>, or through
338             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=HPPPM-Demand-Management>. I will be notified, and then you'll
339             automatically be notified of progress on your bug as I make changes.
340              
341             =head1 SUPPORT
342              
343             You can find documentation for this module with the perldoc command.
344              
345             perldoc HPPPM::ErrorHandler
346              
347              
348             You can also look for information at:
349              
350             =over 4
351              
352             =item * RT: CPAN's request tracker (report bugs here)
353              
354             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=HPPPM-Demand-Management>
355              
356             =item * AnnoCPAN: Annotated CPAN documentation
357              
358             L<http://annocpan.org/dist/HPPPM-Demand-Management>
359              
360             =item * CPAN Ratings
361              
362             L<http://cpanratings.perl.org/d/HPPPM-Demand-Management>
363              
364             =item * Search CPAN
365              
366             L<http://search.cpan.org/dist/HPPPM-Demand-Management/>
367              
368             =back
369              
370              
371             =head1 ACKNOWLEDGEMENTS
372              
373              
374             =head1 LICENSE AND COPYRIGHT
375              
376             Copyright 2012 Varun Juyal.
377              
378             This program is free software; you can redistribute it and/or modify it
379             under the terms of either: the GNU General Public License as published
380             by the Free Software Foundation; or the Artistic License.
381              
382             See http://dev.perl.org/licenses/ for more information.
383              
384              
385             =cut
386