added check for connected when triggered method is called. can't trigger
[urisagit/Stem.git] / lib / Stem / Gather.pm
1 #  File: Stem/Gather.pm
2
3 #  This file is part of Stem.
4 #  Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
5
6 #  Stem is free software; you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License as published by
8 #  the Free Software Foundation; either version 2 of the License, or
9 #  (at your option) any later version.
10
11 #  Stem is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15
16 #  You should have received a copy of the GNU General Public License
17 #  along with Stem; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 #  For a license to use the Stem under conditions other than those
21 #  described here, to purchase support for this software, or to purchase a
22 #  commercial warranty contract, please contact Stem Systems at:
23
24 #       Stem Systems, Inc.              781-643-7504
25 #       79 Everett St.                  info@stemsystems.com
26 #       Arlington, MA 02474
27 #       USA
28
29 package Stem::Gather ;
30
31 #use Stem::Trace 'log' => 'stem_status', 'sub' => 'TraceStatus' ;
32 #use Stem::Trace 'log' => 'stem_error' , 'sub' => 'TraceError' ;
33
34 =head1 Description
35
36 This is a object module used by Stem Cells and objects to detect when
37 a set of asynchronous events have finished. It is constructed by an
38 owner object which then stores it in itselt. Gather objects are
39 initialized with a set of keys to be gathered. When the owner object
40 is notified of an event, it calls the C<gathered> method of the gather
41 object with a list of keys. When all of the keys are gathered, a
42 callback is made to the owner object. An optional timeout is available
43 which will also generate a callback if the keys are not gathered in
44 time.
45
46 =head1 Synopsis
47
48         use Stem::Gather ;
49
50         # $self is the owner object that has already been created
51
52         my $gather = Stem::Gather->new(
53                 'object'        => $self,
54                 'keys'          => [qw( msg1 msg2 )]
55         ) ;
56
57         $self->{'gather'} = $gather ;
58
59         sub msg1_in {
60
61                 my( $self ) = @_ ;
62                 $self->{'gather'}->gathered( 'msg1' ) ;
63         }
64
65         sub msg2_in {
66
67                 my( $self ) = @_ ;
68                 $self->{'gather'}->gathered( 'msg2' ) ;
69         }
70
71         sub gather_done {
72
73                 my( $self ) = @_ ;
74
75                 print "we have gathered\n" ;
76         }
77
78 =cut
79
80 use strict ;
81
82 my %class_to_attr_name ;
83
84 my $attr_spec = [
85
86         {
87                 'name'          => 'object',
88                 'required'      => 1,
89                 'type'          => 'object',
90                 'help'          => <<HELP,
91 This is the owner object which has the methods that get called when Stem::Gather
92 has either finished gathering all of the keys or it has timed out.
93 HELP
94         },
95         {
96                 'name'          => 'keys',
97                 'required'      => 1,
98                 'type'          => 'list',
99                 'help'          => <<HELP,
100 This is the list of keys to gather.
101 HELP
102         },
103         {
104                 'name'          => 'gathered_method',
105                 'default'       => 'gather_done',
106                 'help'          => <<HELP,
107 This method is called in the owner object when all of the keys are gathered.
108 HELP
109         },
110         {
111                 'name'          => 'no_start',
112                 'type'          => 'boolean',
113                 'help'          => <<HELP,
114 If set, then do not start the gather object upon creation. A call to
115 the C<restart> must be made. This only meaningful if this gather has a
116 timeout set.
117 HELP
118         },
119         {
120                 'name'          => 'timeout',
121                 'help'          => <<HELP,
122 This is an optional timeout period (in seconds) waiting for the gather
123 to be completed
124 HELP
125         },
126         {
127                 'name'          => 'timeout_method',
128                 'default'       => 'gather_timeout',
129                 'help'          => <<HELP,
130 This method is called in the owner object if the gather timed out
131 before all keys were gathered.
132 HELP
133         },
134 ] ;
135
136
137 ###########
138 # This POD section is autoegenerated. Any edits to it will be lost.
139
140 =head2 Constructor Attributes for Class Stem::Gather
141
142 =over 4
143
144
145 =item * Attribute - B<object>
146
147 =over 4
148
149
150 =item Description:
151 This is the owner object which has the methods that get called when Stem::Gather
152 has either finished gathering all of the keys or it has timed out.
153
154
155 =item Its B<type> is: object
156
157 =item It is B<required>.
158
159 =back
160
161 =item * Attribute - B<keys>
162
163 =over 4
164
165
166 =item Description:
167 This is the list of keys to gather.
168
169
170 =item Its B<type> is: list
171
172 =item It is B<required>.
173
174 =back
175
176 =item * Attribute - B<gathered_method>
177
178 =over 4
179
180
181 =item Description:
182 This method is called in the owner object when all of the keys are gathered.
183
184
185 =item It B<defaults> to: gather_done
186
187 =back
188
189 =item * Attribute - B<no_start>
190
191 =over 4
192
193
194 =item Description:
195 If set, then do not start the gather object upon creation. A call to
196 the C<restart> must be made. This only meaningful if this gather has a
197 timeout set.
198
199
200 =item Its B<type> is: boolean
201
202 =back
203
204 =item * Attribute - B<timeout>
205
206 =over 4
207
208
209 =item Description:
210 This is an optional timeout period (in seconds) waiting for the gather
211 to be completed
212
213
214 =back
215
216 =item * Attribute - B<timeout_method>
217
218 =over 4
219
220
221 =item Description:
222 This method is called in the owner object if the gather timed out
223 before all keys were gathered.
224
225
226 =item It B<defaults> to: gather_timeout
227
228 =back
229
230 =back
231
232 =cut
233
234 # End of autogenerated POD
235 ###########
236
237
238
239
240 =head2 Method new
241
242 This is the constructor method for Stem::Gather. It uses the standard
243 Stem key/value API with the
244
245 =cut
246
247 sub new {
248
249         my( $class ) = shift ;
250
251         my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
252         return $self unless ref $self ;
253
254 #       return 'Stem::Gather "keys" is not an array reference'
255 #               unless ref $self->{'keys'} eq 'ARRAY' ;
256
257         $self->restart() unless $self->{'no_start'} ;
258
259         return( $self ) ;
260 }
261
262 =head2 Method restart
263
264 This method is called to start up the gather object when it has
265 already gathered all the keys, it has timed out or it was never
266 started (the no_start attribute was enabled). It takes no arguments.
267
268 =cut
269
270
271 sub restart {
272
273         my( $self ) = @_ ;
274
275         $self->{'gathered'} = 0 ;
276
277         $self->{'keys_left'} = { map { $_, 1 } @{$self->{'keys'}} } ;
278
279 #       TraceStatus "GAT keys '@{$self->{'keys'}}'" ;
280
281         $self->_cancel_timeout() ;
282
283         if ( my $timeout = $self->{'timeout'} ) {
284
285                 $self->{'timer_event'} = Stem::Event::Timer->new(
286                                 'object'        => $self,
287                                 'delay'         => $timeout, 
288                                 'hard'          => 1,
289                                 'repeat'        => 0 ) ;
290         }
291 }
292
293 =head2 Method add_keys
294
295 This method is passed a list of keys which will be added to the list
296 to be watched for by the Stem::Gather object. The new keys are not
297 looked for until a call to the C<restart> method is made.
298
299 =cut
300
301 sub add_keys {
302
303         my( $self, @keys ) = @_ ;
304
305         push @{$self->{'keys'}}, @keys ;
306 }
307
308 =head2 Method gathered
309
310 This method is called with a list of keys that are gathered. The keys
311 that haven't been gathered before are marked as gathered. If there are
312 no more keys to be gathered, the method in the C<gathered_method>
313 attribute is called in the owner object. You have to call the
314 C<restart> method on this gather object to use it again.You can pass
315 this methods keys that have been gathered or are not even in the list
316 to be gathered and they are ignored.
317
318 =cut
319
320 sub gathered {
321
322         my( $self, @keys ) = @_ ;
323
324 #       TraceStatus "gathered: @keys" ;
325
326         return if $self->{'gathered'} ;
327
328         delete @{$self->{'keys_left'}}{@keys} ;
329
330         return if keys %{$self->{'keys_left'}} ;
331
332         $self->_cancel_timeout() ;
333         $self->{'gathered'} = 1 ;
334
335         my $method = $self->{'gathered_method'} ;
336
337 #       TraceStatus "gathered done: calling $method" ;
338
339         return $self->{'object'}->$method() ;
340 }
341
342 sub timed_out {
343
344         my( $self ) = @_ ;
345
346         $self->_cancel_timeout() ;
347
348         my $method = $self->{'timeout_method'} ;
349         $self->{'object'}->$method() ;
350
351         return ;
352 }
353
354 sub _cancel_timeout {
355
356         my( $self ) = @_ ;
357
358         if ( my $timer = $self->{'timer_event'} ) {
359                 $timer->cancel() ;
360
361                 delete $self->{'timer_event'} ;
362         }
363 }
364
365 =head2 Method
366
367 This method B<must> be called if the owner object is being shut down or
368 destroyed. It will cancel any pending timeout and break the link back
369 to the owner object. The owner object can then be destroyed without
370 leaking memory.
371
372 =cut
373
374 sub shut_down {
375
376         my( $self ) = @_ ;
377
378         $self->_cancel_timeout() ;
379
380         delete $self->{'object'} ;
381 }
382
383 1 ;