1 // Copyright (c) 2012 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.
5 #ifndef DBUS_PROPERTY_H_
6 #define DBUS_PROPERTY_H_
12 #include "base/basictypes.h"
13 #include "base/bind.h"
14 #include "base/callback.h"
15 #include "dbus/message.h"
16 #include "dbus/object_proxy.h"
18 // D-Bus objects frequently provide sets of properties accessed via a
19 // standard interface of method calls and signals to obtain the current value,
20 // set a new value and be notified of changes to the value. Unfortunately this
21 // interface makes heavy use of variants and dictionaries of variants. The
22 // classes defined here make dealing with properties in a type-safe manner
25 // Client implementation classes should define a Properties structure, deriving
26 // from the PropertySet class defined here. This structure should contain a
27 // member for each property defined as an instance of the Property<> class,
28 // specifying the type to the template. Finally the structure should chain up
29 // to the PropertySet constructor, and then call RegisterProperty() for each
30 // property defined to associate them with their string name.
33 // class ExampleClient {
35 // struct Properties : public dbus::PropertySet {
36 // dbus::Property<std::string> name;
37 // dbus::Property<uint16> version;
38 // dbus::Property<dbus::ObjectPath> parent;
39 // dbus::Property<std::vector<std::string> > children;
41 // Properties(dbus::ObjectProxy* object_proxy,
42 // PropertyChangedCallback callback)
43 // : dbus::PropertySet(object_proxy, "com.example.DBus", callback) {
44 // RegisterProperty("Name", &name);
45 // RegisterProperty("Version", &version);
46 // RegisterProperty("Parent", &parent);
47 // RegisterProperty("Children", &children);
49 // virtual ~Properties() {}
52 // The Properties structure requires a pointer to the object proxy of the
53 // actual object to track, and after construction should have signals
54 // connected to that object and initial values set by calling ConnectSignals()
55 // and GetAll(). The structure should not outlive the object proxy, so it
56 // is recommended that the lifecycle of both be managed together.
58 // Example (continued):
60 // typedef std::map<std::pair<dbus::ObjectProxy*, Properties*> > Object;
61 // typedef std::map<dbus::ObjectPath, Object> ObjectMap;
62 // ObjectMap object_map_;
64 // dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path) {
65 // return GetObject(object_path).first;
68 // Properties* GetProperties(const dbus::ObjectPath& object_path) {
69 // return GetObject(object_path).second;
72 // Object GetObject(const dbus::ObjectPath& object_path) {
73 // ObjectMap::iterator it = object_map_.find(object_path);
74 // if (it != object_map_.end())
77 // dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(...);
78 // // connect signals, etc.
80 // Properties* properties = new Properties(
82 // base::Bind(&PropertyChanged,
83 // weak_ptr_factory_.GetWeakPtr(),
85 // properties->ConnectSignals();
86 // properties->GetAll();
88 // Object object = std::make_pair(object_proxy, properties);
89 // object_map_[object_path] = object;
94 // This now allows code using the client implementation to access properties
95 // in a type-safe manner, and assuming the PropertyChanged callback is
96 // propogated up to observers, be notified of changes. A typical access of
97 // the current value of the name property would be:
99 // ExampleClient::Properties* p = example_client->GetProperties(object_path);
100 // std::string name = p->name.value();
102 // Normally these values are updated from signals emitted by the remote object,
103 // in case an explicit round-trip is needed to obtain the current value, the
104 // Get() method can be used and indicates whether or not the value update was
105 // successful. The updated value can be obtained in the callback using the
108 // p->children.Get(base::Bind(&OnGetChildren));
110 // A new value can be set using the Set() method, the callback indicates
111 // success only; it is up to the remote object when (and indeed if) it updates
112 // the property value, and whether it emits a signal or a Get() call is
113 // required to obtain it.
115 // p->version.Set(20, base::Bind(&OnSetVersion))
119 // D-Bus Properties interface constants, declared here rather than
120 // in property.cc because template methods use them.
121 const char kPropertiesInterface
[] = "org.freedesktop.DBus.Properties";
122 const char kPropertiesGetAll
[] = "GetAll";
123 const char kPropertiesGet
[] = "Get";
124 const char kPropertiesSet
[] = "Set";
125 const char kPropertiesChanged
[] = "PropertiesChanged";
129 // PropertyBase is an abstract base-class consisting of the parts of
130 // the Property<> template that are not type-specific, such as the
131 // associated PropertySet, property name, and the type-unsafe parts
132 // used by PropertySet.
135 PropertyBase() : property_set_(NULL
) {}
137 // Initializes the |property_set| and property |name| so that method
138 // calls may be made from this class. This method is called by
139 // PropertySet::RegisterProperty() passing |this| for |property_set| so
140 // there should be no need to call it directly. If you do beware that
141 // no ownership or reference to |property_set| is taken so that object
142 // must outlive this one.
143 void Init(PropertySet
* property_set
, const std::string
& name
);
145 // Retrieves the name of this property, this may be useful in observers
146 // to avoid specifying the name in more than once place, e.g.
148 // void Client::PropertyChanged(const dbus::ObjectPath& object_path,
149 // const std::string &property_name) {
150 // Properties& properties = GetProperties(object_path);
151 // if (property_name == properties.version.name()) {
152 // // Handle version property changing
155 const std::string
& name() const { return name_
; }
157 // Method used by PropertySet to retrieve the value from a MessageReader,
158 // no knowledge of the contained type is required, this method returns
159 // true if its expected type was found, false if not.
160 virtual bool PopValueFromReader(MessageReader
*) = 0;
163 // Retrieves the associated property set.
164 PropertySet
* property_set() { return property_set_
; }
167 // Pointer to the PropertySet instance that this instance is a member of,
168 // no ownership is taken and |property_set_| must outlive this class.
169 PropertySet
* property_set_
;
171 // Name of the property.
174 DISALLOW_COPY_AND_ASSIGN(PropertyBase
);
177 // PropertySet groups a collection of properties for a remote object
178 // together into a single structure, fixing their types and name such
179 // that calls made through it are type-safe.
181 // Clients always sub-class this to add the properties, and should always
182 // provide a constructor that chains up to this and then calls
183 // RegisterProperty() for each property defined.
185 // After creation, client code should call ConnectSignals() and most likely
186 // GetAll() to seed initial values and update as changes occur.
189 // Callback for changes to cached values of properties, either notified
190 // via signal, or as a result of calls to Get() and GetAll(). The |name|
191 // argument specifies the name of the property changed.
192 typedef base::Callback
<void(const std::string
& name
)> PropertyChangedCallback
;
194 // Constructs a property set, where |object_proxy| specifies the proxy for
195 // the/ remote object that these properties are for, care should be taken to
196 // ensure that this object does not outlive the lifetime of the proxy;
197 // |interface| specifies the D-Bus interface of these properties, and
198 // |property_changed_callback| specifies the callback for when properties
199 // are changed, this may be a NULL callback.
200 PropertySet(ObjectProxy
* object_proxy
, const std::string
& interface
,
201 PropertyChangedCallback property_changed_callback
);
203 // Destructor; we don't hold on to any references or memory that needs
204 // explicit clean-up, but clang thinks we might.
205 virtual ~PropertySet();
207 // Registers a property, generally called from the subclass constructor;
208 // pass the |name| of the property as used in method calls and signals,
209 // and the pointer to the |property| member of the structure. This will
210 // call the PropertyBase::Init method.
211 void RegisterProperty(const std::string
& name
, PropertyBase
* property
);
213 // Connects property change notification signals to the object, generally
214 // called immediately after the object is created and before calls to other
215 // methods. Sub-classes may override to use different D-Bus signals.
216 virtual void ConnectSignals();
218 // Methods connected by ConnectSignals() and called by dbus:: when
219 // a property is changed. Sub-classes may override if the property
220 // changed signal provides different arguments.
221 virtual void ChangedReceived(Signal
*);
222 virtual void ChangedConnected(const std::string
& interface_name
,
223 const std::string
& signal_name
,
226 // Queries the remote object for values of all properties and updates
227 // initial values. Sub-classes may override to use a different D-Bus
228 // method, or if the remote object does not support retrieving all
229 // properties, either ignore or obtain each property value individually.
230 virtual void GetAll();
231 virtual void OnGetAll(Response
* response
);
233 // Update properties by reading an array of dictionary entries, each
234 // containing a string with the name and a variant with the value, from
235 // |message_reader|. Returns false if message is in incorrect format.
236 bool UpdatePropertiesFromReader(MessageReader
* reader
);
238 // Updates a single property by reading a string with the name and a
239 // variant with the value from |message_reader|. Returns false if message
240 // is in incorrect format, or property type doesn't match.
241 bool UpdatePropertyFromReader(MessageReader
* reader
);
243 // Calls the property changed callback passed to the constructor, used
244 // by sub-classes that do not call UpdatePropertiesFromReader() or
245 // UpdatePropertyFromReader(). Takes the |name| of the changed property.
246 void NotifyPropertyChanged(const std::string
& name
);
248 // Retrieves the object proxy this property set was initialized with,
249 // provided for sub-classes overriding methods that make D-Bus calls
250 // and for Property<>. Not permitted with const references to this class.
251 ObjectProxy
* object_proxy() { return object_proxy_
; }
253 // Retrieves the interface of this property set.
254 const std::string
& interface() const { return interface_
; }
257 // Get a weak pointer to this property set, provided so that sub-classes
258 // overriding methods that make D-Bus calls may use the existing (or
259 // override) callbacks without providing their own weak pointer factory.
260 base::WeakPtr
<PropertySet
> GetWeakPtr() {
261 return weak_ptr_factory_
.GetWeakPtr();
265 // Pointer to object proxy for making method calls, no ownership is taken
266 // so this must outlive this class.
267 ObjectProxy
* object_proxy_
;
269 // Interface of property, e.g. "org.chromium.ExampleService", this is
270 // distinct from the interface of the method call itself which is the
271 // general D-Bus Properties interface "org.freedesktop.DBus.Properties".
272 std::string interface_
;
274 // Callback for property changes.
275 PropertyChangedCallback property_changed_callback_
;
277 // Map of properties (as PropertyBase*) defined in the structure to
278 // names as used in D-Bus method calls and signals. The base pointer
279 // restricts property access via this map to type-unsafe and non-specific
281 typedef std::map
<const std::string
, PropertyBase
*> PropertiesMap
;
282 PropertiesMap properties_map_
;
284 // Weak pointer factory as D-Bus callbacks may last longer than these
286 base::WeakPtrFactory
<PropertySet
> weak_ptr_factory_
;
288 DISALLOW_COPY_AND_ASSIGN(PropertySet
);
291 // Property template, this defines the type-specific and type-safe methods
292 // of properties that can be accessed as members of a PropertySet structure.
294 // Properties provide a cached value that has an initial sensible default
295 // until the reply to PropertySet::GetAll() is retrieved and is updated by
296 // all calls to that method, Property<>::Get() and property changed signals
297 // handled by PropertySet. It can be obtained by calling value() on the
300 // It is recommended that this cached value be used where necessary, with
301 // code using PropertySet::PropertyChangedCallback to be notified of changes,
302 // rather than incurring a round-trip to the remote object for each property
305 // Where a round-trip is necessary, the Get() method is provided. And to
306 // update the remote object value, the Set() method is also provided.
308 // Handling of particular D-Bus types is performed via specialization,
309 // typically the PopValueFromReader() and AppendToWriter() methods will need
310 // to be provided, and in rare cases a constructor to provide a default value.
311 // Specializations for basic D-Bus types, strings, object paths and arrays
312 // are provided for you.
314 class Property
: public PropertyBase
{
316 // Callback for Get() method, |success| indicates whether or not the
317 // value could be retrived, if true the new value can be obtained by
318 // calling value() on the property.
319 typedef base::Callback
<void(bool success
)> GetCallback
;
321 // Callback for Set() method, |success| indicates whether or not the
322 // new property value was accepted by the remote object.
323 typedef base::Callback
<void(bool success
)> SetCallback
;
325 Property() : weak_ptr_factory_(this) {}
327 // Retrieves the cached value.
328 const T
& value() const { return value_
; }
330 // Requests an updated value from the remote object incurring a
331 // round-trip. |callback| will be called when the new value is available.
332 // This may not be implemented by some interfaces, and may be overriden
333 // by sub-classes if interfaces use different method calls.
334 virtual void Get(GetCallback callback
) {
335 MethodCall
method_call(kPropertiesInterface
, kPropertiesGet
);
336 MessageWriter
writer(&method_call
);
337 writer
.AppendString(property_set()->interface());
338 writer
.AppendString(name());
340 ObjectProxy
* object_proxy
= property_set()->object_proxy();
341 DCHECK(object_proxy
);
342 object_proxy
->CallMethod(&method_call
,
343 ObjectProxy::TIMEOUT_USE_DEFAULT
,
344 base::Bind(&Property
<T
>::OnGet
,
349 // Callback for Get(), may be overriden by sub-classes if interfaces
350 // use different response arguments.
351 virtual void OnGet(SetCallback callback
, Response
* response
) {
353 LOG(WARNING
) << name() << ": Get: failed.";
357 MessageReader
reader(response
);
358 if (PopValueFromReader(&reader
))
359 property_set()->NotifyPropertyChanged(name());
361 if (!callback
.is_null())
362 callback
.Run(response
);
365 // Requests that the remote object change the property value to |value|,
366 // |callback| will be called to indicate the success or failure of the
367 // request, however the new value may not be available depending on the
368 // remote object. This method may be overridden by sub-classes if
369 // interfaces use different method calls.
370 virtual void Set(const T
& value
, SetCallback callback
) {
371 MethodCall
method_call(kPropertiesInterface
, kPropertiesSet
);
372 MessageWriter
writer(&method_call
);
373 writer
.AppendString(property_set()->interface());
374 writer
.AppendString(name());
375 AppendToWriter(&writer
, value
);
377 ObjectProxy
* object_proxy
= property_set()->object_proxy();
378 DCHECK(object_proxy
);
379 object_proxy
->CallMethod(&method_call
,
380 ObjectProxy::TIMEOUT_USE_DEFAULT
,
381 base::Bind(&Property
<T
>::OnSet
,
386 // Callback for Set(), may be overriden by sub-classes if interfaces
387 // use different response arguments.
388 virtual void OnSet(SetCallback callback
, Response
* response
) {
389 LOG_IF(WARNING
, !response
) << name() << ": Set: failed.";
390 if (!callback
.is_null())
391 callback
.Run(response
);
394 // Updates the cached property value, replacing any previous value
395 // entirely, by popping from |reader| which should be positioned at the
396 // property value, generally of variant type.
397 // Implementation provided by specialization.
398 virtual bool PopValueFromReader(MessageReader
* reader
);
400 // Appends the passed |value| to |writer|, generally as a variant type.
401 // Implementation provided by specialization.
402 virtual void AppendToWriter(MessageWriter
* writer
, const T
& value
);
405 // Get a weak pointer to this propertyt, provided so that sub-classes
406 // overriding methods that make D-Bus calls may use the existing (or
407 // override) callbacks without providing their own weak pointer factory.
408 base::WeakPtr
<Property
<T
> > GetWeakPtr() {
409 return weak_ptr_factory_
.GetWeakPtr();
413 // Current cached value of the property.
416 // Weak pointer factory as D-Bus callbacks may last longer than these
418 base::WeakPtrFactory
<Property
<T
> > weak_ptr_factory_
;
423 #endif // DBUS_PROPERTY_H_