File Coverage

blib/lib/Net/Radio/oFono/Roles/Manager.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Net::Radio::oFono::Roles::Manager;
2              
3 1     1   14 use 5.010;
  1         4  
  1         34  
4 1     1   5 use strict;
  1         1  
  1         32  
5 1     1   5 use warnings;
  1         2  
  1         44  
6              
7             =head1 NAME
8              
9             Net::Radio::oFono::Roles::Manager - Role for Interfaces which manages objects
10              
11             =head1 DESCRIPTION
12              
13             This package provides a role for being added to classes which need to manages
14             embedded remote objects in remote dbus object.
15              
16             =cut
17              
18             our $VERSION = '0.001';
19              
20             # must be done by embedding class
21             # use base qw(Net::Radio::oFono::Helpers::EventMgr);
22              
23 1     1   549 use Net::DBus qw(:typing);
  0            
  0            
24             use Carp qw/croak/;
25              
26             use Log::Any qw($log);
27              
28             =head1 SYNOPSIS
29              
30             package Net::Radio::oFono::NewInterface;
31              
32             use Net::Radio::oFono::Roles::Manager qw(Embed);
33             use base qw(Net::Radio::oFono::Helpers::EventMgr? Net::Radio::oFono::Roles::RemoteObj Net::Radio::oFono::Roles::Manager ...);
34              
35             use Net::DBus qw(:typing);
36              
37             sub new
38             {
39             my ( $class, %events ) = @_;
40              
41             my $self = $class->SUPER::new(%events); # SUPER::new finds first - so EventMgr::new
42              
43             bless( $self, $class );
44              
45             $self->_init();
46              
47             return $self;
48             }
49              
50             sub _init
51             {
52             my $self = $_[0];
53              
54             # initialize roles
55             $self->Net::Radio::oFono::Roles::RemoteObj::_init( "/modem_0", "org.ofono.NewInterface" ); # must be first one
56             $self->Net::Radio::oFono::Roles::Manager::_init( "Embed", "NewEmbed" );
57             ...
58              
59             return;
60             }
61              
62             sub DESTROY
63             {
64             my $self = $_[0];
65              
66             # destroy roles
67             ...
68             $self->Net::Radio::oFono::Roles::Manager::DESTROY(); # must be last one
69             $self->Net::Radio::oFono::Roles::RemoteObj::DESTROY(); # must be last one
70              
71             # destroy base class
72             $self->Net::Radio::oFono::Helpers::EventMgr::DESTROY();
73              
74             return;
75             }
76              
77             =head1 EVENTS
78              
79             Following events are triggered by this role:
80              
81             =over 4
82              
83             =item ON_ . uc($type) . _ADDED
84              
85             Triggered when a new object of specified type was added.
86              
87             =item ON_ . uc($type) . _REMOVED
88              
89             Triggered when an object of specified type is removed.
90              
91             =back
92              
93             =head1 FUNCTIONS
94              
95             =head2 import($type;$interface)
96              
97             When invoked, getters for embedded objects are injected into caller's
98             namespace using the generic L and L as well
99             as required static methods for managed types.
100              
101             Using the MessageManager example:
102              
103             package Net::Radio::oFono::MessageManager;
104             ...
105             use Net::Radio::oFono::Roles::Manager qw(Message);
106              
107             Injects C and C into
108             Net::Radio::oFono::MessageManager,
109             using C for C and
110             C for C. Injects C<_get_managed_type>
111             and C<_get_managed_interface> into Net::Radio::oFono::MessageManager,
112             returning C as descriptive type and C as interface
113             or class type, respectively.
114              
115             package Net::Radio::oFono::NetworkRegistration;
116             ...
117             use Net::Radio::oFono::Roles::NetworkRegistration qw(Operator NetworkOperator);
118              
119             Injects C and C into
120             Net::Radio::oFono::NetworkRegistration,
121             using C for C and
122             C for C. Injects C<_get_managed_type>
123             and C<_get_managed_interface> into Net::Radio::oFono::NetworkRegistration,
124             returning C as descriptive type and C as
125             interface or class type, respectively.
126              
127             =cut
128              
129             sub import
130             {
131             my ( $me, $type, $interface ) = @_;
132              
133             $interface //= $type;
134             my $caller = caller;
135              
136             if ( defined($type) && !( $caller->can("Get${type}") ) )
137             {
138             my $pkg = __PACKAGE__; # avoid inheritance confusion
139              
140             my $code = <<"EOC";
141             package $caller;
142              
143             sub Get${type}s
144             {
145             return ${pkg}::GetObjects(\@_);
146             }
147              
148             sub Get${type}
149             {
150             return ${pkg}::GetObject(\@_);
151             }
152              
153             1;
154             EOC
155             eval $code or die "Can't inject provides-API";
156             }
157              
158             if ( defined($interface) && !( $caller->can("_get_managed_type") ) )
159             {
160             my $pkg = __PACKAGE__; # avoid inheritance confusion
161              
162             my $code = <<"EOC";
163             package $caller;
164              
165             sub _get_managed_type
166             {
167             return "${type}";
168             }
169              
170             sub _get_managed_interface
171             {
172             return "${interface}";
173             }
174              
175             1;
176             EOC
177             eval $code or die "Can't inject chicken-egg-solver";
178             }
179              
180             return 1;
181             }
182              
183             =head1 METHODS
184              
185             =head2 _init()
186              
187             Initializes the manager role of the object.
188              
189             C<$type> and $<$interface> are the spoken type of the embedded object
190             (for signals, events) and the remote interface name (without the
191             C prefix).
192              
193             If no interface is named, the spoken type is used as interface name
194             (which is pretty common, like for Modem or Message).
195              
196             The initialization connects to the signals C<${type}Added> and
197             C<${type}Removed> provided by oFono's manager objects.
198              
199             =cut
200              
201             sub _init
202             {
203             my ($self) = @_;
204              
205             $self->{mgmt_type} = $self->_get_managed_type();
206             $self->{MGMT_TYPE} = uc( $self->{mgmt_type} );
207             $self->{mgmt_interface} = $self->_get_managed_interface();
208              
209             my $on_obj_added = sub { return $self->onObjectAdded(@_); };
210             $self->{sig_obj_added} =
211             $self->{remote_obj}->connect_to_signal( $self->{mgmt_type} . "Added", $on_obj_added );
212              
213             my $on_obj_removed = sub { return $self->onObjectRemoved(@_); };
214             $self->{sig_obj_removed} =
215             $self->{remote_obj}->connect_to_signal( $self->{mgmt_type} . "Removed", $on_obj_removed );
216              
217             $self->GetObjects(1);
218              
219             return;
220             }
221              
222             =head2 DESTROY
223              
224             Frees previously aquired resources like connected signals, list of managed
225             objects (object_path).
226              
227             Must be invoked before the RemoteObject role frees it's resources ...
228              
229             =cut
230              
231             sub DESTROY
232             {
233             my $self = $_[0];
234              
235             my $type = $self->{mgmt_type};
236             $type or croak "Please use ogd";
237              
238             defined( $self->{remote_obj} )
239             and $self->{remote_obj}->disconnect_from_signal( "${type}Added", $self->{sig_obj_added} );
240             defined( $self->{remote_obj} )
241             and $self->{remote_obj}->disconnect_from_signal( "${type}Removed", $self->{sig_obj_removed} );
242              
243             undef $self->{mgmt_objects};
244              
245             return;
246             }
247              
248             =head2 GetObjects(;$force)
249              
250             Returns the managed objects of the remote object as hash with the
251             object path as key and the properties dictionary (hash) as value.
252              
253             When invoked with a true value as first argument, the managed
254             object list is refreshed from the remote object.
255              
256             Returns the object hash in array more and the reference to the
257             object hash in scalar mode.
258              
259             =over 8
260              
261             =item B
262              
263             Return cloned objects to avoid dirtying the local cache ...
264              
265             =back
266              
267             =cut
268              
269             sub GetObjects
270             {
271             my ( $self, $force ) = @_;
272              
273             if ($force)
274             {
275             my $getter = "Get" . $self->{mgmt_type} . "s";
276             my @obj_lst = @{ $self->{remote_obj}->$getter() };
277             my %mgmt_objects;
278              
279             foreach my $obj_info (@obj_lst)
280             {
281             $mgmt_objects{ $obj_info->[0] } = $obj_info->[1];
282             }
283              
284             $self->{mgmt_objects} = \%mgmt_objects;
285             }
286              
287             return wantarray ? %{ $self->{mgmt_objects} } : $self->{mgmt_objects};
288             }
289              
290             =head2 GetObject($object_path;$force)
291              
292             Returns an instance of the managed object interface identified by the specified
293             object path.
294              
295             Take above example for C, this method will return instances of
296             C using the /{modem0,modem1,...}/{message_01,...}
297             object path.
298              
299             =cut
300              
301             sub GetObject
302             {
303             my ( $self, $obj_path, $force ) = @_;
304              
305             $force and $self->GetObjects($force);
306              
307             my $objClass = "Net::Radio::oFono::" . $self->{mgmt_interface};
308             # check for package first, but Package::Util is just a reserved name and Module::Util is to stupid
309             # probably $objClass->DOES($typical_role) is a way out, but it's not really the same ...
310             return $objClass->new($obj_path);
311             }
312              
313             =head2 onObjectAdded
314              
315             Callback method used when the signal C<..Added> is received.
316             Can be overwritten to implement other or enhanced behavior.
317              
318             =over 4
319              
320             =item *
321              
322             Updates properties cache
323              
324             =item *
325              
326             Triggers event for added object
327              
328             =back
329              
330             =cut
331              
332             sub onObjectAdded
333             {
334             my ( $self, $obj_path, $properties ) = @_;
335              
336             $self->{mgmt_objects}->{$obj_path} = $properties;
337             $self->trigger_event( "ON_" . $self->{MGMT_TYPE} . "_ADDED", $obj_path );
338              
339             return;
340             }
341              
342             =head2 onObjectRemoved
343              
344             Callback method used when the signal C<..Removed> is received.
345             Can be overwritten to implement other or enhanced behavior.
346              
347             =over 4
348              
349             =item *
350              
351             Updates properties cache
352              
353             =item *
354              
355             Triggers event for removed object
356              
357             =back
358              
359             =cut
360              
361             sub onObjectRemoved
362             {
363             my ( $self, $obj_path ) = @_;
364              
365             delete $self->{mgmt_objects}->{$obj_path};
366             $self->trigger_event( "ON_" . $self->{MGMT_TYPE} . "_REMOVED", $obj_path );
367              
368             return;
369             }
370              
371             =head1 BUGS
372              
373             Please report any bugs or feature requests to C, or through
374             the web interface at L. I will be notified, and then you'll
375             automatically be notified of progress on your bug as I make changes.
376              
377             If you think you've found a bug then please read "How to Report Bugs
378             Effectively" by Simon Tatham:
379             L.
380              
381             =head1 SUPPORT
382              
383             You can find documentation for this module with the perldoc command.
384              
385             perldoc Net::Radio::oFono
386              
387             You can also look for information at:
388              
389             =over 4
390              
391             =item * RT: CPAN's request tracker (report bugs here)
392              
393             L
394              
395             If you think you've found a bug then please read "How to Report Bugs
396             Effectively" by Simon Tatham:
397             L.
398              
399             =item * AnnoCPAN: Annotated CPAN documentation
400              
401             L
402              
403             =item * CPAN Ratings
404              
405             L
406              
407             =item * Search CPAN
408              
409             L
410              
411             =back
412              
413             =head2 Where can I go for help with a concrete version?
414              
415             Bugs and feature requests are accepted against the latest version
416             only. To get patches for earlier versions, you need to get an
417             agreement with a developer of your choice - who may or not report the
418             issue and a suggested fix upstream (depends on the license you have
419             chosen).
420              
421             =head2 Business support and maintenance
422              
423             For business support you can contact Jens via his CPAN email
424             address rehsackATcpan.org. Please keep in mind that business
425             support is neither available for free nor are you eligible to
426             receive any support based on the license distributed with this
427             package.
428              
429             =head1 ACKNOWLEDGEMENTS
430              
431             At first the guys from the oFono-Team shall be named: Marcel Holtmann and
432             Denis Kenzior, the maintainers and all the people named in ofono/AUTHORS.
433             Without their effort, there would no need for a Net::Radio::oFono module.
434              
435             Further, Peter "ribasushi" Rabbitson helped a lot by providing hints
436             and support how to make this API accessor a valuable CPAN module.
437              
438             =head1 AUTHOR
439              
440             Jens Rehsack, C<< >>
441              
442             =head1 LICENSE AND COPYRIGHT
443              
444             Copyright 2012 Jens Rehsack.
445              
446             This program is free software; you can redistribute it and/or modify it
447             under the terms of either: the GNU General Public License as published
448             by the Free Software Foundation; or the Artistic License.
449              
450             See http://dev.perl.org/licenses/ for more information.
451              
452             =cut
453              
454             1;