File Coverage

blib/lib/SIAM/Object.pm
Criterion Covered Total %
statement 102 152 67.1
branch 17 30 56.6
condition n/a
subroutine 20 30 66.6
pod 23 23 100.0
total 162 235 68.9


line stmt bran cond sub pod time code
1             package SIAM::Object;
2              
3 2     2   13 use warnings;
  2         3  
  2         53  
4 2     2   11 use strict;
  2         3  
  2         54  
5              
6 2     2   2549 use Log::Handler;
  2         172622  
  2         17  
7 2     2   1641 use SIAM::Report;
  2         9  
  2         26  
8              
9             # default log manager
10             our $logmgr = Log::Handler->new(
11             'screen' =>
12             {'log_to' => 'STDERR',
13             'maxlevel' => 'warning',
14             'minlevel' => 'emergency'});
15              
16              
17             =head1 NAME
18              
19              
20             SIAM::Object - the base class for all SIAM object (including the root).
21              
22              
23             =cut
24              
25              
26             =head1 SYNOPSIS
27              
28              
29              
30             =head1 INSTANCE METHODS
31              
32             =head2 new
33              
34             $new_object = new SIAM::Object($driver, $id)
35              
36             Instantiates a new object. The method expects a driver object and an Object ID.
37              
38             =cut
39              
40             sub new
41             {
42 115     115 1 187 my $class = shift;
43 115         128 my $driver = shift;
44 115         144 my $id = shift;
45              
46 115         160 my $self = {};
47 115         272 bless $self, $class;
48              
49 115         514 $self->{'_attr'} = {'siam.object.id' => $id,
50             'siam.object.class' => $class};
51 115         202 $self->{'_driver'} = $driver;
52              
53             # retrieve attributes from the driver unless I am root
54 115 100       295 if( not $self->is_root )
55             {
56 114 50       360 if( not $driver->fetch_attributes($self->{'_attr'}) )
57             {
58 0         0 SIAM::Object->error('Failed fetching attributes for ' . $id);
59 0         0 return undef;
60             }
61              
62             # set siam.object.complete to true if undefined
63 114 50       312 if( not defined($self->{'_attr'}{'siam.object.complete'}) )
64             {
65 114         244 $self->{'_attr'}{'siam.object.complete'} = 1;
66             }
67              
68             # set siam.object.has_reports to false if undefined
69 114 100       266 if( not defined($self->{'_attr'}{'siam.object.has_reports'}) )
70             {
71 110         223 $self->{'_attr'}{'siam.object.has_reports'} = 0;
72             }
73            
74             # check if mandatory attributes are defined by the driver
75 114 50       563 if( $self->can('_mandatory_attributes') )
76             {
77 114         124 foreach my $attr (@{ $self->_mandatory_attributes() })
  114         349  
78             {
79 254 50       790 if( not defined($self->{'_attr'}{$attr}) )
80             {
81 0         0 SIAM::Object->error
82             ('Driver did not fetch a mandatory attribute "' .
83             $attr . '" for object ID "' . $id . '"');
84 0         0 return undef;
85             }
86             }
87             }
88             }
89              
90 115         897 return $self;
91             }
92              
93              
94             =head2 instantiate_object
95              
96             Expects the object class and ID. Returns an object retrieved from the driver.
97              
98             =cut
99              
100             sub instantiate_object
101             {
102 6     6 1 10 my $self = shift;
103 6         11 my $obj_class = shift;
104 6         15 my $obj_id = shift;
105              
106 6         532 my $obj = eval 'new ' . $obj_class . '($self->_driver, $obj_id)';
107 6 50       31 if( $@ )
108             {
109 0         0 $self->error('Cannot instantiate object of class "' . $obj_class .
110             '" and ID "' . $obj_id . '": ' . $@);
111 0         0 return undef;
112             }
113            
114 6         24 return $obj;
115             }
116              
117              
118             =head2 get_contained_objects
119              
120             my $list = $object->get_contained_objects($classname, $options);
121              
122             Fetches the list of contained objects of a given class. Returns arrayref of
123             C instances. This is the preferred method of instantiating new
124             objects instead of manually calling the C method.
125              
126             It is assumed that the class name is already known to Perl, and the
127             corresponding module was loaded with C or C.
128              
129             Without the options, the method retrieves all available objects. Options may
130             define a filter criteria as follows:
131              
132             my $list =
133             $siam->get_contained_objects('SIAM::Contract', {
134             'match_attribute' => [ 'siam.object.access_scope_id',
135             ['SCOPEID01', 'SCOPEID02'] ]
136             });
137              
138             Currently only one filter condition is supported.
139              
140             =cut
141              
142             sub get_contained_objects
143             {
144 55     55 1 75 my $self = shift;
145 55         70 my $classname = shift;
146 55         95 my $options = shift;
147              
148 55         128 my $driver = $self->_driver;
149 55         116 my $ids =
150             $driver->fetch_contained_object_ids($self->id, $classname, $options);
151            
152 55         92 my $ret = [];
153 55         66 foreach my $id (@{$ids})
  55         86  
154             {
155 100         6415 my $obj = eval($classname . '->new($driver, $id)');
156              
157 100 50       418 if( $@ )
    50          
158             {
159 0         0 SIAM::Object->error($@);
160             }
161             elsif( defined($obj) )
162             {
163 100         105 push(@{$ret}, $obj);
  100         270  
164             }
165             }
166              
167 55         242 return $ret;
168             }
169              
170              
171             =head2 get_objects_by_attribute
172              
173             my $list = $siam->get_objects_by_attribute(
174             'SIAM::Device', 'siam.device.inventory_id', $id);
175              
176             The method takes 3 arguments: class name, attribute name, and attribute
177             value. It returns an arrayref of objects matching the attribute. Empty
178             arrayref is returned if no objects match the criteria.
179              
180             =cut
181              
182             sub get_objects_by_attribute
183             {
184 0     0 1 0 my $self = shift;
185 0         0 my $classname = shift;
186 0         0 my $attr = shift;
187 0         0 my $value = shift;
188              
189 0         0 my $driver = $self->_driver;
190 0         0 my $ids =
191             $driver->fetch_object_ids_by_attribute($classname, $attr, $value);
192            
193 0         0 my $ret = [];
194 0         0 foreach my $id (@{$ids})
  0         0  
195             {
196 0         0 my $obj = eval($classname . '->new($driver, $id)');
197            
198 0 0       0 if( $@ )
    0          
199             {
200 0         0 SIAM::Object->error($@);
201             }
202             elsif( defined($obj) )
203             {
204 0         0 push(@{$ret}, $obj);
  0         0  
205             }
206             }
207              
208 0         0 return $ret;
209             }
210            
211              
212              
213             =head2 deep_walk_contained_objects
214              
215             my $list = $object->deep_walk_contained_objects($classname);
216              
217             The method walks down the tree of contained objects and retrieves a list
218             of all found objects. It returns an array reference with all found objects;
219              
220             =cut
221              
222              
223             sub deep_walk_contained_objects
224             {
225 1     1 1 3 my $self = shift;
226 1         3 my $classname = shift;
227              
228             # id => objref
229             # the hash is needed to avoid object duplications
230 1         4 my $results = {};
231 1         7 $self->_walk_recursive($classname, $results);
232              
233 1         1 return [values %{$results}];
  1         6  
234             }
235              
236              
237             sub _walk_recursive
238             {
239 10     10   14 my $self = shift;
240 10         12 my $classname = shift;
241 10         11 my $results = shift;
242              
243 10         21 my $driver = $self->_driver;
244 10         20 my $contained_classes = $driver->fetch_contained_classes($self->id());
245              
246 10         15 foreach my $obect_class (@{$contained_classes})
  10         21  
247             {
248 7         17 my $list = $self->get_contained_objects($obect_class);
249              
250 7 100       20 if( $obect_class eq $classname )
251             {
252 2         4 foreach my $item (@{$list})
  2         5  
253             {
254 3         8 $results->{$item->id()} = $item;
255             }
256             }
257            
258 7         11 foreach my $item (@{$list})
  7         12  
259             {
260 9         45 $item->_walk_recursive($classname, $results);
261             }
262             }
263 10         69 return;
264             }
265              
266              
267              
268             =head2 id
269              
270             Returns a value of C attribute
271              
272             =cut
273              
274 358     358 1 2079 sub id { shift->attr('siam.object.id') }
275              
276              
277             =head2 objclass
278              
279             Returns the value of C attribute.
280              
281             =cut
282            
283 59     59 1 669 sub objclass { shift->attr('siam.object.class') }
284              
285              
286             =head2 attr
287              
288             $val = $contract->attr('siam.contract.inventory_id');
289              
290             Returns a value of an attribute.
291              
292             =cut
293              
294             sub attr
295             {
296 455     455 1 1629 my $self = shift;
297 455         505 my $key = shift;
298 455         2107 return $self->{'_attr'}{$key};
299             }
300              
301              
302             =head2 attributes
303              
304             Returns a hashref with copies of all object attributes.
305              
306             =cut
307              
308             sub attributes
309             {
310 50     50 1 676 my $self = shift;
311              
312 50         71 my $ret = {};
313 50         57 while( my($key, $val) = each %{$self->{'_attr'}} )
  385         1218  
314             {
315 335         844 $ret->{$key} = $val;
316             }
317 50         135 return $ret;
318             }
319              
320              
321             =head2 is_complete
322              
323             Returns the value of C.
324              
325             =cut
326              
327             sub is_complete
328             {
329 0     0 1 0 my $self = shift;
330 0         0 my $key = shift;
331 0         0 return $self->{'_attr'}{'siam.object.complete'};
332             }
333              
334            
335              
336             =head2 computable
337              
338             $val = $contract->computable('siam.contract.content_md5hash');
339              
340             Returns a value of a computable.
341              
342             =cut
343              
344             sub computable
345             {
346 3     3 1 9 my $self = shift;
347 3         5 my $key = shift;
348 3         11 return $self->_driver->fetch_computable($self->id, $key);
349             }
350              
351              
352             =head2 set_condition
353              
354             $dataelement->set_condition('torrus.import_successful', 1);
355              
356             The SIAM client application may use this method to send a (key, value)
357             pair to the driver and tell it about some state update. The condition
358             names and accepted values are defined by the driver and are
359             driver-specific. This is a one-way communication, and there is no way to
360             read the condition value.
361              
362             =cut
363              
364             sub set_condition
365             {
366 0     0 1 0 my $self = shift;
367 0         0 my $key = shift;
368 0         0 my $value = shift;
369 0         0 $self->_driver->set_condition($self->id, $key, $value);
370             }
371              
372             =head2 is_root
373              
374             Returns true if the object is a root.
375              
376             =cut
377              
378 215     215 1 659 sub is_root { (shift->id) eq 'SIAM.ROOT' }
379              
380              
381             =head2 is_predefined
382              
383             Returns true if the object is a predefined object (the one with the ID
384             starting with I)
385              
386             =cut
387              
388 0     0 1 0 sub is_predefined { substr(shift->id, 0, 5) eq 'SIAM.' }
389              
390              
391             =head2 contained_in
392              
393             Returns the object that contains this object. Returns undef if container
394             is the root object.
395              
396             =cut
397              
398             sub contained_in
399             {
400 2     2 1 1658 my $self = shift;
401              
402 2         9 my $attr = $self->_driver->fetch_container($self->id);
403 2 100       9 if( $attr->{'siam.object.id'} eq 'SIAM.ROOT' )
404             {
405 1         4 return undef;
406             }
407            
408 1         10 return $self->instantiate_object($attr->{'siam.object.class'},
409             $attr->{'siam.object.id'});
410             }
411            
412              
413              
414             =head2 get_reports
415              
416             Returns arrayref with contained SIAM::Report objects
417              
418             =cut
419              
420             sub get_reports
421             {
422 1     1 1 3 my $self = shift;
423              
424 1 50       5 if( $self->attr('siam.object.has_reports') )
425             {
426 1         14 return $self->get_contained_objects('SIAM::Report');
427             }
428             else
429             {
430 0         0 return [];
431             }
432             }
433              
434              
435              
436             =head1 CLASS METHODS
437              
438             =head2 validate_driver
439              
440             Takes a driver object as an argument and verifies if it implements all
441             required methods. returns true if all required methods are present. It
442             issues error messages in case of missing methods.
443              
444             =cut
445              
446             sub validate_driver
447             {
448 1     1 1 3 my $class = shift;
449 1         2 my $driver = shift;
450              
451 1         3 my $ok = 1;
452 1         4 foreach my $m ('fetch_attributes', 'fetch_contained_object_ids',
453             'fetch_contained_classes', 'fetch_container',
454             'fetch_object_ids_by_attribute', 'set_condition',
455             'manifest_attributes', 'connect', 'disconnect')
456             {
457 9 50       51 if( not $driver->can($m) )
458             {
459 0         0 SIAM::Object->error
460             ('The driver of class ' . ref($driver) . ' does not ' .
461             'implement a required method: ' . $m);
462 0         0 $ok = 0;
463             }
464             }
465              
466 1         7 return $ok;
467             }
468              
469              
470              
471              
472              
473             =head2 set_log_manager
474              
475             Sets a log manager for SIAM objects. Note that it does not set the log
476             manager for the driver. The default log manager is a C
477             object with STDERR output of warnings and errors. The method expects one
478             argument, an object which implements the following methods:
479              
480             =over 4
481              
482             =item * debug
483              
484             =item * info
485              
486             =item * warn
487              
488             =item * error
489              
490             =back
491              
492             Classes that suit as log managers: C, C, ...
493              
494             =cut
495              
496             sub set_log_manager
497             {
498 0     0 1 0 my $class = shift;
499 0         0 $logmgr = shift;
500             }
501              
502              
503             =head2 get_log_manager
504              
505             Returns the current logger object.
506              
507             =cut
508              
509             sub get_log_manager
510             {
511 1     1 1 5 return $logmgr;
512             }
513              
514              
515             =head2 debug, info, warn, error
516              
517             These methods dispatch a message to the log manager. If the log manager
518             is undefined, all except C print the message to STDERR with a
519             preceeding timestamp.
520              
521             =cut
522              
523             sub debug
524             {
525 0     0 1 0 my $class = shift;
526 0         0 my $msg = shift;
527 0         0 $logmgr->debug($msg);
528             }
529              
530             sub info
531             {
532 0     0 1 0 my $class = shift;
533 0         0 my $msg = shift;
534 0         0 $logmgr->info($msg);
535             }
536              
537             sub warn
538             {
539 0     0 1 0 my $class = shift;
540 0         0 my $msg = shift;
541 0         0 $logmgr->warn($msg);
542             }
543              
544             sub error
545             {
546 0     0 1 0 my $class = shift;
547 0         0 my $msg = shift;
548 0         0 $logmgr->error($msg);
549             }
550              
551              
552              
553             =head1 PRIVATE METHODS
554              
555             =head2 _driver
556              
557             Returns the driver object
558              
559             =cut
560              
561 140     140   7097 sub _driver { shift->{'_driver'} }
562              
563              
564             =head2 _print_stderr
565              
566             Prints a message to STDERR with a preceeding timestamp
567              
568             =cut
569              
570             sub _print_stderr
571             {
572 0     0     my $class = shift;
573 0           my $msg = shift;
574              
575 0           print STDERR '[' . scalar(localtime(time())) . '] ' . $msg . "\n";
576             }
577              
578              
579              
580             1;
581              
582             # Local Variables:
583             # mode: cperl
584             # indent-tabs-mode: nil
585             # cperl-indent-level: 4
586             # cperl-continued-statement-offset: 4
587             # cperl-continued-brace-offset: -4
588             # cperl-brace-offset: 0
589             # cperl-label-offset: -2
590             # End: