Improvement for telephony: just-in-time event revalidation
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Trigger / EventGroup.pm
1 package OpenILS::Application::Trigger::EventGroup;
2 use strict; use warnings;
3 use OpenILS::Application::Trigger::Event;
4 use base 'OpenILS::Application::Trigger::Event';
5 use OpenSRF::EX qw/:try/;
6
7 use OpenSRF::Utils::Logger qw/$logger/;
8
9 use OpenILS::Utils::Fieldmapper;
10 use OpenILS::Utils::CStoreEditor q/:funcs/;
11 use OpenILS::Application::Trigger::ModRunner;
12
13 my $log = 'OpenSRF::Utils::Logger';
14
15 sub new {
16     my $class = shift;
17     my @ids = @_;
18     $class = ref($class) || $class;
19
20     my $editor = new_editor(xact=>1);
21
22     my $self = bless {
23         environment => {},
24         events      => [
25             map {
26                 ref($_) ?
27                     do { $_->standalone(0); $_->editor($editor); $_ } :
28                     OpenILS::Application::Trigger::Event->new($_, $editor)
29             } @ids
30         ],
31         ids         => [ map { ref($_) ? $_->id : $_ } @ids ],
32         editor      => $editor
33     } => $class;
34
35
36     $self->editor->xact_commit; # flush out those updates
37     $self->editor->xact_begin;
38
39     return $self;
40 }
41
42 sub react {
43     my $self = shift;
44
45     return $self if (defined $self->reacted);
46
47     if ($self->valid) {
48         $self->update_state( 'reacting') || die 'Unable to update event group state';
49         $self->build_environment;
50
51         try {
52             $self->reacted(
53                 OpenILS::Application::Trigger::ModRunner::Reactor
54                     ->new( $self->event->event_def->reactor, $self->environment )
55                     ->run
56                     ->final_result
57             );
58         } otherwise {
59             $log->error("Event reacting failed with ". shift() );
60             $self->update_state( 'error' ) || die 'Unable to update event group state';
61         };
62
63         if (defined $self->reacted) {
64             $self->update_state( 'reacted' ) || die 'Unable to update event group state';
65         } else {
66             $self->update_state( 'error' ) || die 'Unable to update event group state';
67         }
68     } else {
69         $self->{reacted} = undef;
70     }
71     return $self;
72 }
73
74 sub validate {
75     my $self = shift;
76
77     return $self if (defined $self->valid);
78
79     $self->update_state( 'validating') || die 'Unable to update event group state';
80     $self->editor->xact_begin;
81
82     my @valid_events;
83     try {
84         for my $event ( @{ $self->events } ) {
85             $event->validate;
86             push @valid_events, $event if ($event->valid);
87         }
88         $self->valid(1) if (@valid_events);
89         $self->{events} = \@valid_events;
90         $self->{ids} = [ map { $_->id } @valid_events ];
91         $self->editor->xact_commit;
92     } otherwise {
93         $log->error("Event group validation failed with ". shift() );
94         $self->editor->xact_rollback;
95         $self->update_state( 'error' ) || die 'Unable to update event group state';
96     };
97
98     return $self;
99 }
100  
101 sub revalidate_test {
102     my $self = shift;
103
104     $self->editor->xact_begin;
105
106     my @valid_events;
107     try {
108         for my $event ( @{ $self->events } ) {
109             push @valid_events, $event->id if $event->revalidate_test;
110         }
111         $self->editor->xact_rollback;
112     } otherwise {
113         $log->error("Event group validation failed with ". shift());
114         $self->editor->xact_rollback;
115     };
116
117     return \@valid_events;
118 }
119  
120 sub cleanedup {
121     my $self = shift;
122     return undef unless (ref $self);
123
124     my $c = shift;
125     $self->{cleanedup} = $c if (defined $c);
126     return $self->{cleanedup};
127 }
128
129 sub reacted {
130     my $self = shift;
131     return undef unless (ref $self);
132
133     my $r = shift;
134     $self->{reacted} = $r if (defined $r);
135     return $self->{reacted};
136 }
137
138 sub valid {
139     my $self = shift;
140     return undef unless (ref $self);
141
142     my $v = shift;
143     $self->{valid} = $v if (defined $v);
144     return $self->{valid};
145 }
146
147 sub event {
148     my $self = shift;
149     return undef unless (ref $self);
150
151     return $self->{events}[0]->event;
152 }
153
154 sub events {
155     my $self = shift;
156     return undef unless (ref $self);
157
158     return $self->{events};
159 }
160
161 sub ids {
162     my $self = shift;
163     return undef unless (ref $self);
164
165     return $self->{ids};
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 unfind {
187     my $self = shift;
188     return undef unless (ref $self);
189
190     die 'Cannot unfind a reacted event group' if (defined $self->reacted);
191
192     $self->update_state( 'pending' ) || die 'Unable to update event group state';
193     $self->{events} = undef;
194     return $self;
195 }
196
197 sub update_state {
198     my $self = shift;
199     return undef unless ($self && ref $self);
200
201     my $state = shift;
202     return undef unless ($state);
203
204     my $fields = shift;
205
206     $self->editor->xact_begin || return undef;
207
208     my @oks;
209     my $ok;
210     my $last_updated;
211     for my $event ( @{ $self->events } ) {
212         my $e = $self->editor->retrieve_action_trigger_event( $event->id );
213         $e->start_time( 'now' ) unless $e->start_time;
214         $e->update_time( 'now' );
215         $e->update_process( $$ );
216         $e->state( $state );
217
218         $e->clear_start_time() if ($e->state eq 'pending');
219
220         if ($fields && ref($fields)) {
221             $e->$_($$fields{$_}) for (keys %$fields);
222         }
223
224         my $ok = $self->editor->update_action_trigger_event( $e );
225         if ($ok) {
226             push @oks, $ok;
227             $last_updated = $e->id;
228         }
229     }
230
231     if (scalar(@oks) < scalar(@{ $self->ids })) {
232         $self->editor->xact_rollback;
233         return undef;
234     } 
235
236     my $updated = $self->editor->retrieve_action_trigger_event($last_updated);
237     $ok = $self->editor->xact_commit;
238
239     if ($ok) {
240         for my $event ( @{ $self->events } ) {
241             my $e = $event->event;
242             $e->start_time( $updated->start_time );
243             $e->update_time( $updated->update_time );
244             $e->update_process( $updated->update_process );
245             $e->state( $updated->state );
246         }
247     }
248
249     return $ok || undef;
250 }
251
252 sub findEvent {
253     my $self = shift;
254     my $member = shift;
255
256     $member = $member->id if (ref($member));
257
258     my @list = grep { $member == $_->id } @{ $self->events };
259
260     return shift(@list);
261 }
262
263 sub build_environment {
264     my $self = shift;
265     my $env = $self->environment;
266
267     $$env{EventProcessor} = $self;
268     $$env{target} = [];
269     $$env{event} = [];
270     $$env{user_data} = [];
271     for my $e ( @{ $self->events } ) {
272         for my $env_part ( keys %{ $e->environment } ) {
273             next if ($env_part eq 'EventProcessor');
274             if ($env_part eq 'target') {
275                 push @{ $$env{target} }, $e->environment->{target};
276             } elsif ($env_part eq 'event') {
277                 push @{ $$env{event} }, $e->environment->{event};
278             } elsif ($env_part eq 'user_data') {
279                 push @{ $$env{user_data} }, $e->environment->{user_data};
280             } else {
281                 $$env{$env_part} = $e->environment->{$env_part};
282             }
283         }
284     }
285
286     return $self;
287 }
288
289 1;