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