File Coverage

blib/lib/Notify/NoticePool.pm
Criterion Covered Total %
statement 33 156 21.1
branch 3 56 5.3
condition 1 9 11.1
subroutine 8 22 36.3
pod 0 16 0.0
total 45 259 17.3


line stmt bran cond sub pod time code
1              
2             package Notify::NoticePool;
3              
4             require 5.00503;
5 1     1   797 use strict;
  1         2  
  1         34  
6 1     1   5 use Carp;
  1         1  
  1         51  
7 1     1   5 use Notify::Notice;
  1         2  
  1         48  
8 1     1   1144 use Tie::Persistent;
  1         22671  
  1         189  
9              
10             require Exporter;
11              
12             our @ISA = qw( Exporter );
13             our %EXPORT_TAGS = ( 'all' => [ qw( DEFAULT_RESEND_INTERVAL DEFAULT_MAX_RETRIES ) ] );
14             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15             our @EXPORT = qw( );
16             #our $VERSION = do { my @r = (q$Revision: 1.1 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
17             our $VERSION = '0.0.1';
18              
19             # Set our notification constants
20 1     1   9 use constant DEFAULT_RESEND_INTERVAL => 300;
  1         2  
  1         63  
21 1     1   4 use constant DEFAULT_MAX_RETRIES => 5;
  1         2  
  1         1645  
22             our $resend_interval = DEFAULT_RESEND_INTERVAL;
23             our $max_retries = DEFAULT_MAX_RETRIES;
24              
25             sub new {
26              
27 1     1 0 12 my ($self, $options) = @_;
28 1   33     11 my $class = ref($self) || $self;
29 1         2 my $this = {};
30 1         4 bless $this, $class;
31              
32 1 50       4 confess "Error creating Notice Pool: No file store given."
33             unless exists $options->{'file_store'};
34              
35 1         7 $this->{'__NOTICE_FILE'} = $options->{'file_store'};
36 1 50       4 $this->{'__TRANSPORT'} = (exists $options->{'transport'})
37             ? $options->{'transport'} : { };
38              
39 1 50       5 $this->updateOutstanding ()
40             unless exists $options->{'no_implicit_update'};
41              
42 1         3 return $this;
43              
44             } #end sub new
45              
46             sub setResendInterval {
47              
48 0     0 0 0 my ($self, $interval) = @_;
49              
50 0 0       0 confess "Error setting resend interval: No interval given."
51             unless $interval;
52              
53 0         0 $resend_interval = $interval;
54              
55             } #end sub setResendInterval
56              
57             sub getResendInterval {
58              
59 0     0 0 0 my ($self) = @_;
60 0         0 return $resend_interval;
61              
62             } #end getResendInterval
63              
64             sub setMaxRetries {
65              
66 0     0 0 0 my ($self, $retries) = @_;
67              
68 0 0       0 confess "Error setting number of max retries: No maximum given."
69             unless $retries;
70              
71 0         0 $max_retries = $retries;
72              
73             } #end sub setMaxRetries
74              
75             sub getMaxRetries {
76              
77 0     0 0 0 my ($self) = @_;
78 0         0 return $max_retries;
79              
80             } #end sub getMaxRetries
81              
82             sub addTransport {
83              
84 0     0 0 0 my ($self, $entries) = @_;
85              
86 0         0 foreach (keys %$entries) {
87              
88 0 0 0     0 confess "Error adding transport entry for type $_. Invalid transport object."
89             unless defined $entries->{$_}->send and defined $entries->{$_}->receive;
90              
91 0         0 $self->{'__TRANSPORT'}->{$_} = $entries->{$_};
92              
93             }
94              
95             } #end sub addTransport
96              
97             sub getUniqueID {
98              
99 0     0 0 0 my ($self) = @_;
100 0         0 my %tied;
101              
102 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
103 0         0 my $lastid = $tied{'__LAST_ID'} + 1;
104 0         0 while (exists $tied{ $lastid }) { $lastid++; }
  0         0  
105 0         0 untie %tied;
106              
107 0         0 return $lastid;
108              
109             } #end sub getUniqueID
110              
111             sub exists {
112              
113 0     0 0 0 my ($self, $id) = @_;
114 0         0 my %tied;
115              
116 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
117 0         0 my $result = exists $tied{$id};
118 0         0 untie %tied;
119              
120 0         0 return $result;
121              
122             } #end sub exists
123              
124             sub addNotice {
125              
126 0     0 0 0 my ($self, $notice) = @_;
127 0         0 my %tied;
128              
129 0 0       0 confess "Error adding notice: No notice given."
130             unless $notice;
131              
132 0         0 my $notice_attribs = $notice->getNotice ();
133              
134 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
135              
136 0 0       0 unless (exists $tied{ $notice_attribs->{'id'} }) {
137              
138 0         0 $notice_attribs->{'time_created'} = $notice_attribs->{'time_updated'} = time ();
139 0         0 $tied{ $notice_attribs->{'id'} } = $notice_attribs;
140              
141             # Update the last used ID
142 0         0 $tied{'__LAST_ID'} = $notice_attribs->{'id'};
143              
144             }
145             else {
146 0         0 return undef;
147             }
148              
149 0         0 untie %tied;
150              
151 0         0 my $new_notice = new Notify::Notice ($notice_attribs);
152 0         0 my $updated = $self->sendIfAppropriate ($new_notice);
153              
154 0 0       0 return ($updated) ? $updated : $new_notice;
155              
156             } #end sub addNotice
157              
158             sub sendIfAppropriate {
159              
160 0     0 0 0 my ($self, $notice) = @_;
161 0         0 my $attribs = $notice->getNotice ();
162 0         0 my %tied;
163              
164             # Try to send the notice immediate with an updated object
165             # and update the persistent object on disk. Note that we
166             # had to untie before trying the send in order to have
167             # guaranteed messaging.
168              
169 0 0       0 if ($attribs->{'status'} == OUTGOING_PENDING) {
170              
171 0 0       0 if ($self->sendNotice ($notice)) {
172 0         0 $attribs->{'status'} = WAITING_RESPONSE;
173             }
174             else {
175 0         0 $attribs->{'attempts'}++;
176             }
177              
178 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
179 0         0 $tied{ $attribs->{'id'} } = $attribs;
180 0         0 untie %tied;
181              
182 0         0 return new Notify::Notice ($attribs);
183              
184             }
185             else {
186 0         0 return undef;
187             }
188              
189             } #end sub sendIfAppropriate
190              
191             sub resolveNotice {
192              
193 0     0 0 0 my ($self, $notice) = @_;
194 0         0 my %tied;
195              
196 0 0       0 confess "Error resolving notice: No notice given."
197             unless $notice;
198              
199 0         0 my $notice_attribs = $notice->getNotice ();
200              
201 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
202 0 0       0 return undef unless exists $tied{ $notice_attribs->{'id'} };
203 0         0 delete $tied{ $notice_attribs->{'id'} };
204 0         0 untie %tied;
205              
206 0         0 return 1;
207              
208             } #end sub resolveNotice
209              
210             sub retrieveNotice {
211              
212 0     0 0 0 my ($self, $notice) = @_;
213 0         0 my %tied;
214 0         0 my ($notice_attribs, $db_attribs);
215              
216 0         0 $notice_attribs = $notice->getNotice ();
217              
218 0 0       0 confess "Error retrieving notice: No notice given."
219             unless $notice;
220              
221 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'r';
222 0 0       0 if (exists $tied{ $notice_attribs->{'id'} }) {
223 0         0 $db_attribs = $tied{ $notice_attribs->{'id'} };
224             }
225             else {
226 0         0 return undef;
227             }
228 0         0 untie %tied;
229              
230 0 0       0 if ($db_attribs->{'status'} == WAITING_PROCESSING) {
231              
232             # Mark that the notification is transaction is considered
233             # done unless the application updated the notification
234             # back to OUTGOING_PENDING
235 0         0 $db_attribs->{'status'} = DONE;
236 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
237 0         0 $tied{ $db_attribs->{'id'} } = $db_attribs;
238 0         0 untie %tied;
239              
240             }
241              
242 0         0 return new Notify::Notice ($db_attribs);
243              
244             } #end sub retreiveNotice
245              
246             sub updateNotice {
247              
248 0     0 0 0 my ($self, $notice) = @_;
249 0         0 my %tied;
250 0         0 my ($new_attribs, $old_attribs);
251              
252 0 0       0 confess "Error updating notice: No notice given."
253             unless $notice;
254              
255 0         0 $new_attribs = $notice->getNotice ();
256              
257 0         0 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
258              
259 0 0       0 return undef unless exists $tied{ $new_attribs->{'id'} };
260 0         0 $old_attribs = $tied{$new_attribs->{'id'}};
261 0         0 push @{ $new_attribs->{'history'} }, $old_attribs->{'message'};
  0         0  
262 0         0 $new_attribs->{'time_updated'} = time ();
263 0         0 $tied{ $new_attribs->{'id'} } = $new_attribs;
264              
265 0         0 untie %tied;
266              
267 0         0 my $new_notice = new Notify::Notice ($new_attribs);
268 0         0 my $updated = $self->sendIfAppropriate ($new_notice);
269              
270 0 0       0 return ($updated) ? $updated : $new_notice;
271              
272             } #end sub updateNotice
273              
274             sub updateOutstanding {
275              
276 1     1 0 2 my ($self) = @_;
277 1         2 my %tied;
278              
279 1         10 tie %tied, 'Tie::Persistent', $self->{'__NOTICE_FILE'}, 'rw';
280              
281 1         78 foreach my $key (keys %tied) {
282              
283             # Skip the special LASTID key
284 0 0       0 next if $key =~ /^__LAST_ID$/;
285              
286 0         0 my $notice_attribs = $tied{$key};
287              
288 0 0       0 if ($notice_attribs->{'status'} == OUTGOING_PENDING) {
    0          
289              
290             # Check to see if we are within the send interval
291 0 0 0     0 next unless $notice_attribs->{'attempts'} and
292             (time () - $notice_attribs->{'time_updated'} > $resend_interval);
293              
294 0         0 my $outgoing = new Notify::Notice ($notice_attribs);
295              
296 0 0       0 if ($self->sendNotice ($outgoing)) {
297              
298 0         0 $notice_attribs->{'status'} = WAITING_RESPONSE;
299 0         0 $notice_attribs->{'time_updated'} = time ();
300              
301             }
302             else {
303              
304 0         0 $notice_attribs->{'attempts'}++;
305              
306 0 0       0 if ($notice_attribs->{'attempts'} > $max_retries) {
307 0         0 $notice_attribs->{'status'} = FAILURE;
308             }
309              
310             }
311              
312             }
313             elsif ($notice_attribs->{'status'} == WAITING_RESPONSE) {
314              
315 0         0 my $incoming = new Notify::Notice ($notice_attribs);
316 0         0 my $response = $self->getNoticeResponse ($incoming);
317              
318 0 0       0 if ($response) {
319              
320 0         0 push @{ $notice_attribs->{'history'} }, $notice_attribs->{'message'};
  0         0  
321 0         0 $notice_attribs->{'message'} = $response;
322 0         0 $notice_attribs->{'status'} = WAITING_PROCESSING;
323 0         0 $notice_attribs->{'time_updated'} = time ();
324              
325             }
326              
327             }
328              
329             # Assign the copy to the persistent DB
330 0         0 $tied{$key} = $notice_attribs;
331              
332             }
333              
334 1         16 untie %tied;
335              
336 1         383 return 1;
337              
338             } #end sub updateOutstanding
339              
340             sub sendNotice {
341              
342 0     0 0   my ($self, $notice) = @_;
343 0           my $attribs = $notice->getNotice ();
344              
345 0 0         confess "Error: Attempted to send notice to undefined transport type."
346             unless exists $self->{'__TRANSPORT'}->{ $attribs->{'transport'} };
347              
348 0           return $self->{'__TRANSPORT'}->{ $attribs->{'transport'} }->send ($notice);
349              
350             } #end sub sendNotice
351              
352             sub getNoticeResponse {
353              
354 0     0 0   my ($self, $notice) = @_;
355 0           my $attribs = $notice->getNotice ();
356              
357 0 0         confess "Error: Attempted to retrieve notice from undefined transport type."
358             unless exists $self->{'__TRANSPORT'}->{ $attribs->{'transport'} };
359              
360 0           return $self->{'__TRANSPORT'}->{ $attribs->{'transport'} }->receive ($notice);
361              
362             } #end sub getNoticeResponse
363              
364             1;
365              
366             __END__