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