File Coverage

blib/lib/XAS/Lib/App.pm
Criterion Covered Total %
statement 15 75 20.0
branch 0 8 0.0
condition n/a
subroutine 5 27 18.5
pod 8 8 100.0
total 28 118 23.7


line stmt bran cond sub pod time code
1             package XAS::Lib::App;
2              
3             our $VERSION = '0.05';
4              
5 1     1   659 use Try::Tiny;
  1         1  
  1         55  
6 1     1   3 use Pod::Usage;
  1         2  
  1         75  
7 1     1   464 use Hash::Merge;
  1         1753  
  1         42  
8 1     1   669 use Getopt::Long;
  1         7221  
  1         5  
9              
10             use XAS::Class
11 1         20 debug => 0,
12             version => $VERSION,
13             base => 'XAS::Base',
14             mixin => 'XAS::Lib::Mixins::Handlers',
15             import => 'CLASS',
16             utils => 'dotid',
17             filesystem => 'File',
18             vars => {
19             PARAMS => {
20             -throws => { optional => 1, default => undef },
21             -facility => { optional => 1, default => undef },
22             -priority => { optional => 1, default => undef },
23             }
24             }
25 1     1   164 ;
  1         1  
26              
27             #use Data::Dumper;
28              
29             # ----------------------------------------------------------------------
30             # Public Methods
31             # ----------------------------------------------------------------------
32              
33             sub signal_handler {
34 0     0 1   my $signal = shift;
35              
36 0           my $ex = XAS::Exception->new(
37             type => 'xas.lib.app.signal_handler',
38             info => 'process interrupted by signal ' . $signal
39             );
40              
41 0           $ex->throw();
42              
43             }
44              
45             sub define_signals {
46 0     0 1   my $self = shift;
47              
48 0           $SIG{'INT'} = \&signal_handler;
49 0           $SIG{'QUIT'} = \&signal_handler;
50              
51             }
52              
53             sub define_pidfile {
54 0     0 1   my $self = shift;
55              
56             }
57              
58             sub define_daemon {
59 0     0 1   my $self = shift;
60              
61             }
62              
63             sub run {
64 0     0 1   my $self = shift;
65              
66 0           my $rc = 0;
67              
68             try {
69              
70 0     0     $self->define_signals();
71 0           $self->define_daemon();
72 0           $self->define_pidfile();
73              
74 0           $self->main();
75              
76             } catch {
77              
78 0     0     my $ex = $_;
79              
80 0           $rc = $self->exit_handler($ex);
81              
82 0           };
83              
84 0           return $rc;
85              
86             }
87              
88             sub main {
89 0     0 1   my $self = shift;
90              
91 0           $self->log->warn('You need to override main()');
92              
93             }
94              
95             sub options {
96 0     0 1   my $self = shift;
97              
98 0           return {};
99              
100             }
101              
102             # ----------------------------------------------------------------------
103             # Private Methods
104             # ----------------------------------------------------------------------
105              
106             sub init {
107 0     0 1   my $class = shift;
108              
109 0           my $self = $class->SUPER::init(@_);
110              
111 0 0         if (defined($self->throws)) {
112              
113 0           $self->env->throws($self->throws);
114 0           $self->class->throws($self->throws);
115              
116             }
117              
118 0 0         if (defined($self->priority)) {
119              
120 0           $self->env->priority($self->priority);
121              
122             }
123              
124 0 0         if (defined($self->facility)) {
125              
126 0           $self->env->facility($self->facility);
127              
128             }
129              
130 0           my $options = $self->options();
131 0           my $defaults = $self->_default_options();
132              
133 0           $self->_parse_cmdline($defaults, $options);
134              
135 0           return $self;
136              
137             }
138              
139             sub _default_options {
140 0     0     my $self = shift;
141              
142 0           my $version = $self->CLASS->VERSION;
143 0           my $script = $self->env->script;
144              
145             return {
146 0     0     'alerts!' => sub { $self->env->alerts($_[1]); },
147 0     0     'help|h|?' => sub { pod2usage(-verbose => 0, -exitstatus => 0); },
148 0     0     'manual' => sub { pod2usage(-verbose => 2, -exitstatus => 0); },
149 0     0     'version' => sub { printf("%s - v%s\n", $script, $version); exit 0; },
  0            
150             'debug' => sub {
151 0     0     $self->env->xdebug(1);
152 0           $self->log->level('debug', 1);
153             },
154             'priority=s' => sub {
155 0     0     $self->env->priority($_[1]);
156             },
157             'facility=s' => sub {
158 0     0     $self->env->facility($_[1]);
159             },
160             'log-file=s' => sub {
161 0     0     my $logfile = File($_[1]);
162 0           $self->env->log_type('file');
163 0           $self->env->log_file($logfile);
164 0           $self->log->activate();
165             },
166             'log-type=s' => sub {
167 0     0     $self->env->log_type($_[1]);
168 0           $self->log->activate();
169             },
170             'log-facility=s' => sub {
171 0     0     $self->env->log_facility($_[1]);
172             },
173 0           };
174              
175             }
176              
177             sub _parse_cmdline {
178 0     0     my ($self, $defaults, $optional) = @_;
179              
180 0           my $hm = Hash::Merge->new('RIGHT_PRECEDENT');
181 0           my %options = %{ $hm->merge($defaults, $optional) };
  0            
182              
183 0 0         GetOptions(%options) or pod2usage(-verbose => 0, -exitstatus => 1);
184              
185             }
186              
187             1;
188              
189             __END__
190              
191             =head1 NAME
192              
193             XAS::Lib::App - The base class to write procedures within the XAS environment
194              
195             =head1 SYNOPSIS
196              
197             use XAS::Lib::App;
198              
199             my $app = XAS::Lib::App->new();
200              
201             $app->run();
202              
203             =head1 DESCRIPTION
204              
205             This module defines a base class for writing procedures. It provides
206             signal handling, options processing, along with a exit handler.
207              
208             =head1 METHODS
209              
210             =head2 new
211              
212             This method initializes the module. It inherits from L<XAS::Base|XAS::Base>
213             and takes these additional parameters:
214              
215             =over 4
216              
217             =item B<-throws>
218              
219             This changes the default error message from "changeme" to something useful.
220              
221             =item B<-facility>
222              
223             This will change the facility of the alert. The default is 'systems'.
224              
225             =item B<-priority>
226              
227             This will change the priority of the alert. The default is 'low'.
228              
229             =back
230              
231             =head2 run
232              
233             This method sets up a global exception handler and calls main(). The main()
234             method will be passed one parameter: an initialized handle to this class.
235              
236             Example
237              
238             sub main {
239             my $self = shift;
240              
241             $self->log->debug('in main');
242              
243             }
244              
245             =over 4
246              
247             =item Exception Handling
248              
249             If an exception is caught, the global exception handler will send an alert,
250             write the exception to the log and returns an exit code of 1.
251              
252             =item Normal Completion
253              
254             When the procedure completes successfully, it will return an exit code of 0.
255              
256             =back
257              
258             To change this behavior you would need to override the exit_handler() method.
259              
260             =head2 main
261              
262             This is where your main line logic starts.
263              
264             =head2 options
265              
266             This method sets up additional cli options. Option handling is provided
267             by L<Getopt::Long|https://metacpan.org/pod/Getopt::Long>. To access these
268             options you need to define accessors for them.
269              
270             Example
271              
272             use XAS::Class
273             version => '0.01',
274             base => 'XAS::Lib::App',
275             accessors => 'widget'
276             ;
277              
278             sub main {
279             my $self = shift;
280              
281             $self->log->info('starting up');
282             sleep(60);
283             $self->log->info('shutting down');
284              
285             }
286              
287             sub options {
288             my $self = shift;
289              
290             return {
291             'widget=s' => sub {
292             $self->{widget} = uc($_[1]);
293             }
294             };
295              
296             }
297              
298             =head2 define_signals
299              
300             This method sets up basic signal handling. By default this is only for the INT
301             and QUIT signals.
302              
303             Example
304              
305             sub define_signals {
306             my $self = shift;
307              
308             $SIG{INT} = \&signal_handler;
309             $SIG{QUIT} = \&singal_handler;
310              
311             }
312              
313             =head2 define_pidfile
314              
315             This is an entry point to define a pid file.
316              
317             =head2 define_daemon
318              
319             This is an entry point so the procedure can daemonize.
320              
321             =head2 signal_handler($signal)
322              
323             This method is a default signal handler. By default it throws an exception.
324             It takes one parameter.
325              
326             =over 4
327              
328             =item B<$signal>
329              
330             The signal that was captured.
331              
332             =back
333              
334             =head1 OPTIONS
335              
336             This module handles the following command line options.
337              
338             =head2 --facility
339              
340             Defines the facility to use. Defaults to 'systems'. This will override the
341             class parameter.
342              
343             =head2 --priority
344              
345             Defines the priority to use. Defaults to 'low'. This will override the
346             class parameter.
347              
348             =head2 --debug
349              
350             This toggles debugging output.
351              
352             =head2 --[no]alerts
353              
354             This toggles sending alerts. They are on by default.
355              
356             =head2 --help
357              
358             This prints out a short help message based on the procedures pod.
359              
360             =head2 --manual
361              
362             This displaces the procedures manual in the defined pager.
363              
364             =head2 --version
365              
366             This prints out the version of the module.
367              
368             =head2 --log-type
369              
370             What type of log to use. By default the log is displayed on the console. Log
371             types can be one of the following "console", "file", "json" or "syslog".
372              
373             =head2 --log-facility
374              
375             What log facility class to use. This follows syslog convention. By default
376             the facility is "local6".
377              
378             =head2 --log-file
379              
380             The name of the log file. When --logfile is specified, it implies a log type
381             of "file".
382              
383             =head1 SEE ALSO
384              
385             =over 4
386              
387             =item L<XAS::Lib::App::Daemon|XAS::Lib::App::Daemon>
388              
389             =item L<XAS::Lib::App::Service|XAS::Lib::App::Service>
390              
391             =item L<XAS::Lib::App::Service::Unix|XAS::Lib::App::Service::Unix>
392              
393             =item L<XAS::Lib::App::Service::Win32|XAS::Lib::App::Service::Win32>
394              
395             =item L<XAS|XAS>
396              
397             =back
398              
399             =head1 AUTHOR
400              
401             Kevin L. Esteb, E<lt>kevin@kesteb.usE<gt>
402              
403             =head1 COPYRIGHT AND LICENSE
404              
405             Copyright (c) 2012-2015 Kevin L. Esteb
406              
407             This is free software; you can redistribute it and/or modify it under
408             the terms of the Artistic License 2.0. For details, see the full text
409             of the license at http://www.perlfoundation.org/artistic_license_2_0.
410              
411             =cut