File Coverage

blib/lib/HeliosX/Job/JSON.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package HeliosX::Job::JSON;
2              
3 1     1   15185 use 5.008;
  1         2  
  1         37  
4 1     1   4 use strict;
  1         1  
  1         27  
5 1     1   3 use warnings;
  1         8  
  1         26  
6 1     1   3 use base 'Helios::Job';
  1         1  
  1         487  
7              
8             use JSON::Tiny qw(decode_json);
9             $JSON::Tiny::TRUE = 1;
10             $JSON::Tiny::FALSE = 0;
11              
12             use Helios::Config;
13             use HeliosX::Job::JSON::Error;
14              
15             our $VERSION = '1.00';
16              
17             =head1 NAME
18              
19             HeliosX::Job::JSON - Helios::Job subclass using JSON to specify job arguments
20              
21             =head1 SYNOPSIS
22              
23             # In your Helios::Service class:
24             package MyService;
25             use parent 'Helios::Service';
26             use HeliosX::Job::JSON;
27            
28             sub JobClass { 'HeliosX::Job::JSON' }
29            
30             sub run {
31             ... run code here ...
32             }
33            
34             1;
35            
36             # In your job submission code, use
37             # HeliosX::Job::JSON just like Helios::Job.
38             my $config = Helios::Config->parseConfig();
39             my $arg_json = qq/{ "args" : { "arg1": "value1", "arg2": "string2" } }/;
40             my $job = HeliosX::Job::JSON->new();
41             $job->setConfig($config);
42             $job->setJobType('MyService');
43             $job->setArgString($arg_json);
44             my $jobid = $job->submit();
45              
46             # You may also specify the config, jobtype,
47             # and argument string to the constructor.
48             my $arg_json = qq/{ "args" : { "arg1": "value1", "arg2": "string2" } }/;
49             my $job = HeliosX::Job::JSON->new(
50             config => $config,
51             jobtype => 'MyService',
52             argstring => $arg_json
53             );
54             my $jobid = $job->submit();
55            
56             # Also, if you omit config, HeliosX::Job::JSON will
57             # use Helios::Config to get the config hash.
58             # If you specify the jobtype in the JSON object string,
59             # you do not have to specify a specific jobtype
60             my $arg_json = qq/{ "jobtype" : "MyService", "args" : { "arg1": "value1", "arg2": "string2" } }/;
61             my $job = HeliosX::Job::JSON->new(
62             argstring => $arg_json
63             );
64             my $jobid = $job->submit();
65              
66             # Or use the included heliosx_job_json_submit command.
67             heliosx_job_json_submit --jobtype=MyService --args='{ "args" : { "arg1": "value1", "arg2": "string2" } }'
68              
69              
70             =head1 DESCRIPTION
71              
72             HeliosX::Job::JSON is a Helios::Job subclass allowing you to specify Helios
73             job arguments in JSON format instead of Helios's default XML format. If parts
74             of your application or system use the JSON data format, or your Helios job
75             arguments are difficult to express in XML, you can change your Helios service
76             to use HeliosX::Job::JSON to specify your job arguments in JSON.
77              
78             =head1 JSON JOB ARGUMENT FORMAT
79              
80             Helios job argument JSON should describe a JSON object in the format:
81              
82             {
83             "jobtype" : "",
84             "args" : {
85             "" : "",
86             "" : "",
87             ...etc...
88             }
89             }
90              
91             Your JSON object string will define a "jobtype" string and an "args" object.
92             The name and value pairs of the args object will become the job's argument
93             hash. For example:
94              
95             {
96             "jobtype" : "MyService",
97             "args": {
98             "arg1" : "value1",
99             "arg2" : "value2",
100             "original_file" : "photo.jpg",
101             "size" : "125x125"
102             }
103             }
104              
105             The jobtype value is optional if you specify a jobtype another way i.e. using
106             the --jobtype option with heliosx_job_json_submit or using HeliosX::Job::JSON's
107             setJobType() method.
108              
109             =head1 NOTE ABOUT METAJOBS
110              
111             HeliosX::Job::JSON does not yet support Helios metajobs. Specifying metajob
112             arguments in JSON may be supported in a future release.
113              
114             =head1 METHODS
115              
116             =head2 new()
117              
118             The HeliosX::Job::JSON new() constructor overrides Helios::Job's constructor
119             to allow you to specify the Helios config hash, jobtype, and argument string
120             without making separate subsequent method calls to setConfig(), setJobType(),
121             or setArgString().
122              
123             =cut
124              
125             sub new {
126             my $cl = shift;
127             my $self;
128             if ( @_ && ref($_[0]) && ref($_[0]) eq 'Helios::TS::Job' ) {
129             $self = $cl->SUPER::new(@_);
130             } else {
131             $self = $cl->SUPER::new();
132             }
133             bless($self, $cl);
134             if (@_ > 1) {
135             my %params = @_;
136             if ( $params{config} ) { $self->setConfig($params{config}); }
137             if ( $params{jobtype} ) { $self->setJobType($params{jobtype}); }
138             if ( $params{argstring} ) { $self->setArgString($params{argstring}); }
139             }
140             return $self;
141             }
142              
143             =head2 parseArgs()
144              
145             HeliosX::Job::JSON's parseArgs() method is much simpler than Helios::Job's
146             parseArgs() method because JSON's object format is very close to Perl's concept
147             of a hash.
148              
149             =cut
150              
151             sub parseArgs {
152             my $self = shift;
153             my $arg_string = $self->job()->arg()->[0];
154              
155             my $args_hash = $self->parseArgString($arg_string);
156              
157             unless ( defined($args_hash->{args}) ) {
158             HeliosX::Job::JSON::Error->throw("HeliosX::Job::JSON->parseArgs(): args object is missing!");
159             }
160              
161             my $args = $args_hash->{args};
162            
163             $self->setArgs( $args );
164             return $args;
165             }
166              
167              
168             =head2 parseArgString($json_string)
169              
170             The parseArgString() method does the actual parsing of the JSON object string
171             into the Perl hash using JSON::Tiny. If parsing fails, the method will throw
172             a HeliosX::Job::JSON::Error exception.
173              
174             =cut
175              
176             sub parseArgString {
177             my $self = shift;
178             my $arg_string = shift;
179            
180             my $arg_hash;
181             eval {
182             $arg_hash = decode_json($arg_string);
183             1;
184             } or do {
185             my $E = $@;
186             HeliosX::Job::JSON::Error->throw("HeliosX::Job::JSON->parseArgString(): $E");
187             };
188             return $arg_hash;
189             }
190              
191              
192             =head2 submit()
193              
194             HeliosX::Job::JSON's submit() method overrides Helios::Job's submit() to allow
195             specifying the jobtype via the JSON object instead of requiring a separate call
196             to setJobType(). If the jobtype wasn't explicitly specified and submit()
197             cannot determine the jobtype from the JSON object, it will throw a
198             HeliosX::Job::JSON::Error exception.
199              
200             Also, if the config hash was not explicitly specified with either a config
201             parameter to new() or the setConfig() method, submit() will use
202             Helios::Config->parseConfig() to get the collective database's dsn, user, and
203             password values in the [global] section of the Helios configuration.
204              
205             If job submission is successful, this method will return the new job's jobid
206             to the calling routine.
207              
208             =cut
209              
210             sub submit {
211             my $self = shift;
212            
213             # if setJobType() wasn't used to specify the jobtype
214             # try to get it from the JSON object
215             # ugh: we're exposing some of Helios::Job's guts here :(
216             unless ( $self->job()->{__funcname} ) {
217             my $args = $self->parseArgString( $self->getArgString() );
218             if ( defined($args->{jobtype}) ){
219             $self->setJobType( $args->{jobtype} );
220             } else {
221             # uhoh, if the JSON object didn't have the jobtype,
222             # and the user didn't use setJobType(),
223             # we can't submit!!
224             HeliosX::Job::JSON::Error->throw("HeliosX::Job::JSON::Error->throw(): No jobtype specified!");
225             }
226             }
227              
228             # if setConfig() wasn't used to pass the config,
229             # attempt to use Helios::Config to parse the global config
230             unless ( $self->getConfig() ) {
231             my $conf = Helios::Config->parseConfig();
232             $self->setConfig($conf);
233             }
234            
235             return $self->SUPER::submit();
236             }
237              
238              
239             1;
240             __END__