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
119namespace dbus {
120
121const char kObjectManagerInterface[] = "org.freedesktop.DBus.ObjectManager";
122const char kObjectManagerGetManagedObjects[] = "GetManagedObjects";
123const char kObjectManagerInterfacesAdded[] = "InterfacesAdded";
124const char kObjectManagerInterfacesRemoved[] = "InterfacesRemoved";
125
126class Bus;
127class MessageReader;
128class ObjectProxy;
129class Response;
130class 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.
135class CHROME_DBUS_EXPORT ObjectManager
136    : public base::RefCountedThreadSafe<ObjectManager> {
137public:
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  // Cleans up any match rules and filter functions added by this ObjectManager.
227  // The Bus object will take care of this so you don't have to do it manually.
228  //
229  // BLOCKING CALL.
230  void CleanUp();
231
232 protected:
233  virtual ~ObjectManager();
234
235 private:
236  friend class base::RefCountedThreadSafe<ObjectManager>;
237
238  // Connects the InterfacesAdded and InterfacesRemoved signals and calls
239  // GetManagedObjects. Called from OnSetupMatchRuleAndFilterComplete.
240  void InitializeObjects();
241
242  // Called from the constructor to add a match rule for PropertiesChanged
243  // signals on the DBus thread and set up a corresponding filter function.
244  bool SetupMatchRuleAndFilter();
245
246  // Called on the origin thread once the match rule and filter have been set
247  // up. |success| is false, if an error occurred during set up; it's true
248  // otherwise.
249  void OnSetupMatchRuleAndFilterComplete(bool success);
250
251  // Called by dbus:: when a message is received. This is used to filter
252  // PropertiesChanged signals from the correct sender and relay the event to
253  // the correct PropertySet.
254  static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
255                                              DBusMessage* raw_message,
256                                              void* user_data);
257  DBusHandlerResult HandleMessage(DBusConnection* connection,
258                                  DBusMessage* raw_message);
259
260  // Called when a PropertiesChanged signal is received from the sender.
261  // This method notifies the relevant PropertySet that it should update its
262  // properties based on the received signal. Called from HandleMessage.
263  void NotifyPropertiesChanged(const dbus::ObjectPath object_path,
264                               Signal* signal);
265  void NotifyPropertiesChangedHelper(const dbus::ObjectPath object_path,
266                                     Signal* signal);
267
268  // Called by dbus:: in response to the GetManagedObjects() method call.
269  void OnGetManagedObjects(Response* response);
270
271  // Called by dbus:: when an InterfacesAdded signal is received and initially
272  // connected.
273  void InterfacesAddedReceived(Signal* signal);
274  void InterfacesAddedConnected(const std::string& interface_name,
275                                const std::string& signal_name,
276                                bool success);
277
278  // Called by dbus:: when an InterfacesRemoved signal is received and
279  // initially connected.
280  void InterfacesRemovedReceived(Signal* signal);
281  void InterfacesRemovedConnected(const std::string& interface_name,
282                                  const std::string& signal_name,
283                                  bool success);
284
285  // Updates the map entry for the object with path |object_path| using the
286  // D-Bus message in |reader|, which should consist of an dictionary mapping
287  // interface names to properties dictionaries as recieved by both the
288  // GetManagedObjects() method return and the InterfacesAdded() signal.
289  void UpdateObject(const ObjectPath& object_path, MessageReader* reader);
290
291  // Updates the properties structure of the object with path |object_path|
292  // for the interface named |interface_name| using the D-Bus message in
293  // |reader| which should consist of the properties dictionary for that
294  // interface.
295  //
296  // Called by UpdateObjects() for each interface in the dictionary; this
297  // method takes care of both creating the entry in the ObjectMap and
298  // ObjectProxy if required, as well as the PropertySet instance for that
299  // interface if necessary.
300  void AddInterface(const ObjectPath& object_path,
301                    const std::string& interface_name,
302                    MessageReader* reader);
303
304  // Removes the properties structure of the object with path |object_path|
305  // for the interfaces named |interface_name|.
306  //
307  // If no further interfaces remain, the entry in the ObjectMap is discarded.
308  void RemoveInterface(const ObjectPath& object_path,
309                       const std::string& interface_name);
310
311  // Removes all objects and interfaces from the object manager when
312  // |old_owner| is not the empty string and/or re-requests the set of managed
313  // objects when |new_owner| is not the empty string.
314  void NameOwnerChanged(const std::string& old_owner,
315                        const std::string& new_owner);
316
317  Bus* bus_;
318  std::string service_name_;
319  std::string service_name_owner_;
320  std::string match_rule_;
321  ObjectPath object_path_;
322  ObjectProxy* object_proxy_;
323  bool setup_success_;
324  bool cleanup_called_;
325
326  // Maps the name of an interface to the implementation class used for
327  // instantiating PropertySet structures for that interface's properties.
328  typedef std::map<std::string, Interface*> InterfaceMap;
329  InterfaceMap interface_map_;
330
331  // Each managed object consists of a ObjectProxy used to make calls
332  // against that object and a collection of D-Bus interface names and their
333  // associated PropertySet structures.
334  struct Object {
335    Object();
336    ~Object();
337
338    ObjectProxy* object_proxy;
339
340    // Maps the name of an interface to the specific PropertySet structure
341    // of that interface's properties.
342    typedef std::map<const std::string, PropertySet*> PropertiesMap;
343    PropertiesMap properties_map;
344  };
345
346  // Maps the object path of an object to the Object structure.
347  typedef std::map<const ObjectPath, Object*> ObjectMap;
348  ObjectMap object_map_;
349
350  // Weak pointer factory for generating 'this' pointers that might live longer
351  // than we do.
352  // Note: This should remain the last member so it'll be destroyed and
353  // invalidate its weak pointers before any other members are destroyed.
354  base::WeakPtrFactory<ObjectManager> weak_ptr_factory_;
355
356  DISALLOW_COPY_AND_ASSIGN(ObjectManager);
357};
358
359}  // namespace dbus
360
361#endif  // DBUS_OBJECT_MANAGER_H_
362