File Coverage

blib/lib/HPPPM/ErrorHandler.pm
Criterion Covered Total %
statement 100 160 62.5
branch 11 50 22.0
condition 7 44 15.9
subroutine 16 18 88.8
pod 5 5 100.0
total 139 277 50.1


line stmt bran cond sub pod time code
1             package HPPPM::ErrorHandler;
2              
3 3     3   1939 use strict;
  3         6  
  3         115  
4 3     3   11 use warnings;
  3         5  
  3         78  
5 3     3   11 use Moose;
  3         4  
  3         16  
6 3     3   20914 use Pod::Usage;
  3         1189759  
  3         468  
7 3     3   2825 use Log::Log4perl;
  3         137338  
  3         18  
8 3     3   2202 use Data::Dumper;
  3         15695  
  3         267  
9 3     3   2485 use Getopt::Long;
  3         27056  
  3         18  
10 3     3   594 use LWP::UserAgent;
  3         5  
  3         84  
11 3     3   15 use Error::TryCatch;
  3         7  
  3         32  
12 3     3   720055 use namespace::autoclean;
  3         6  
  3         28  
13 3     3   225 use English qw( -no_match_vars );
  3         4  
  3         66  
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 1     1   2 my $self = shift;
29 1   33     3 my $fields = shift || confess "No fields to check properties";
30 1   33     2 my $reqd_types = shift || confess "No types to check";
31 1         29 my $operation = $self->current_operation();
32 1         4 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
33 1         13 my (@present_types, $msg, $present, $reqd);
34              
35 1         2 @present_types = grep { exists $fields->{$_} } @{ $reqd_types };
  3         6  
  1         2  
36              
37 1 50       2 return 1 if @present_types == @{ $reqd_types };
  1         4  
38              
39 0         0 $reqd = join " ",@{ $reqd_types };
  0         0  
40 0         0 $present = join " ",@present_types;
41 0         0 $msg = "Properties present donot match the min. no of properties";
42 0         0 $msg .= "needed for $operation operation.Properties present:$present";
43 0         0 $msg .= " Properties required:$reqd Exiting!";
44              
45 0         0 $logger->logconfess($msg);
46             }
47              
48              
49             #Read and return file contents as a single string
50              
51             sub _get_file_content {
52 0     0   0 my $self = shift;
53 0   0     0 my $fname = shift || confess "No filename to read content from";
54 0         0 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
55 0         0 my $fields;
56              
57 0         0 try {
58 0         0 $logger->debug("About to read fields containing req fields");
59              
60 0   0     0 open my $fhandle, "<", $fname
61             || throw new Error::Unhandled -text => $OS_ERROR;
62 0         0 local $INPUT_RECORD_SEPARATOR = undef;
63 0         0 ($fields = <$fhandle>) =~ s/\\n//g;
64             }
65 0 0       0 catch Error::Unhandled with {
  0 0       0  
  0 0       0  
  0         0  
66 0         0 print "Unable to read $fname..Exiting! $OS_ERROR";
67 0         0 $logger->logcroak("Unable to read $fname $OS_ERROR");
68             }
69              
70 0         0 $logger->debug("$fname read! content: $fields");
71            
72 0         0 return $fields;
73             }
74              
75              
76             sub validate_read_cmdargs {
77 0     0 1 0 my $self = shift;
78 0         0 my $p = new Getopt::Long::Parser;
79 0         0 my ($oper, $fields, $log_cfg, $ret, $logger,
80             $user, $pawd, $help, $oper_exists);
81            
82 0 0       0 $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 0 0       0 pod2usage(-verbose => 2, -noperldoc => 1) if $help;
94 0 0 0     0 confess pod2usage(-verbose => 2, -noperldoc => 1, -msg => 'Insufficient Args!')
      0        
      0        
      0        
95             if ! ($oper || $user || $pawd || $fields || $log_cfg);
96 0 0 0     0 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 0         0 Log::Log4perl->init($log_cfg);
100 0         0 $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
101            
102 0         0 $oper_exists = grep { /$oper/ } $self->get_supported_ops();
  0         0  
103 0 0       0 $logger->info("Current operation: $oper") if $oper_exists;
104 0 0       0 $logger->logconfess("Unsupported operation: $oper") if ! $oper_exists;
105            
106             #set current oper, user and password
107 0         0 $self->current_operation($oper);
108 0         0 $self->user($user);
109 0         0 $self->password($pawd);
110            
111             #If $fields points to a file, slurp it
112 0 0 0     0 $fields = $self->_get_file_content($fields) if( -f $fields and -s $fields );
113              
114 0         0 return $fields;
115             }
116              
117              
118             sub validate_inputs {
119 1     1 1 2 my $self = shift;
120 1   33     4 my $fields = shift || confess "No args to validate";
121 1         2 my $ignore_types = shift;
122 1         36 my $operation = $self->current_operation();
123 1         4 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
124 1         16 my %ops_inputs_reqd = %{$self->ops_inputs_reqd};
  1         27  
125 1         2 my (@reqd_types, $ret, $url);
126              
127             #Lookup & localize reqd types needed perform the op
128 1         2 @reqd_types = @{ $ops_inputs_reqd{ $operation } };
  1         3  
129 1         7 $ret
130             = $self->_check_reqd_types($fields, \@reqd_types);
131 1 50       4 $logger->debug("Reqd. Types for Current Oper Present!") if $ret;
132            
133 1         102 return 1;
134             }
135              
136              
137             sub validate_tokens {
138 1     1 1 2249 my $self = shift;
139 1         2 my $fields = shift;
140 1         37 my $operation = $self->current_operation();
141 1         9 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
142 1         243 my %ops_inputs_reqd = %{ $self->ops_inputs_reqd };
  1         125  
143 1         2 my (@tokens, $has_tokens, @illegal_tokens, $illegal);
144              
145 1 50       4 $logger->info("No token tag in input fields!")
146             if ! $fields;
147              
148 1         4 @tokens = ($fields =~ /\b((?:REQD|REQ|UD|T)\.[A-Z\._0-9]+)\b/gc);
149             @illegal_tokens
150 1         2 = grep {! /(^(?:REQD|REQ|UD|T)\.?(?:VP|P)?\.[A-Z_0-9]+?)$/} @tokens;
  0         0  
151 1 50       3 if(@illegal_tokens) {
152 0         0 $illegal = join " ",@illegal_tokens;
153 0         0 $logger->logconfess("Illegal Token names: $illegal Exiting!");
154             }
155              
156 1         5 return 1;
157             }
158              
159              
160             sub check_url_availability {
161 1     1 1 2290 my $self = shift;
162 1   33     4 my $service_url = shift || confess "No url to check availability";
163 1   50     5 my $timeout = shift || 60;
164 1         10 my $ua = LWP::UserAgent->new('timeout' => $timeout);
165 1         2098 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
166 1         25 my ($resp, $msg);
167              
168 1         8 try {
169 1         4 $resp = $ua->get($service_url);
170 1 50       184512 throw new Error::Unhandled -text => $resp->status_line
171             if ! $resp->is_success;
172             }
173 1 0       15 catch Error::Unhandled with {
  0 0       0  
  0 50       0  
  0         0  
174 0         0 $logger->logcroak($resp->status_line);
175             }
176              
177 1         51 return 1;
178             }
179              
180              
181             sub extract {
182 1     1 1 2 my $self = shift;
183 1   33     4 my $resp = shift || confess "No response to extract from";
184 1   33     35 my $to_extract = shift || confess "Nothing to extract";
185 1         3 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
186 1         21 my ($xml_parser, $xml_ref, %details, $key, $code, $string, %tag_vals);
187              
188 1         2 $logger->debug("Extracting values in tags ". join ' ', @{ $to_extract });
  1         5  
189             #$resp =~ s/^.+(\<?xml.*)$/$1/i if $resp =~ /^.+(\<?xml.*)$/;
190              
191 1         6 try {
192             require XML::Simple
193 1 0       199 || throw new Error::Unhandled -text => 'XML::Simple not found';
194              
195 0         0 $xml_parser = XML::Simple->new();
196 0         0 $xml_ref = $xml_parser->XMLin($resp);
197              
198 0         0 $logger->debug("Extracting tag values using the neat XML Parsing");
199              
200 0         0 for my $key (keys %{$xml_ref}) {
  0         0  
201 0 0       0 next if $key !~ /\:body$/i;
202              
203 0         0 %details = %{$xml_ref->{$key}};
  0         0  
204             #if ( $key =~ /\:fault$/i ) {
205             # $tag_vals{$_} ||= $details{$_} for @{ $to_extract };
206             #}
207             #($key) = keys %details;
208              
209 0         0 $tag_vals{$_} = $details{$key}->{$_} for @{ $to_extract };
  0         0  
210             }
211             }
212 1 50       4 catch Error::Unhandled with {
  1 50       11  
  1 50       60  
  0         0  
213 1         4 $logger->debug("Extraction Failed...");
214             }
215              
216 1 50       8 if (! %tag_vals ) {
217 1         2 $logger->debug("Trying to extract fault with regexp...");
218              
219 1         4 for my $tag ( @{ $to_extract } ) {
  1         3  
220 2 50       43 $tag_vals{$tag} = $1
221             if $resp =~ /<$tag>(.+)<\/$tag>/isx;
222             }
223             }
224            
225 1         10 $logger->debug("TAGS -> VALUES: ", %tag_vals);
226              
227 1         16 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