Home | History | Annotate | Download | only in dbus
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef DBUS_OBJECT_MANAGER_H_
      6 #define DBUS_OBJECT_MANAGER_H_
      7 
      8 #include <map>
      9 
     10 #include "base/memory/ref_counted.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "dbus/object_path.h"
     13 #include "dbus/property.h"
     14 
     15 // Newer D-Bus services implement the Object Manager interface to inform other
     16 // clients about the objects they export, the properties of those objects, and
     17 // notification of changes in the set of available objects:
     18 //     http://dbus.freedesktop.org/doc/dbus-specification.html
     19 //       #standard-interfaces-objectmanager
     20 //
     21 // This interface is very closely tied to the Properties interface, and uses
     22 // even more levels of nested dictionaries and variants. In addition to
     23 // simplifying implementation, since there tends to be a single object manager
     24 // per service, spanning the complete set of objects an interfaces available,
     25 // the classes implemented here make dealing with this interface simpler.
     26 //
     27 // Except where noted, use of this class replaces the need for the code
     28 // documented in dbus/property.h
     29 //
     30 // Client implementation classes should begin by deriving from the
     31 // dbus::ObjectManager::Interface class, and defining a Properties structure as
     32 // documented in dbus/property.h.
     33 //
     34 // Example:
     35 //   class ExampleClient : public dbus::ObjectManager::Interface {
     36 //    public:
     37 //     struct Properties : public dbus::PropertySet {
     38 //       dbus::Property<std::string> name;
     39 //       dbus::Property<uint16> version;
     40 //       dbus::Property<dbus::ObjectPath> parent;
     41 //       dbus::Property<std::vector<std::string> > children;
     42 //
     43 //       Properties(dbus::ObjectProxy* object_proxy,
     44 //                  const PropertyChangedCallback callback)
     45 //           : dbus::PropertySet(object_proxy, kExampleInterface, callback) {
     46 //         RegisterProperty("Name", &name);
     47 //         RegisterProperty("Version", &version);
     48 //         RegisterProperty("Parent", &parent);
     49 //         RegisterProperty("Children", &children);
     50 //       }
     51 //       virtual ~Properties() {}
     52 //     };
     53 //
     54 // The link between the implementation class and the object manager is set up
     55 // in the constructor and removed in the destructor; the class should maintain
     56 // a pointer to its object manager for use in other methods and establish
     57 // itself as the implementation class for its interface.
     58 //
     59 // Example:
     60 //   explicit ExampleClient::ExampleClient(dbus::Bus* bus)
     61 //       : bus_(bus),
     62 //         weak_ptr_factory_(this) {
     63 //     object_manager_ = bus_->GetObjectManager(kServiceName, kManagerPath);
     64 //     object_manager_->RegisterInterface(kInterface, this);
     65 //   }
     66 //
     67 //   virtual ExampleClient::~ExampleClient() {
     68 //     object_manager_->UnregisterInterface(kInterface);
     69 //   }
     70 //
     71 // The D-Bus thread manager takes care of issuing the necessary call to
     72 // GetManagedObjects() after the implementation classes have been set up.
     73 //
     74 // The object manager interface class has one abstract method that must be
     75 // implemented by the class to create Properties structures on demand. As well
     76 // as implementing this, you will want to implement a public GetProperties()
     77 // method.
     78 //
     79 // Example:
     80 //   dbus::PropertySet* CreateProperties(dbus::ObjectProxy* object_proxy,
     81 //                                       const std::string& interface_name)
     82 //       OVERRIDE {
     83 //     Properties* properties = new Properties(
     84 //           object_proxy, interface_name,
     85 //           base::Bind(&PropertyChanged,
     86 //                      weak_ptr_factory_.GetWeakPtr(),
     87 //                      object_path));
     88 //     return static_cast<dbus::PropertySet*>(properties);
     89 //   }
     90 //
     91 //   Properties* GetProperties(const dbus::ObjectPath& object_path) {
     92 //     return static_cast<Properties*>(
     93 //         object_manager_->GetProperties(object_path, kInterface));
     94 //   }
     95 //
     96 // Note that unlike classes that only use dbus/property.h there is no need
     97 // to connect signals or obtain the initial values of properties. The object
     98 // manager class handles that for you.
     99 //
    100 // PropertyChanged is a method of your own to notify your observers of a change
    101 // in your properties, either as a result of a signal from the Properties
    102 // interface or from the Object Manager interface. You may also wish to
    103 // implement the optional ObjectAdded and ObjectRemoved methods of the class
    104 // to likewise notify observers.
    105 //
    106 // When your class needs an object proxy for a given object path, it may
    107 // obtain it from the object manager. Unlike the equivalent method on the bus
    108 // this will return NULL if the object is not known.
    109 //
    110 //   object_proxy = object_manager_->GetObjectProxy(object_path);
    111 //   if (object_proxy) {
    112 //     ...
    113 //   }
    114 //
    115 // There is no need for code using your implementation class to be aware of the
    116 // use of object manager behind the scenes, the rules for updating properties
    117 // documented in dbus/property.h still apply.
    118 
    119 namespace dbus {
    120 
    121 const char kObjectManagerInterface[] = "org.freedesktop.DBus.ObjectManager";
    122 const char kObjectManagerGetManagedObjects[] = "GetManagedObjects";
    123 const char kObjectManagerInterfacesAdded[] = "InterfacesAdded";
    124 const char kObjectManagerInterfacesRemoved[] = "InterfacesRemoved";
    125 
    126 class Bus;
    127 class MessageReader;
    128 class ObjectProxy;
    129 class Response;
    130 class Signal;
    131 
    132 // ObjectManager implements both the D-Bus client components of the D-Bus
    133 // Object Manager interface, as internal methods, and a public API for
    134 // client classes to utilize.
    135 class CHROME_DBUS_EXPORT ObjectManager
    136     : public base::RefCountedThreadSafe<ObjectManager> {
    137 public:
    138   // ObjectManager::Interface must be implemented by any class wishing to have
    139   // its remote objects managed by an ObjectManager.
    140   class Interface {
    141    public:
    142     virtual ~Interface() {}
    143 
    144     // Called by ObjectManager to create a Properties structure for the remote
    145     // D-Bus object identified by |object_path| and accessibile through
    146     // |object_proxy|. The D-Bus interface name |interface_name| is that passed
    147     // to RegisterInterface() by the implementation class.
    148     //
    149     // The implementation class should create and return an instance of its own
    150     // subclass of dbus::PropertySet; ObjectManager will then connect signals
    151     // and update the properties from its own internal message reader.
    152     virtual PropertySet* CreateProperties(
    153         ObjectProxy *object_proxy,
    154         const dbus::ObjectPath& object_path,
    155         const std::string& interface_name) = 0;
    156 
    157     // Called by ObjectManager to inform the implementation class that an
    158     // object has been added with the path |object_path|. The D-Bus interface
    159     // name |interface_name| is that passed to RegisterInterface() by the
    160     // implementation class.
    161     //
    162     // If a new object implements multiple interfaces, this method will be
    163     // called on each interface implementation with differing values of
    164     // |interface_name| as appropriate. An implementation class will only
    165     // receive multiple calls if it has registered for multiple interfaces.
    166     virtual void ObjectAdded(const ObjectPath& object_path,
    167                              const std::string& interface_name) { }
    168 
    169     // Called by ObjectManager to inform the implementation class than an
    170     // object with the path |object_path| has been removed. Ths D-Bus interface
    171     // name |interface_name| is that passed to RegisterInterface() by the
    172     // implementation class. Multiple interfaces are handled as with
    173     // ObjectAdded().
    174     //
    175     // This method will be called before the Properties structure and the
    176     // ObjectProxy object for the given interface are cleaned up, it is safe
    177     // to retrieve them during removal to vary processing.
    178     virtual void ObjectRemoved(const ObjectPath& object_path,
    179                                const std::string& interface_name) { }
    180   };
    181 
    182   // Client code should use Bus::GetObjectManager() instead of this constructor.
    183   ObjectManager(Bus* bus,
    184                 const std::string& service_name,
    185                 const ObjectPath& object_path);
    186 
    187   // Register a client implementation class |interface| for the given D-Bus
    188   // interface named in |interface_name|. That object's CreateProperties()
    189   // method will be used to create instances of dbus::PropertySet* when
    190   // required.
    191   void RegisterInterface(const std::string& interface_name,
    192                          Interface* interface);
    193 
    194   // Unregister the implementation class for the D-Bus interface named in
    195   // |interface_name|, objects and properties of this interface will be
    196   // ignored.
    197   void UnregisterInterface(const std::string& interface_name);
    198 
    199   // Returns a list of object paths, in an undefined order, of objects known
    200   // to this manager.
    201   std::vector<ObjectPath> GetObjects();
    202 
    203   // Returns the list of object paths, in an undefined order, of objects
    204   // implementing the interface named in |interface_name| known to this manager.
    205   std::vector<ObjectPath> GetObjectsWithInterface(
    206       const std::string& interface_name);
    207 
    208   // Returns a ObjectProxy pointer for the given |object_path|. Unlike
    209   // the equivalent method on Bus this will return NULL if the object
    210   // manager has not been informed of that object's existance.
    211   ObjectProxy* GetObjectProxy(const ObjectPath& object_path);
    212 
    213   // Returns a PropertySet* pointer for the given |object_path| and
    214   // |interface_name|, or NULL if the object manager has not been informed of
    215   // that object's existance or the interface's properties. The caller should
    216   // cast the returned pointer to the appropriate type, e.g.:
    217   //   static_cast<Properties*>(GetProperties(object_path, my_interface));
    218   PropertySet* GetProperties(const ObjectPath& object_path,
    219                              const std::string& interface_name);
    220 
    221   // Instructs the object manager to refresh its list of managed objects;
    222   // automatically called by the D-Bus thread manager, there should never be
    223   // a need to call this manually.
    224   void GetManagedObjects();
    225 
    226  protected:
    227   virtual ~ObjectManager();
    228 
    229  private:
    230   friend class base::RefCountedThreadSafe<ObjectManager>;
    231 
    232 
    233   // Called by dbus:: in response to the GetManagedObjects() method call.
    234   void OnGetManagedObjects(Response* response);
    235 
    236   // Called by dbus:: when an InterfacesAdded signal is received and initially
    237   // connected.
    238   void InterfacesAddedReceived(Signal* signal);
    239   void InterfacesAddedConnected(const std::string& interface_name,
    240                                 const std::string& signal_name,
    241                                 bool success);
    242 
    243   // Called by dbus:: when an InterfacesRemoved signal is received and
    244   // initially connected.
    245   void InterfacesRemovedReceived(Signal* signal);
    246   void InterfacesRemovedConnected(const std::string& interface_name,
    247                                   const std::string& signal_name,
    248                                   bool success);
    249 
    250   // Updates the map entry for the object with path |object_path| using the
    251   // D-Bus message in |reader|, which should consist of an dictionary mapping
    252   // interface names to properties dictionaries as recieved by both the
    253   // GetManagedObjects() method return and the InterfacesAdded() signal.
    254   void UpdateObject(const ObjectPath& object_path, MessageReader* reader);
    255 
    256   // Updates the properties structure of the object with path |object_path|
    257   // for the interface named |interface_name| using the D-Bus message in
    258   // |reader| which should consist of the properties dictionary for that
    259   // interface.
    260   //
    261   // Called by UpdateObjects() for each interface in the dictionary; this
    262   // method takes care of both creating the entry in the ObjectMap and
    263   // ObjectProxy if required, as well as the PropertySet instance for that
    264   // interface if necessary.
    265   void AddInterface(const ObjectPath& object_path,
    266                     const std::string& interface_name,
    267                     MessageReader* reader);
    268 
    269   // Removes the properties structure of the object with path |object_path|
    270   // for the interfaces named |interface_name|.
    271   //
    272   // If no further interfaces remain, the entry in the ObjectMap is discarded.
    273   void RemoveInterface(const ObjectPath& object_path,
    274                        const std::string& interface_name);
    275 
    276   Bus* bus_;
    277   std::string service_name_;
    278   ObjectPath object_path_;
    279   ObjectProxy* object_proxy_;
    280 
    281   // Maps the name of an interface to the implementation class used for
    282   // instantiating PropertySet structures for that interface's properties.
    283   typedef std::map<std::string, Interface*> InterfaceMap;
    284   InterfaceMap interface_map_;
    285 
    286   // Each managed object consists of a ObjectProxy used to make calls
    287   // against that object and a collection of D-Bus interface names and their
    288   // associated PropertySet structures.
    289   struct Object {
    290     Object();
    291     ~Object();
    292 
    293     ObjectProxy* object_proxy;
    294 
    295     // Maps the name of an interface to the specific PropertySet structure
    296     // of that interface's properties.
    297     typedef std::map<const std::string, PropertySet*> PropertiesMap;
    298     PropertiesMap properties_map;
    299   };
    300 
    301   // Maps the object path of an object to the Object structure.
    302   typedef std::map<const ObjectPath, Object*> ObjectMap;
    303   ObjectMap object_map_;
    304 
    305   // Weak pointer factory for generating 'this' pointers that might live longer
    306   // than we do.
    307   // Note: This should remain the last member so it'll be destroyed and
    308   // invalidate its weak pointers before any other members are destroyed.
    309   base::WeakPtrFactory<ObjectManager> weak_ptr_factory_;
    310 
    311   DISALLOW_COPY_AND_ASSIGN(ObjectManager);
    312 };
    313 
    314 }  // namespace dbus
    315 
    316 #endif  // DBUS_OBJECT_MANAGER_H_
    317