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