This is an automated email from the git hooks/post-receive script.

intrigeri pushed a commit to branch experimental
in repository libnet-dbus-perl.

commit d3fbdc09ef08842979e6f68eb61e2d74cf4c4f17
Author: Daniel P. Berrange <d...@berrange.com>
Date:   Thu Sep 29 21:57:40 2005 +0000

    Added initial tutorial on creating services
---
 lib/Net/DBus/Tutorial.pm                  |  44 +++++
 lib/Net/DBus/Tutorial/ExportingObjects.pm | 309 ++++++++++++++++++++++++++++++
 2 files changed, 353 insertions(+)

diff --git a/lib/Net/DBus/Tutorial.pm b/lib/Net/DBus/Tutorial.pm
new file mode 100644
index 0000000..1b399cd
--- /dev/null
+++ b/lib/Net/DBus/Tutorial.pm
@@ -0,0 +1,44 @@
+=pod
+
+=head1 NAME
+
+Net::DBus::Tutorial - tutorials on the Perl DBus APIs
+
+=head1 DESCRIPTION
+
+This section includes tutorials on the Perl DBus APIs. Current
+topics include providing a service, by exporting objects to the
+bus, and accessing a service, by calling objects on the bus.
+
+=over 4
+
+=item L<Net::DBus::Tutorial::ExportingObjects>
+
+This tutorial covers how to provide a service to the bus by
+exporting objects. The topics covered include basics of creating
+objects and methods, emitting signals, exporting properties,
+registering services for automatic activation.
+
+=item L<Net::DBus::Tutorial::UsingObjects>
+
+This tutorial cover how to use a service provided on the bus
+by another application. The topics covered include the basics
+of calling methods on remote objects, explicitly calling methods
+in particular interfaces, listening for signals.
+
+=back
+
+=head1 SEE ALSO
+
+L<Net::DBus>, L<Net::DBus::Object>, L<Net::DBus::RemoteObject>,
+L<http://freedesktop.org/>
+
+=head1 AUTHORS
+
+Daniel P. Berrange L<mailto:d...@berrange.com>
+
+=head1 COPYRIGHT
+
+Copyright 2005 Daniel P. Berrange
+
+=cut
diff --git a/lib/Net/DBus/Tutorial/ExportingObjects.pm 
b/lib/Net/DBus/Tutorial/ExportingObjects.pm
new file mode 100644
index 0000000..fb795f7
--- /dev/null
+++ b/lib/Net/DBus/Tutorial/ExportingObjects.pm
@@ -0,0 +1,309 @@
+=pod
+
+=head1 NAME
+
+Net::DBus::Tutorial::ExportingObjects - tutorials on providing a DBus service
+
+=head1 DESCRIPTION
+
+This document provides a tutorial on providing a DBus service using the
+Perl Net::DBus application bindings. This examples in this document
+will be based on the code from the L<Music::Player> distribution, which 
+is a simple DBus service providing a music track player.
+
+=head1 CREATING AN OBJECT
+
+The first step in creating an object is to create a new package
+which inherits from L<Net::DBus::Object>. The Music::Player::Manager
+object provides an API for managing the collection of music player
+backends for different track types. To start with, lets create the
+skeleton of the package & its constructor. The constructor of the
+super type, L<Net::DBus::Object> expects to be given to parameters,
+a handle to the L<Net::DBus::Service> owning the object, and a path
+under which the object shall be exported. Since the manager class is
+intended to be a singleton object, we can hard code the path to it
+within the constructor:
+
+  package Music::Player::Manager;
+
+  use base qw(Net::DBus);
+
+  sub new {
+      my $class = shift;
+      my $service = shift;
+      my $self = $class->SUPER::new($service, "/music/player/manager");
+      
+      bless $self, $class;
+      
+      return $self;
+  }
+
+  1;
+
+
+Now, as mentioned, the manager with handle a number of different 
+player backends. So we need to provide methods for registering
+new backends, and querying for backends capable of playing a 
+particular file type. So modifying the above code we add a hash
+table in the constructor, to store the backends:
+
+
+  sub new {
+      my $class = shift;
+      my $service = shift;
+      my $self = $class->SUPER::new($service, "/music/player/manager");
+
+      $self->{backends} = {};
+      
+      bless $self, $class;
+      
+      return $self;
+  }
+
+And now a method to register a new backend. This takes a Perl
+module name and uses it to instantiate a backend. Since the
+backends are also going to be DBus objects, we need to pass
+in a reference to the service we are attached to, along with
+a path under which to register the backend. We use the C<get_service>
+method to retreieve a reference to the service the manager is
+attached to, and attach the player backend to this same service:
+When a method on DBus object is invoked, the first parameter is
+the object reference (C<$self>), and the remainder are the 
+parameters provided to the method call. Thus writing a method 
+implementation on a DBUs is really no different to normal object
+oriented Perl (cf L<perltoot>):
+
+  sub register_backend {
+      my $self = shift;
+      my $name = shift;
+      my $module = shift;
+
+      eval "use $module";
+      if ($@) {
+          die "cannot load backend $module: $@" ;
+      }
+
+      $self->{backends} = $module->new($self->get_service,
+                                       "/music/player/backend/$name");
+  }
+
+Looking at this one might wonder what happens if the C<die>
+method is triggered. In such a scenario, rather than terminating
+the service process, the error will be caught and propagated back 
+to the remote caller to deal with.
+
+The player backends provide a method C<get_track_types> which returns
+an array reference of the music track types they support. We can use 
+this method to provide an API to allow easy retrieval of a backend 
+for a particular track type. This method will return a path with which 
+the backend object can be accessed
+
+  sub find_backend {
+      my $self = shift;
+      my $extension = shift;
+      
+      foreach my $name (keys %{$self->{backends}}) {
+         my $backend = $self->{backends}->{$name};
+         foreach my $type (@{$backend->get_track_types}) {
+            if ($type eq $extension) {
+                return $backend->get_object_path;
+            }
+         }
+      }
+      
+      die "no backend for type $extension";
+  }
+
+Lets take a quick moment to consider how this method would be used to
+play a music track. If you've not already done so, refresh your memory
+from L<Net::DBus::Tutorial::UsingObjects>. Now, we have an MP3 file 
+which we wish to play, so we search for the path to a backend, then 
+retrieve the object for it, and play the track:
+
+  ...get the music player service...
+  # Ask for a path to a player for mp3 files
+  my $path = $service->find_backend("mp3");
+  # $path now contains '/music/player/backend/mpg123'
+  # and we can get the backend object
+  my $backend = $service->get_object($path);
+  # and finally play the track
+  $backend->play("/vol/music/beck/guero/09-scarecrow.mp3");
+
+=head1 PROVIDING INTROSPECTION DATA
+
+The code above is a complete working object, ready to be registered with
+a service, and since the parameters and return values for the two methods 
+are both simple strings we could stop there. In some cases, however, one
+might want to be more specific about data types expected for parameters,
+for example signed vs unsigned integers. Adding explicit data typing also
+makes interaction with other programming languages more reliable. Providing
+explicit data type defintions for exported method is known in the DBus world
+as C<Introspection>, and it makes life much more reliable for users of one's
+service whom may be using a strongly typed language such as C.
+
+The first step in providing introspection data for a DBus object in Perl, is
+to specify the name of the interface provided by the object. This is typically
+a period separated string, by convention containing the domain name of the 
+application as its first component. Since most Perl modules end up living on
+CPAN, one might use C<org.cpan> as the first component, followed by the package
+name of the module (replacing :: with .), eg C<org.cpan.music.player.manager>. 
If it is
+not planned to host the module on CPAN, a personal/project domain might be
+used eg C<com.berrange.music.player.manager>. The interface for an object is 
defined
+by loading the L<Net::DBus::Exporter> module, providing the interface as its
+first parameter. So the earlier code example would be modified to look like:
+
+  package Music::Player::Manager;
+
+  use base qw(Net::DBus);
+  use Net::DBus::Exporter qw(com.berrange.music.player.manager)
+
+Next up, it is neccessary to provide data types for the parameters and return
+values of the methods. The L<Net::DBus::Exporter> module provides a method
+C<dbus_method> for this purpose, which takes three parameter, the name of the
+method being exported, an array reference of parameter types, and an array
+reference of return types (the latter can be omitted if there are no return
+values). This can be called at any point in the module's code, but by 
convention
+it is preferrable to associate calls to C<dbus_method> with the actual method
+implementation, thus:
+
+  dbus_method("register_backend", ["string", "string"]);
+  sub register_backend {
+      my $self = shift;
+      my $name = shift;
+      my $module = shift;
+
+      .. snipped rest of method body ...
+  }
+
+And, thus:
+
+  dbus_method("find_backend", ["string"], ["string"])
+  sub find_backend {
+      my $self = shift;
+      my $extension = shift;
+      ... snip method body...
+  }
+
+
+=head1 DEFINING A SERVICE
+
+Now that the objects have been written, it is time to define
+a service. A service is nothing more than a well known name
+for a given API contract. A contract can be thought of as a
+definition of a list of object paths, and the corresponding
+interfaces they provide. So, someone else could come along a
+provide an alternate music player implementation using the 
+Python or QT bindings for DBus, and if they provided the same
+set of object paths & interfaces, they could justifiably register
+the same service on the bus. 
+
+The L<Net::DBus::Service> module provides the means to register
+a service. Its constructor expects a reference to the bus object
+(an instance of L<Net::DBus>), along with the name of the service.
+As with interface names, the first component of a service name is 
+usually derived from a domain name, and then suffixed with the 
+name of the application, in our example forming C<org.cpan.Music.Player>.
+While some objects will be created on the fly during execution
+of the application, others are created upon initial startup. The
+music player manager object created earlier in this tutorial is
+an example of the latter. It is typical to instantiate and register
+these objects in the constructor for the service. Thus a service
+object for the music player application would look like:
+
+    package Music::Player;
+
+    use base qw(Net::DBus::Service);
+
+    sub new {
+        my $class = shift;
+        my $bus = shift;
+        my $self = $class->SUPER::new($bus, "org.cpan.music.player");
+
+        bless $self, $class;
+
+        $self->{manager} = Music::Player::Manager->new($self);
+
+        return $self;
+    }
+
+The L<Net::DBus::Service> automatically provides one special
+object to all services, under the path C</org/freedesktop/DBus/Exporter>.
+This object implements the C<org.freedesktop.DBus.Exporter> interface
+which has a method C<ListObject>. This enables clients to determine
+a list of all objects exported within a service. While not functionally
+neccessary for most applications, it is none-the-less a useful tool for
+developers debugging applications, or wondering what a service provides.
+
+=head1 CONNECTING TO THE BUS
+
+The final step in getting our service up and running is to connect it
+to the bus. This brings up an interesting conundrum, does one export
+the service on the system bus (shared by all users & processes on the
+machine), or the session bus (one per user logged into a machine). In
+some cases the answer, with only one of the two buses conceptually making
+sense. In other cases, however, both the session & system bus are valid.
+In the former one would use the C<session> or <system> methods on L<Net::DBus>
+to get a handle to the desired bus, while in the latter case, the C<find>
+method would be used. This applies a heuristic to determine the correct
+bus based on execution environment. In the case of the music player, either
+bus is relevant, so the code to connect the service to the bus would look 
+like:
+
+   use Net::DBus;
+
+   my $bus = Net::DBus->find;
+   my $player = Music::Player->new($bus);
+
+With the service attached to the bus, it is merely neccessary to run 
+the main event processing loop to listen out for & handle incoming
+DBus messages. So the above code is modified to start a simple reactor:
+
+   use Net::DBus;
+   use Net::DBus::Reactor;
+
+   my $bus = Net::DBus->find;
+   my $player = Music::Player->new($bus);
+
+   Net::DBus::Reactor->main->run;
+
+   exit 0;
+
+Saving this code into a script C</usr/bin/music-player.pl>, coding 
+is complete and the service ready for use by clients on the bus.
+
+=head1 SERVICE ACTIVATION
+
+One might now wonder how best to start the service, particularly 
+if it is a service capable of running on
+both the system and session buses. DBus has the answer in the 
+concept of C<activation>. What happens is that when a client
+on the bus attempts to call a method, or register a signal
+handler against, a service not currently running, it will first
+try and start the service. Service's which wish to participate
+in this process merely need stick a simple service definition
+file into the directoy C</usr/share/dbus-1/services>. The file
+should be named to match the service name, with the file extension
+C<.service> appended. eg, 
C</usr/share/dbus-1/services/org.cpan.music.player.service>
+The file contains two keys, first the name of the service, and 
+second the name of the executable used to run the service, or in 
+this case the Perl script. So, for our simple service the data
+file would contain:
+
+  [D-BUS Service]
+  Name=org.cpan.music.player
+  Exec=/usr/bin/music-player.pl
+
+=head1 SEE ALSO
+
+L<Net::DBus::Tutorial> for details of other tutorials, and
+L<Net::DBus> for API documentation
+
+=head1 AUTHORS
+
+Daniel Berrange <d...@berrange.com>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2005 Daniel P. Berrange
+
+=cut

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-perl/packages/libnet-dbus-perl.git

_______________________________________________
Pkg-perl-cvs-commits mailing list
Pkg-perl-cvs-commits@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-perl-cvs-commits

Reply via email to