File Coverage

blib/lib/HPPPM/Demand/Management.pm
Criterion Covered Total %
statement 57 98 58.1
branch 2 20 10.0
condition 1 14 7.1
subroutine 14 20 70.0
pod 6 6 100.0
total 80 158 50.6


line stmt bran cond sub pod time code
1             package HPPPM::Demand::Management;
2              
3 3     3   58376 use strict;
  3         7  
  3         135  
4 3     3   16 use warnings;
  3         5  
  3         98  
5 3     3   16 use Carp;
  3         11  
  3         336  
6 3     3   2017 use Moose;
  3         1327695  
  3         23  
7 3     3   29099 use Template;
  3         56303  
  3         119  
8 3     3   2490 use LWP::UserAgent;
  3         120874  
  3         102  
9 3     3   1910 use Error::TryCatch;
  3         237100  
  3         22  
10 3     3   727816 use POSIX qw(strftime);
  3         16806  
  3         28  
11 3     3   6998 use LWP::Protocol::https;
  3         219400  
  3         122  
12 3     3   1498 use HTTP::Request::Common;
  3         4743  
  3         227  
13 3     3   1377 use namespace::autoclean;
  3         3211  
  3         15  
14 3     3   1618 use English qw(-no_match_vars);
  3         4266  
  3         15  
15              
16             our $VERSION = '0.01';
17              
18             has 'ops_inputs_reqd' => (
19             is => 'ro',
20             isa => 'HashRef',
21             lazy => 1,
22             builder => '_set_ops_inputs_reqd',
23             );
24              
25             has 'ops_inputs' => (
26             is => 'ro',
27             isa => 'HashRef',
28             lazy => 1,
29             builder => '_set_ops_inputs',
30             );
31              
32             has 'operations' => (
33             is => 'rw',
34             isa => 'HashRef',
35             lazy => 1,
36             builder => '_set_operations',
37             );
38              
39             has 'service_url' => (
40             is => 'rw',
41             isa => 'Str',
42             );
43              
44             has 'current_operation' => (
45             is => 'rw',
46             isa => 'Str',
47             );
48              
49             has 'user' => (
50             is => 'rw',
51             isa => 'Str',
52             );
53              
54             has 'password' => (
55             is => 'rw',
56             isa => 'Str',
57             );
58              
59             extends 'HPPPM::ErrorHandler';
60              
61              
62             #Stores the mapping between operation and the mandatory inputs/types.
63             #For e.x. "createRequest" operation needs atleast the "requestType"
64             #type to be present in the input fields.
65              
66             sub _set_ops_inputs_reqd {
67 1     1   3 my $self = shift;
68 1         2 my %ops_inputs_reqd;
69              
70 1         25 %ops_inputs_reqd
71             = (
72             #operations => Mandatory inputs/types
73             createRequest => ["serviceUrl", "requestType", "fields"],
74             addRequestNotes => ["serviceUrl", "requestId", "notes"],
75             executeWFTransitions => ["serviceUrl", "receiver", "transition"],
76             deleteRequests => ["serviceUrl", "requestIds"],
77             getRequests => ["serviceUrl", "requestIds"],
78             setRequestFields => ["serviceUrl", "requestId", "fields"],
79             setRequestRemoteReferenceStatus => ["serviceUrl", "receiver",
80             "source", "status", "fields"],
81             );
82              
83 1         50 return \%ops_inputs_reqd;
84             }
85              
86              
87             #Stores the mapping between operation and inputs/types.
88              
89             sub _set_ops_inputs {
90 0     0   0 my $self = shift;
91 0         0 my %ops_inputs;
92              
93 0         0 %ops_inputs
94             = (
95             createRequest => ["serviceUrl", "requestType", "fields",
96             "URLReferences", "notes"],
97             addRequestNotes => ["serviceUrl", "requestId", "notes"],
98             executeWFTransitions => ["serviceUrl", "receiver", "transition"],
99             deleteRequests => ["serviceUrl", "requestIds"],
100             getRequests => ["serviceUrl", "requestIds"],
101             setRequestFields => ["serviceUrl", "requestId", "fields"],
102             setRequestRemoteReferenceStatus => ["serviceUrl", "receiver",
103             "source", "status", "fields"],
104             );
105              
106 0         0 return \%ops_inputs;
107             }
108              
109              
110             sub get_supported_ops {
111 0     0 1 0 my $self = shift;
112              
113 0         0 return keys %{ $self->ops_inputs };
  0         0  
114             }
115              
116              
117             sub get_current_oper {
118 0     0 1 0 my $self = shift;
119              
120 0         0 return $self->current_operation();
121             }
122              
123              
124             sub get_reqd_inputs {
125 0     0 1 0 my $self = shift;
126 0         0 my $oper = shift;
127              
128 0 0       0 return $self->ops_inputs_reqd->{ $oper } if $oper;
129 0         0 return $self->ops_inputs_reqd();
130             }
131              
132              
133             sub get_inputs {
134 0     0 1 0 my $self = shift;
135 0         0 my $oper = shift;
136              
137 0 0       0 return $self->ops_inputs->{ $oper } if $oper;
138 0         0 return $self->ops_inputs();
139             }
140              
141              
142             sub create_request {
143 1     1 1 4177 my $self = shift;
144 1   33     9 my $inputs = shift || confess "No inputs to construct request passed in!";
145 1         34 my $tt = Template->new( INTERPOLATE => 1);
146 1         33321 my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
147 1         529 my $oper = $self->current_operation();
148 1         4 my $req;
149            
150 1         94 $inputs->{'DATETIME'} = strftime ('%Y-%m-%dT%H:%M:%SZ', gmtime);
151 1         61 $inputs->{'USER'} = $self->user();
152 1         56 $inputs->{'PASSWORD'} = $self->password();
153 1         6 $inputs->{'CURRENT_OPERATION'} = $oper;
154              
155 1         11 $logger->info("Creating request for $oper operation");
156              
157 1         216 try {
158 1 50       12 $tt->process("templates/$oper".'.tt2', $inputs, \$req)
159             || throw new Error::Unhandled -text => $tt->error;
160             }
161 1 0       124 catch Error::Unhandled with {
  0 0       0  
  0 50       0  
  0         0  
162 0         0 $logger->logcroak($tt->error);
163             }
164              
165 1         7 $logger->info("Request created successfully!");
166 1         17 $logger->debug("Request created:\n$req");
167              
168 1         24 return $req;
169             }
170              
171              
172             sub post_request {
173 0     0 1   my $self = shift;
174 0   0       my $url = shift || confess "No WebService url passed in!";
175 0   0       my $req = shift || confess "No request to post passed in!";
176 0   0       my $ct = shift || 'application/xml';
177 0           my $ua = LWP::UserAgent->new();
178 0           my $logger = Log::Log4perl->get_logger( $PROGRAM_NAME );
179 0           my $oper = $self->current_operation();
180 0           my $res;
181              
182 0 0         return 0 if ! $self->check_url_availability( $url );
183              
184 0           $logger->info("About to POST request to $url");
185              
186 0           try {
187 0   0       $res = $ua->request(
188             POST => $url,
189             Content_type => $ct,
190             Content => $req,
191             ) || throw new Error::Unhandled -text => $res->status_line;
192             }
193 0 0         catch Error::Unhandled with {
  0 0          
  0 0          
  0            
194 0           $logger->logcroak( $res->status_line );
195             }
196              
197 0           $logger->info("POSTing successful!");
198 0           $logger->debug("Response received:\n".$res);
199              
200 0           return $res->content;
201             }
202              
203             __PACKAGE__->meta->make_immutable;
204              
205             1; # End of HPPPM::Demand::Management
206              
207             __END__
208              
209              
210             =head1 NAME
211              
212             HPPPM::Demand::Management - Web Service Automation for HPPPM Demand Management
213              
214             =head1 VERSION
215              
216             Version 0.01
217              
218             =head1 SYNOPSIS
219              
220             Command Call:
221              
222             perl bin/hpppm_demand.pl -o createRequest -u user -p password -f data/createRequest.data -c cfg/logging.conf
223              
224             -o or --operation is the webservice operation being performed
225              
226             -u or --user user authorized to perform web service operation
227              
228             -p or --password user's password
229              
230             -f or --fields location of file containing input fields that will be used to create
231             the web service request.Instead of a path this can also be a string
232             containing the input fields.A sample data file for each web service
233             operation has been bundled along with distribution under data dir.
234              
235             -c or --logconfig location to the configuration file that drives logging behavior.
236              
237             -h or --help or -? display help.
238              
239             Typical Usage:
240              
241             $hpppm = HPPPM::Demand::Management->new();
242              
243             $fields = $hpppm->validate_read_cmdargs(@ARGV);
244              
245             $tags = $hpppm->get_inputs($hpppm->get_current_oper());
246              
247             $inputs = FieldParser::parser($fields, $tags);
248              
249             $ret = $hpppm->validate_inputs($inputs);
250              
251             $ret = $hpppm->validate_tokens($inputs->{'fields'})
252             if grep /^fields$/, @{ $tags };
253              
254             $ret = $hpppm->extract($res, ['faultcode', 'faultstring',
255             'exception:detail', 'id', 'return']);
256              
257             =head1 DESCRIPTION
258              
259             A framework that helps automate the Web service interaction offered by
260             HP Project and Portfolio Management(aka - HPPPM).HPPPM is an industry
261             wide tool that is used to standardize, manage and capture the execution
262             of a project and operational activities.For more on HPPPM refer the
263             online documentation at HP.HPPPM offers Web Service operations to
264             various interfacing applications involved in a project to talk to each
265             other.HPPPM offers solutions for various activities of an organization
266             viz - application portfolio, demand, financial and so on.This framework
267             currently supports Demand Management only.
268              
269             The framework is built up on 3 modules that have a designated task to do:
270              
271             field_parser - A Higher Order Perl parser meant to parse the input fields
272             that will be used in creating the Web service request.
273             This module is generic and can be used by others after
274             tweaking as per need.
275              
276             error_handler - Performs command line parsing, validation and error/info
277             extraction.
278              
279             demand_management - Creates the Web Service request and does an HTTP post
280             to the Web service.
281              
282             All the above modules offer utilities/methods/functions to the outside
283             world.The framework is typically meant to run via a wrapper script that
284             uses the utilities offered.A sample wrapper script is bundled along with
285             this distribution under the bin dir.
286              
287             A little knowledge in how HPPPM works is absolutely necessary if you
288             intend to use this framework to automate webservice calling for you.
289             In HPPPM each work item is designated as a request and is similar in
290             concept to a ticket in many ticketing systems.
291             A request in HPPPM is made up of request type, request header type
292             and workflow.The request type and header are made up of request fields,
293             validations, rules, security and statuses.The workflow is the request
294             component that gets activated once the request is submitted.The workflow
295             is made up various sub components that are classified as Executional,
296             Decisional, Conditional and SubWorkflows.The Decisional subcompnents
297             are the trigger points for user action and they in turn trigger the
298             Executional and/or Conditional sub components as governed by the
299             business logic.Please note that all fields have a unique token name
300             through which it is referenced internally and also in the Webservice
301             call.
302              
303             Following are the Web Service Operations that the framework helps you
304             play with:
305              
306             addRequestNotes - Add notes to an existing PPM request.
307              
308             createRequest - Create a new request in PPM.
309              
310             deleteRequest - Delete PPM requests.
311              
312             executeWFTransitions - Move workflow and the request as a whole from
313             one Decision step to another.
314              
315             getRequests - Get PPM request fields and their values.
316              
317             setRequestFields - Update fields of an existing PPM request.
318              
319             setRequestRemoteReferenceStatus - Updates the status of a remote
320             reference in a request in PPM.
321              
322             example:
323              
324             Let us assume that application XYZ wants to create a HP PPM request
325             using this framework.XYZ application will need the following(apart
326             from this framework installed and working)
327              
328             username of the user authorized in PPM to do the webservice operation
329              
330             password of the above user in PPM
331              
332             input fields in the format the framework expects
333              
334             A sample input field format:
335              
336             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<requestType>" "ABC" "</requestType>" "<fields>" "REQ.VP.APPLICATION" "COMMON" "REQ.VP.ID" "1102" "REQD.VP.RELATED" "No" "REQ.VP.PRIORITY" "2" "</fields>" "<URLReferences>" "abc" "abc" "abc" "</URLReferences>" "<notes>" "varun" "test by varun" "</notes>"
337              
338             All token names and their values go inside the <fields> tags.If you are
339             setting URLReferences they must atleast have a single field which is the
340             name("abc" above) of the URLReference that will appear in the PPM request.
341             For notes write the authorname first followed by the note.Enclose all tags
342             ,fields and their values in double quotes and separated by spaces.
343              
344             The XYZ application needs to change the input fields as per their requirement
345             and use the command call listed in SYNOPSIS to create a request in the PPM
346             environment enclosed between serviceUrl tag.
347              
348             Following is a listing of supported Web services operations and their
349             mandatory input types:
350              
351             createRequest : serviceUrl, requestType, fields
352              
353             addRequestNotes : serviceUrl, requestId, notes
354              
355             executeWFTransitions : serviceUrl, receiver, transition
356              
357             deleteRequests : serviceUrl, requestIds
358              
359             getRequests : serviceUrl, requestIds
360              
361             setRequestFields : serviceUrl, requestId, fields
362              
363             setRequestRemoteReferenceStatus : serviceUrl, receiver, source, status, fields
364              
365             Following is the sample input for various operations supported by this
366             framework:
367              
368             addRequestNotes:
369             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<requestId>" "30990" "</requestId>" "<notes>" "varun" "test by varun" "</notes>"
370              
371             deleteRequests:
372             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<requestIds>" "31520" "31521" "</requestIds>"
373              
374             executeWFTransitions:
375             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<receiver>" "31490" "</receiver>" "<transition>" "Review Complete" "</transition>"
376              
377             getRequests:
378             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<requestIds>" "30935" "30936" "</requestIds>"
379              
380             setRequestFields:
381             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<requestId>" "31490" "</requestId>" "<fields>" "REQD.VP.ORG" "ABC" "REQD.VP.DETAILED_DESC" "Test by Varun" "</fields>"
382              
383             setRequestRemoteReferenceStatus:
384             "<serviceUrl>" "http://abc.com:8080/ppmservices/DemandService?wsdl" "</serviceUrl>" "<receiver>" "31490" "http://t.com:8090" "</receiver>" "<source>" "31490" "http://t.com:8090" "</source>" "<status>" "Assigned" "</status>" "<fields>" "REQD.VP.ORG" "Another test" "REQD.VP.DETAILED_DESC" "Another test Varun" "</fields>"
385              
386             For reference sake the above sample inputs for various operations are also
387             saved in data dir under base distribution.
388              
389             =head1 INHERITANCE,ATTRIBUTES AND ROLES
390              
391             =head1 METHODS
392              
393             =head2 get_supported_ops
394              
395             Returns supported operations
396              
397             =head2 get_current_oper
398              
399             Returns current operation
400              
401             =head2 get_reqd_inputs
402              
403             Lists mandatory types needed inorder to perform the operation.If operation
404             is not passed or is undef, returns all the operations supported along
405             with the mandatory types for each.
406              
407             for e.g. - for createRequest operation the input fields must have
408             "requestType" and "fields".
409            
410              
411             =head2 get_inputs
412              
413             Lists types needed inorder to perform the operation.If operation
414             is not passed or is undef, returns all the operations supported along
415             with the mandatory types for each.
416              
417             for e.g. - for createRequest operation the input fields(mandatory and optional)
418             have "requestType", "fields", "URLReferences", and "notes".
419              
420             =head2 create_request
421              
422             Creates request from inputs passed using templates
423              
424             =head2 post_request
425              
426             POSTs the request to the url passed in.Checks if the web service url
427             is available before posting the request.
428              
429             =head1 LOGGING & DEBUGGING
430              
431             To enable troubleshooting the framework logs activites in a log file(
432             sample stored under logs dir).The logging is controlled via a config
433             file stored under cfg dir.
434              
435             =head1 IMPORTANT NOTE
436              
437             The framework supports test driven development and has a test suite
438             to help in unit testing.The test suite can be located under the t
439             dir under base dist.Also, before using this framework take a look
440             at the various templates under the templates directory and modify
441             as per need.This framework works for HPPPM 9.14 and is backward
442             compatiable as well.However, if you come across any deviations please
443             feel free to mail me your observations.
444              
445             =head1 AUTHOR
446              
447             Varun Juyal, <varunjuyal123@yahoo.com>
448              
449             =head1 BUGS
450              
451             Please report any bugs or feature requests to C<bug-hpppm-demand-management at rt.cpan.org>, or through
452             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=HPPPM-Demand-Management>. I will be notified, and then you'll
453             automatically be notified of progress on your bug as I make changes.
454              
455             =head1 SUPPORT
456              
457             You can find documentation for this module with the perldoc command.
458              
459             perldoc HPPPM::Demand::Management
460              
461              
462             You can also look for information at:
463              
464             =over 4
465              
466             =item * RT: CPAN's request tracker (report bugs here)
467              
468             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=HPPPM-Demand-Management>
469              
470             =item * AnnoCPAN: Annotated CPAN documentation
471              
472             L<http://annocpan.org/dist/HPPPM-Demand-Management>
473              
474             =item * CPAN Ratings
475              
476             L<http://cpanratings.perl.org/d/HPPPM-Demand-Management>
477              
478             =item * Search CPAN
479              
480             L<http://search.cpan.org/dist/HPPPM-Demand-Management/>
481              
482             =back
483              
484              
485             =head1 ACKNOWLEDGEMENTS
486              
487              
488             =head1 LICENSE AND COPYRIGHT
489              
490             Copyright 2012 Varun Juyal.
491              
492             This program is free software; you can redistribute it and/or modify it
493             under the terms of either: the GNU General Public License as published
494             by the Free Software Foundation; or the Artistic License.
495              
496             See http://dev.perl.org/licenses/ for more information.
497              
498              
499             =cut
500