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   25284 use 5.008;
  1         3  
  1         36  
4 1     1   6 use strict;
  1         2  
  1         43  
5 1     1   5 use warnings;
  1         6  
  1         36  
6 1     1   6 use base 'Helios::Job';
  1         1  
  1         768  
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 = '0.02_3670';
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 helios_job_submit_json 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             To specify a Helios job's arguments in JSON, use the following JSON object
81             as an example:
82              
83             {
84             "jobtype" : "Helios::TestService",
85             "args": {
86             "arg1" : "value1",
87             "arg2" : "value2",
88             "original_file" : "photo.jpg",
89             "size" : "125x125"
90             }
91             }
92              
93             Your JSON object string will define a "jobtype" string and an "args" object.
94             The name and value pairs of the args object will become the job's argument
95             hash.
96              
97             The jobtype value is optional if you specify a jobtype another way i.e. using
98             the --jobtype option with heliosx_job_json_submit or using HeliosX::Job::JSON's
99             setJobType() method.
100              
101             =head1 NOTE ABOUT METAJOBS
102              
103             HeliosX::Job::JSON does not yet support Helios metajobs. Specifying metajob
104             arguments in JSON may be supported in a future release.
105              
106             =head1 METHODS
107              
108             =head2 new()
109              
110             The HeliosX::Job::JSON new() constructor overrides Helios::Job's constructor
111             to allow you to specify the Helios config hash, jobtype, and argument string
112             without making separate subsequent method calls to setConfig(), setJobType(),
113             or setArgString().
114              
115             =cut
116              
117             sub new {
118             my $cl = shift;
119             my $self;
120             if ( @_ && ref($_[0]) && ref($_[0]) eq 'Helios::TS::Job' ) {
121             $self = $cl->SUPER::new(@_);
122             } else {
123             $self = $cl->SUPER::new();
124             }
125             bless($self, $cl);
126             if (@_ > 1) {
127             my %params = @_;
128             if ( $params{config} ) { $self->setConfig($params{config}); }
129             if ( $params{jobtype} ) { $self->setJobType($params{jobtype}); }
130             if ( $params{argstring} ) { $self->setArgString($params{argstring}); }
131             }
132             return $self;
133             }
134              
135             =head2 parseArgs()
136              
137             HeliosX::Job::JSON's parseArgs() method is much simpler than Helios::Job's
138             parseArgs() method because JSON's object format is very close to Perl's concept
139             of a hash.
140              
141             =cut
142              
143             sub parseArgs {
144             my $self = shift;
145             my $arg_string = $self->job()->arg()->[0];
146              
147             my $args_hash = $self->parseArgString($arg_string);
148              
149             unless ( defined($args_hash->{args}) ) {
150             HeliosX::Job::JSON::Error->throw("HeliosX::Job::JSON->parseArgs(): args object is missing!");
151             }
152              
153             my $args = $args_hash->{args};
154            
155             $self->setArgs( $args );
156             return $args;
157             }
158              
159              
160             =head2 parseArgString($json_string)
161              
162             The parseArgString() method does the actual parsing of the JSON object string
163             into the Perl hash using JSON::Tiny. If parsing fails, the method will throw
164             a HeliosX::Job::JSON::Error exception.
165              
166             =cut
167              
168             sub parseArgString {
169             my $self = shift;
170             my $arg_string = shift;
171            
172             my $arg_hash;
173             eval {
174             $arg_hash = decode_json($arg_string);
175             1;
176             } or do {
177             my $E = $@;
178             HeliosX::Job::JSON::Error->throw("HeliosX::Job::JSON->parseArgString(): $E");
179             };
180             return $arg_hash;
181             }
182              
183              
184             =head2 submit()
185              
186             HeliosX::Job::JSON's submit() method overrides Helios::Job's submit() to allow
187             specifying the jobtype via the JSON object instead of requiring a separate call
188             to setJobType(). If the jobtype wasn't explicitly specified and submit()
189             cannot determine the jobtype from the JSON object, it will throw a
190             HeliosX::Job::JSON::Error exception.
191              
192             Also, if the config hash was not explicitly specified with either a config
193             parameter to new() or the setConfig() method, submit() will use
194             Helios::Config->parseConfig() to get the collective database's dsn, user, and
195             password values in the [global] section of the Helios configuration.
196              
197             If job submission is successful, this method will return the new job's jobid
198             to the calling routine.
199              
200             =cut
201              
202             sub submit {
203             my $self = shift;
204            
205             # if setJobType() wasn't used to specify the jobtype
206             # try to get it from the JSON object
207             # ugh: we're exposing some of Helios::Job's guts here :(
208             unless ( $self->job()->{__funcname} ) {
209             my $args = $self->parseArgString( $self->getArgString() );
210             if ( defined($args->{jobtype}) ){
211             $self->setJobType( $args->{jobtype} );
212             } else {
213             # uhoh, if the JSON object didn't have the jobtype,
214             # and the user didn't use setJobType(),
215             # we can't submit!!
216             HeliosX::Job::JSON::Error->throw("HeliosX::Job::JSON::Error->throw(): No jobtype specified!");
217             }
218             }
219              
220             # if setConfig() wasn't used to pass the config,
221             # attempt to use Helios::Config to parse the global config
222             unless ( $self->getConfig() ) {
223             my $conf = Helios::Config->parseConfig();
224             $self->setConfig($conf);
225             }
226            
227             return $self->SUPER::submit();
228             }
229              
230              
231             1;
232             __END__