]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Trigger/Event.pm
add strict/warnings all around to ease debugging
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Trigger / Event.pm
1 package OpenILS::Application::Trigger::Event;
2 use strict; use warnings;
3 use OpenSRF::EX qw/:try/;
4
5 use OpenSRF::Utils::Logger qw/:logger/;
6
7 use OpenILS::Utils::Fieldmapper;
8 use OpenILS::Utils::CStoreEditor q/:funcs/;
9 use OpenILS::Application::Trigger::ModRunner;
10
11 my $log = 'OpenSRF::Utils::Logger';
12
13 sub new {
14     my $class = shift;
15     my $id = shift;
16     my $editor = shift;
17     $class = ref($class) || $class;
18
19     return $id if (ref($id) && ref($id) == $class);
20
21     my $standalone = $editor ? 0 : 1;
22     $editor ||= new_editor();
23
24     my $self = bless { id => $id, editor => $editor, standalone => $standalone } => $class;
25
26     return $self->init()
27 }
28
29 sub init {
30     my $self = shift;
31     my $id = shift;
32
33     return $self if ($self->event);
34
35     $self->id( $id ); 
36     $self->environment( {} ); 
37
38     if (!$self->id) {
39         $log->error("No Event ID provided");
40         die "No Event ID provided";
41     }
42
43     return $self if (!$self->id);
44
45     $self->event(
46         $self->editor->retrieve_action_trigger_event([
47             $self->id, {
48                 flesh => 2,
49                 flesh_fields => {
50                     atev    => [ qw/event_def/ ],
51                     atevdef => [ qw/hook env params/ ]
52                 }
53             }
54         ])
55     );
56
57     if ($self->event->state eq 'valid') {
58         $self->valid(1);
59     } elsif ($self->event->state eq 'invalid') {
60         $self->valid(0);
61     } elsif ($self->event->state eq 'reacting') {
62         $self->valid(1);
63     } elsif ($self->event->state eq 'reacted') {
64         $self->valid(1);
65         $self->reacted(1);
66     } elsif ($self->event->state eq 'cleaning') {
67         $self->valid(1);
68         $self->reacted(1);
69     } elsif ($self->event->state eq 'complete') {
70         $self->valid(1);
71         $self->reacted(1);
72         $self->cleanedup(1);
73     } elsif ($self->event->state eq 'error') {
74         $self->valid(0);
75         $self->reacted(0);
76         $self->cleanedup(0);
77     }
78
79
80     $self->update_state('found') || die 'Unable to update event state';
81
82     my $class = $self->_fm_class_by_hint( $self->event->event_def->hook->core_type );
83     
84     my $meth = "retrieve_" . $class;
85     $meth =~ s/Fieldmapper:://;
86     $meth =~ s/::/_/;
87     
88     $self->target( $self->editor->$meth( $self->event->target ) );
89
90     return $self;
91 }
92
93 sub cleanup {
94     my $self = shift;
95     my $env = shift || $self->environment;
96
97     return $self if (defined $self->cleanedup);
98
99     if (defined $self->reacted) {
100         $self->update_state( 'cleaning') || die 'Unable to update event state';
101         try {
102             my $cleanup = $self->reacted ? $self->event->event_def->cleanup_success : $self->event->event_def->cleanup_failure;
103             if($cleanup) {
104                 $self->cleanedup(
105                     OpenILS::Application::Trigger::ModRunner::Cleanup
106                         ->new( $cleanup, $env)
107                         ->run
108                         ->final_result
109                 );
110             } else {
111                 $self->cleanedup(1);
112             }
113         } otherwise {
114             $log->error( shift() );
115             $self->update_state( 'error' ) || die 'Unable to update event state';
116         };
117
118         if ($self->cleanedup) {
119             $self->update_state( 'complete' ) || die 'Unable to update event state';
120         } else {
121             $self->update_state( 'error' ) || die 'Unable to update event state';
122         }
123
124     } else {
125         $self->{cleanedup} = undef;
126     }
127     return $self;
128 }
129
130 sub react {
131     my $self = shift;
132     my $env = shift || $self->environment;
133
134     return $self if (defined $self->reacted);
135
136     if ($self->valid) {
137         if ($self->event->event_def->group_field) { # can't react individually to a grouped definition
138             $self->{reacted} = undef;
139         } else {
140             $self->update_state( 'reacting') || die 'Unable to update event state';
141             try {
142                 $self->reacted(
143                     OpenILS::Application::Trigger::ModRunner::Reactor
144                         ->new( $self->event->event_def->reactor, $env )
145                         ->run
146                         ->final_result
147                 );
148             } otherwise {
149                 $log->error( shift() );
150                 $self->update_state( 'error' ) || die 'Unable to update event state';
151             };
152
153             if (defined $self->reacted) {
154                 $self->update_state( 'reacted' ) || die 'Unable to update event state';
155             } else {
156                 $self->update_state( 'error' ) || die 'Unable to update event state';
157             }
158         }
159     } else {
160         $self->{reacted} = undef;
161     }
162     return $self;
163 }
164
165 sub validate {
166     my $self = shift;
167
168     return $self if (defined $self->valid);
169
170     if ($self->build_environment->environment->{complete}) {
171         $self->update_state( 'validating') || die 'Unable to update event state';
172         try {
173             $self->valid(
174                 OpenILS::Application::Trigger::ModRunner::Validator
175                     ->new( $self->event->event_def->validator, $self->environment )
176                     ->run
177                     ->final_result
178             );
179         } otherwise {
180             $log->error( shift() );
181             $self->update_state( 'error' ) || die 'Unable to update event state';
182         };
183
184         if (defined $self->valid) {
185             if ($self->valid) {
186                 $self->update_state( 'valid' ) || die 'Unable to update event state';
187             } else {
188                 $self->update_state( 'invalid' ) || die 'Unable to update event state';
189             }
190         } else {
191             $self->update_state( 'error' ) || die 'Unable to update event state';
192         }
193     } else {
194         $self->{valid} = undef
195     }
196
197     return $self;
198 }
199  
200 sub cleanedup {
201     my $self = shift;
202     return undef unless (ref $self);
203
204     my $c = shift;
205     $self->{cleanedup} = $c if (defined $c);
206     return $self->{cleanedup};
207 }
208
209 sub reacted {
210     my $self = shift;
211     return undef unless (ref $self);
212
213     my $r = shift;
214     $self->{reacted} = $r if (defined $r);
215     return $self->{reacted};
216 }
217
218 sub valid {
219     my $self = shift;
220     return undef unless (ref $self);
221
222     my $v = shift;
223     $self->{valid} = $v if (defined $v);
224     return $self->{valid};
225 }
226
227 sub event {
228     my $self = shift;
229     return undef unless (ref $self);
230
231     my $e = shift;
232     $self->{event} = $e if (defined $e);
233     return $self->{event};
234 }
235
236 sub id {
237     my $self = shift;
238     return undef unless (ref $self);
239
240     my $i = shift;
241     $self->{id} = $i if (defined $i);
242     return $self->{id};
243 }
244
245 sub environment {
246     my $self = shift;
247     return undef unless (ref $self);
248
249     my $e = shift;
250     $self->{environment} = $e if (defined $e);
251     return $self->{environment};
252 }
253
254 sub editor {
255     my $self = shift;
256     return undef unless (ref $self);
257
258     my $e = shift;
259     $self->{editor} = $e if (defined $e);
260     return $self->{editor};
261 }
262
263 sub unfind {
264     my $self = shift;
265     return undef unless (ref $self);
266
267     die 'Cannot unfind a reacted event' if (defined $self->reacted);
268
269     $self->update_state( 'pending' ) || die 'Unable to update event state';
270     $self->{id} = undef;
271     $self->{event} = undef;
272     $self->{environment} = undef;
273     return $self;
274 }
275
276 sub target {
277     my $self = shift;
278     return undef unless (ref $self);
279
280     my $t = shift;
281     $self->{target} = $t if (defined $t);
282     return $self->{target};
283 }
284
285 sub standalone {
286     my $self = shift;
287     return undef unless (ref $self);
288
289     my $t = shift;
290     $self->{standalone} = $t if (defined $t);
291     return $self->{standalone};
292 }
293
294 sub update_state {
295     my $self = shift;
296     return undef unless ($self && ref $self);
297
298     my $state = shift;
299     return undef unless ($state);
300
301     my $fields = shift;
302
303     if ($self->standalone) {
304         $self->editor->xact_begin || return undef;
305     }
306
307     my $e = $self->editor->retrieve_action_trigger_event( $self->id );
308     if (!$e) {
309         $log->error( "Could not retrieve object ".$self->id." for update" ) if (!$e);
310         return undef;
311     }
312
313     if ($fields && ref($fields)) {
314         $e->$_($$fields{$_}) for (keys %$fields);
315     }
316
317     $log->info( "Retrieved object ".$self->id." for update" );
318     $e->start_time( 'now' ) unless $e->start_time;
319     $e->update_time( 'now' );
320     $e->update_process( $$ );
321     $e->state( $state );
322
323     $e->clear_start_time() if ($e->state eq 'pending');
324
325     my $ok = $self->editor->update_action_trigger_event( $e );
326     if (!$ok) {
327         $self->editor->xact_rollback if ($self->standalone);
328         $log->error( "Update of event ".$self->id." failed" );
329         return undef;
330     } else {
331         $e = $self->editor->data;
332         $e = $self->editor->retrieve_action_trigger_event( $e ) if (!ref($e));
333         if (!$e) {
334             $log->error( "Update of event ".$self->id." did not return an object" );
335             return undef;
336         }
337         $log->info( "Update of event ".$e->id." suceeded" );
338         $ok = $self->editor->xact_commit if ($self->standalone);
339     }
340
341     if ($ok) {
342         $self->event->start_time( $e->start_time );
343         $self->event->update_time( $e->update_time );
344         $self->event->update_process( $e->update_process );
345         $self->event->state( $e->state );
346     }
347
348     return $ok || undef;
349 }
350
351 sub build_environment {
352     my $self = shift;
353     return $self if ($self->environment->{complete});
354
355     $self->update_state( 'collecting') || die 'Unable to update event state';
356
357     try {
358    
359         $self->environment->{target} = $self->target;
360         $self->environment->{event} = $self->event;
361         $self->environment->{template} = $self->event->event_def->template;
362
363         $self->environment->{params}{ $_->param } = eval $_->value for ( @{$self->event->event_def->params} );
364     
365         for my $e ( @{$self->event->event_def->env} ) {
366             my (@label, @path);
367             @path = split(/\./, $e->path) if ($e->path);
368             @label = split(/\./, $e->label) if ($e->label);
369     
370             $self->_object_by_path( $self->target, $e->collector, \@label, \@path );
371         }
372
373         if ($self->event->event_def->group_field) {
374             my @group_path = split(/\./, $self->event->event_def->group_field);
375             my $group_object = $self->_object_by_path( $self->target, undef, [], \@group_path );
376         }
377     
378         $self->environment->{complete} = 1;
379     } otherwise {
380         $log->error( shift() );
381         $self->update_state( 'error' ) || die 'Unable to update event state';
382     };
383
384     if ($self->environment->{complete}) {
385         $self->update_state( 'collected' ) || die 'Unable to update event state';
386     } else {
387         $self->update_state( 'error' ) || die 'Unable to update event state';
388     }
389
390     return $self;
391 }
392
393 sub _fm_class_by_hint {
394     my $self = shift;
395     my $hint = shift;
396
397     my ($class) = grep {
398         Fieldmapper->publish_fieldmapper->{$_}->{hint} eq $hint
399     } keys %{ Fieldmapper->publish_fieldmapper };
400
401     return $class;
402 }
403
404 sub _object_by_path {
405     my $self = shift;
406     my $context = shift;
407     my $collector = shift;
408     my $label = shift;
409     my $path = shift;
410
411     my $step = shift(@$path);
412     
413     my $fhint = Fieldmapper->publish_fieldmapper->{$context->class_name}{links}{$step}{class};
414     my $fclass = $self->_fm_class_by_hint( $fhint );
415
416     my $ffield = Fieldmapper->publish_fieldmapper->{$context->class_name}{links}{$step}{key};
417     my $rtype = Fieldmapper->publish_fieldmapper->{$context->class_name}{links}{$step}{reltype};
418
419     my $meth = 'retrieve_';
420     my $multi = 0;
421     my $lfield = $step;
422     if ($rtype ne 'has_a') {
423         $meth = 'search_';
424         $multi = 1;
425         $lfield = $context->Identity;
426     }
427
428     $meth .= $fclass;
429     $meth =~ s/Fieldmapper:://;
430     $meth =~ s/::/_/;
431
432     my $ed = grep( /open-ils.cstore/, @{$fclass->Controller} ) ?
433             $self->editor :
434             new_rstore_editor();
435
436     my $obj = $context->$step(); 
437
438     if (!ref $obj) {
439         $obj = $ed->$meth( 
440             ($multi) ?
441                 { $ffield => $context->$lfield() } :
442                 $context->$lfield()
443         );
444     }
445
446     if (@$path) {
447
448         my $obj_list = [];
449         if (!$multi || $rtype eq 'might_have') {
450             $obj_list = [$obj] if ($obj);
451         } else {
452             $obj_list = $obj;
453         }
454
455         $self->_object_by_path( $_, $collector, $label, $path ) for (@$obj_list);
456
457         $obj = $$obj_list[0] if (!$multi || $rtype eq 'might_have');
458         $context->$step( $obj ) if ($obj && (!$label || !@$label));
459
460     } else {
461
462         if ($collector) {
463             my $obj_list = [$obj] if ($obj && !$multi);
464             $obj_list = $obj if ($multi);
465
466             my @new_obj_list;
467             for my $o ( @$obj_list ) {
468                 push @new_obj_list,
469                     OpenILS::Application::Trigger::ModRunner::Collector
470                         ->new( $collector, $o )
471                         ->run
472                         ->final_result
473             }
474
475             if (!$multi) {
476                 $obj = $new_obj_list[0];
477             } else {
478                 $obj = \@new_obj_list;
479             }
480         }
481
482         if ($label && @$label) {
483             my $node = $self->environment;
484             my $i = 0; my $max = scalar(@$label);
485             for (; $i < $max; $i++) {
486                 my $part = $$label[$i];
487                 $$node{$part} ||= {};
488                 $node = $$node{$part};
489             }
490             $$node{$$label[-1]} = $obj;
491         } else {
492             $context->$step( $obj ) if ($obj);
493         }
494     }
495
496     return $obj;
497 }
498
499 1;