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