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_
13 #include "base/basictypes.h"
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "dbus/dbus_export.h"
17 #include "dbus/message.h"
18 #include "dbus/object_proxy.h"
20 // D-Bus objects frequently provide sets of properties accessed via a
21 // standard interface of method calls and signals to obtain the current value,
22 // set a new value and be notified of changes to the value. Unfortunately this
23 // interface makes heavy use of variants and dictionaries of variants. The
24 // classes defined here make dealing with properties in a type-safe manner
27 // Client implementation classes should define a Properties structure, deriving
28 // from the PropertySet class defined here. This structure should contain a
29 // member for each property defined as an instance of the Property<> class,
30 // specifying the type to the template. Finally the structure should chain up
31 // to the PropertySet constructor, and then call RegisterProperty() for each
32 // property defined to associate them with their string name.
35 // class ExampleClient {
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;
43 // Properties(dbus::ObjectProxy* object_proxy,
44 // const PropertyChangedCallback callback)
45 // : dbus::PropertySet(object_proxy, "com.example.DBus", callback) {
46 // RegisterProperty("Name", &name);
47 // RegisterProperty("Version", &version);
48 // RegisterProperty("Parent", &parent);
49 // RegisterProperty("Children", &children);
51 // virtual ~Properties() {}
54 // The Properties structure requires a pointer to the object proxy of the
55 // actual object to track, and after construction should have signals
56 // connected to that object and initial values set by calling ConnectSignals()
57 // and GetAll(). The structure should not outlive the object proxy, so it
58 // is recommended that the lifecycle of both be managed together.
60 // Example (continued):
62 // typedef std::map<std::pair<dbus::ObjectProxy*, Properties*> > Object;
63 // typedef std::map<dbus::ObjectPath, Object> ObjectMap;
64 // ObjectMap object_map_;
66 // dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path) {
67 // return GetObject(object_path).first;
70 // Properties* GetProperties(const dbus::ObjectPath& object_path) {
71 // return GetObject(object_path).second;
74 // Object GetObject(const dbus::ObjectPath& object_path) {
75 // ObjectMap::iterator it = object_map_.find(object_path);
76 // if (it != object_map_.end())
79 // dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(...);
80 // // connect signals, etc.
82 // Properties* properties = new Properties(
84 // base::Bind(&PropertyChanged,
85 // weak_ptr_factory_.GetWeakPtr(),
87 // properties->ConnectSignals();
88 // properties->GetAll();
90 // Object object = std::make_pair(object_proxy, properties);
91 // object_map_[object_path] = object;
96 // This now allows code using the client implementation to access properties
97 // in a type-safe manner, and assuming the PropertyChanged callback is
98 // propogated up to observers, be notified of changes. A typical access of
99 // the current value of the name property would be:
101 // ExampleClient::Properties* p = example_client->GetProperties(object_path);
102 // std::string name = p->name.value();
104 // Normally these values are updated from signals emitted by the remote object,
105 // in case an explicit round-trip is needed to obtain the current value, the
106 // Get() method can be used and indicates whether or not the value update was
107 // successful. The updated value can be obtained in the callback using the
110 // p->children.Get(base::Bind(&OnGetChildren));
112 // A new value can be set using the Set() method, the callback indicates
113 // success only; it is up to the remote object when (and indeed if) it updates
114 // the property value, and whether it emits a signal or a Get() call is
115 // required to obtain it.
117 // p->version.Set(20, base::Bind(&OnSetVersion))
121 // D-Bus Properties interface constants, declared here rather than
122 // in property.cc because template methods use them.
123 const char kPropertiesInterface
[] = "org.freedesktop.DBus.Properties";
124 const char kPropertiesGetAll
[] = "GetAll";
125 const char kPropertiesGet
[] = "Get";
126 const char kPropertiesSet
[] = "Set";
127 const char kPropertiesChanged
[] = "PropertiesChanged";
131 // PropertyBase is an abstract base-class consisting of the parts of
132 // the Property<> template that are not type-specific, such as the
133 // associated PropertySet, property name, and the type-unsafe parts
134 // used by PropertySet.
135 class CHROME_DBUS_EXPORT PropertyBase
{
138 virtual ~PropertyBase();
140 // Initializes the |property_set| and property |name| so that method
141 // calls may be made from this class. This method is called by
142 // PropertySet::RegisterProperty() passing |this| for |property_set| so
143 // there should be no need to call it directly. If you do beware that
144 // no ownership or reference to |property_set| is taken so that object
145 // must outlive this one.
146 void Init(PropertySet
* property_set
, const std::string
& name
);
148 // Retrieves the name of this property, this may be useful in observers
149 // to avoid specifying the name in more than once place, e.g.
151 // void Client::PropertyChanged(const dbus::ObjectPath& object_path,
152 // const std::string &property_name) {
153 // Properties& properties = GetProperties(object_path);
154 // if (property_name == properties.version.name()) {
155 // // Handle version property changing
158 const std::string
& name() const { return name_
; }
160 // Returns true if property is valid, false otherwise.
161 bool is_valid() const { return is_valid_
; }
163 // Allows to mark Property as valid or invalid.
164 void set_valid(bool is_valid
) { is_valid_
= is_valid
; }
166 // Method used by PropertySet to retrieve the value from a MessageReader,
167 // no knowledge of the contained type is required, this method returns
168 // true if its expected type was found, false if not.
169 // Implementation provided by specialization.
170 virtual bool PopValueFromReader(MessageReader
* reader
) = 0;
172 // Method used by PropertySet to append the set value to a MessageWriter,
173 // no knowledge of the contained type is required.
174 // Implementation provided by specialization.
175 virtual void AppendSetValueToWriter(MessageWriter
* writer
) = 0;
177 // Method used by test and stub implementations of dbus::PropertySet::Set
178 // to replace the property value with the set value without using a
179 // dbus::MessageReader.
180 virtual void ReplaceValueWithSetValue() = 0;
183 // Retrieves the associated property set.
184 PropertySet
* property_set() { return property_set_
; }
187 // Pointer to the PropertySet instance that this instance is a member of,
188 // no ownership is taken and |property_set_| must outlive this class.
189 PropertySet
* property_set_
;
193 // Name of the property.
196 DISALLOW_COPY_AND_ASSIGN(PropertyBase
);
199 // PropertySet groups a collection of properties for a remote object
200 // together into a single structure, fixing their types and name such
201 // that calls made through it are type-safe.
203 // Clients always sub-class this to add the properties, and should always
204 // provide a constructor that chains up to this and then calls
205 // RegisterProperty() for each property defined.
207 // After creation, client code should call ConnectSignals() and most likely
208 // GetAll() to seed initial values and update as changes occur.
209 class CHROME_DBUS_EXPORT PropertySet
{
211 // Callback for changes to cached values of properties, either notified
212 // via signal, or as a result of calls to Get() and GetAll(). The |name|
213 // argument specifies the name of the property changed.
214 typedef base::Callback
<void(const std::string
& name
)> PropertyChangedCallback
;
216 // Constructs a property set, where |object_proxy| specifies the proxy for
217 // the/ remote object that these properties are for, care should be taken to
218 // ensure that this object does not outlive the lifetime of the proxy;
219 // |interface| specifies the D-Bus interface of these properties, and
220 // |property_changed_callback| specifies the callback for when properties
221 // are changed, this may be a NULL callback.
222 PropertySet(ObjectProxy
* object_proxy
, const std::string
& interface
,
223 const PropertyChangedCallback
& property_changed_callback
);
225 // Destructor; we don't hold on to any references or memory that needs
226 // explicit clean-up, but clang thinks we might.
227 virtual ~PropertySet();
229 // Registers a property, generally called from the subclass constructor;
230 // pass the |name| of the property as used in method calls and signals,
231 // and the pointer to the |property| member of the structure. This will
232 // call the PropertyBase::Init method.
233 void RegisterProperty(const std::string
& name
, PropertyBase
* property
);
235 // Connects property change notification signals to the object, generally
236 // called immediately after the object is created and before calls to other
237 // methods. Sub-classes may override to use different D-Bus signals.
238 virtual void ConnectSignals();
240 // Methods connected by ConnectSignals() and called by dbus:: when
241 // a property is changed. Sub-classes may override if the property
242 // changed signal provides different arguments.
243 virtual void ChangedReceived(Signal
* signal
);
244 virtual void ChangedConnected(const std::string
& interface_name
,
245 const std::string
& signal_name
,
248 // Callback for Get() method, |success| indicates whether or not the
249 // value could be retrived, if true the new value can be obtained by
250 // calling value() on the property.
251 typedef base::Callback
<void(bool success
)> GetCallback
;
253 // Requests an updated value from the remote object for |property|
254 // incurring a round-trip. |callback| will be called when the new
255 // value is available. This may not be implemented by some interfaces,
256 // and may be overriden by sub-classes if interfaces use different
258 virtual void Get(PropertyBase
* property
, GetCallback callback
);
259 virtual void OnGet(PropertyBase
* property
, GetCallback callback
,
262 // Queries the remote object for values of all properties and updates
263 // initial values. Sub-classes may override to use a different D-Bus
264 // method, or if the remote object does not support retrieving all
265 // properties, either ignore or obtain each property value individually.
266 virtual void GetAll();
267 virtual void OnGetAll(Response
* response
);
269 // Callback for Set() method, |success| indicates whether or not the
270 // new property value was accepted by the remote object.
271 typedef base::Callback
<void(bool success
)> SetCallback
;
273 // Requests that the remote object for |property| change the property to
274 // its new value. |callback| will be called to indicate the success or
275 // failure of the request, however the new value may not be available
276 // depending on the remote object. This method may be overridden by
277 // sub-classes if interfaces use different method calls.
278 virtual void Set(PropertyBase
* property
, SetCallback callback
);
279 virtual void OnSet(PropertyBase
* property
, SetCallback callback
,
282 // Update properties by reading an array of dictionary entries, each
283 // containing a string with the name and a variant with the value, from
284 // |message_reader|. Returns false if message is in incorrect format.
285 bool UpdatePropertiesFromReader(MessageReader
* reader
);
287 // Updates a single property by reading a string with the name and a
288 // variant with the value from |message_reader|. Returns false if message
289 // is in incorrect format, or property type doesn't match.
290 bool UpdatePropertyFromReader(MessageReader
* reader
);
292 // Calls the property changed callback passed to the constructor, used
293 // by sub-classes that do not call UpdatePropertiesFromReader() or
294 // UpdatePropertyFromReader(). Takes the |name| of the changed property.
295 void NotifyPropertyChanged(const std::string
& name
);
297 // Retrieves the object proxy this property set was initialized with,
298 // provided for sub-classes overriding methods that make D-Bus calls
299 // and for Property<>. Not permitted with const references to this class.
300 ObjectProxy
* object_proxy() { return object_proxy_
; }
302 // Retrieves the interface of this property set.
303 const std::string
& interface() const { return interface_
; }
306 // Get a weak pointer to this property set, provided so that sub-classes
307 // overriding methods that make D-Bus calls may use the existing (or
308 // override) callbacks without providing their own weak pointer factory.
309 base::WeakPtr
<PropertySet
> GetWeakPtr() {
310 return weak_ptr_factory_
.GetWeakPtr();
314 // Invalidates properties by reading an array of names, from
315 // |message_reader|. Returns false if message is in incorrect format.
316 bool InvalidatePropertiesFromReader(MessageReader
* reader
);
318 // Pointer to object proxy for making method calls, no ownership is taken
319 // so this must outlive this class.
320 ObjectProxy
* object_proxy_
;
322 // Interface of property, e.g. "org.chromium.ExampleService", this is
323 // distinct from the interface of the method call itself which is the
324 // general D-Bus Properties interface "org.freedesktop.DBus.Properties".
325 std::string interface_
;
327 // Callback for property changes.
328 PropertyChangedCallback property_changed_callback_
;
330 // Map of properties (as PropertyBase*) defined in the structure to
331 // names as used in D-Bus method calls and signals. The base pointer
332 // restricts property access via this map to type-unsafe and non-specific
334 typedef std::map
<const std::string
, PropertyBase
*> PropertiesMap
;
335 PropertiesMap properties_map_
;
337 // Weak pointer factory as D-Bus callbacks may last longer than these
339 base::WeakPtrFactory
<PropertySet
> weak_ptr_factory_
;
341 DISALLOW_COPY_AND_ASSIGN(PropertySet
);
344 // Property template, this defines the type-specific and type-safe methods
345 // of properties that can be accessed as members of a PropertySet structure.
347 // Properties provide a cached value that has an initial sensible default
348 // until the reply to PropertySet::GetAll() is retrieved and is updated by
349 // all calls to that method, PropertySet::Get() and property changed signals
350 // also handled by PropertySet. It can be obtained by calling value() on the
353 // It is recommended that this cached value be used where necessary, with
354 // code using PropertySet::PropertyChangedCallback to be notified of changes,
355 // rather than incurring a round-trip to the remote object for each property
358 // Where a round-trip is necessary, the Get() method is provided. And to
359 // update the remote object value, the Set() method is also provided; these
360 // both simply call methods on PropertySet.
362 // Handling of particular D-Bus types is performed via specialization,
363 // typically the PopValueFromReader() and AppendSetValueToWriter() methods
364 // will need to be provided, and in rare cases a constructor to provide a
365 // default value. Specializations for basic D-Bus types, strings, object
366 // paths and arrays are provided for you.
368 class CHROME_DBUS_EXPORT Property
: public PropertyBase
{
371 ~Property() override
{}
373 // Retrieves the cached value.
374 const T
& value() const { return value_
; }
376 // Requests an updated value from the remote object incurring a
377 // round-trip. |callback| will be called when the new value is available.
378 // This may not be implemented by some interfaces.
379 virtual void Get(dbus::PropertySet::GetCallback callback
) {
380 property_set()->Get(this, callback
);
383 // Requests that the remote object change the property value to |value|,
384 // |callback| will be called to indicate the success or failure of the
385 // request, however the new value may not be available depending on the
387 virtual void Set(const T
& value
, dbus::PropertySet::SetCallback callback
) {
389 property_set()->Set(this, callback
);
392 // Method used by PropertySet to retrieve the value from a MessageReader,
393 // no knowledge of the contained type is required, this method returns
394 // true if its expected type was found, false if not.
395 bool PopValueFromReader(MessageReader
* reader
) override
;
397 // Method used by PropertySet to append the set value to a MessageWriter,
398 // no knowledge of the contained type is required.
399 // Implementation provided by specialization.
400 void AppendSetValueToWriter(MessageWriter
* writer
) override
;
402 // Method used by test and stub implementations of dbus::PropertySet::Set
403 // to replace the property value with the set value without using a
404 // dbus::MessageReader.
405 void ReplaceValueWithSetValue() override
{
407 property_set()->NotifyPropertyChanged(name());
410 // Method used by test and stub implementations to directly set the
411 // value of a property.
412 void ReplaceValue(const T
& value
) {
414 property_set()->NotifyPropertyChanged(name());
417 // Method used by test and stub implementations to directly set the
418 // |set_value_| of a property.
419 void ReplaceSetValueForTesting(const T
& value
) { set_value_
= value
; }
422 // Current cached value of the property.
425 // Replacement value of the property.
429 // Clang and GCC don't agree on how attributes should work for explicitly
430 // instantiated templates. GCC ignores attributes on explicit instantiations
431 // (and emits a warning) while Clang requires the visiblity attribute on the
432 // explicit instantiations for them to be visible to other compilation units.
433 // Hopefully clang and GCC agree one day, and this can be cleaned up:
434 // https://llvm.org/bugs/show_bug.cgi?id=24815
435 #pragma GCC diagnostic push
436 #pragma GCC diagnostic ignored "-Wattributes"
439 CHROME_DBUS_EXPORT Property
<uint8
>::Property();
441 CHROME_DBUS_EXPORT
bool Property
<uint8
>::PopValueFromReader(
442 MessageReader
* reader
);
444 CHROME_DBUS_EXPORT
void Property
<uint8
>::AppendSetValueToWriter(
445 MessageWriter
* writer
);
446 extern template class CHROME_DBUS_EXPORT Property
<uint8
>;
449 CHROME_DBUS_EXPORT Property
<bool>::Property();
451 CHROME_DBUS_EXPORT
bool Property
<bool>::PopValueFromReader(
452 MessageReader
* reader
);
454 CHROME_DBUS_EXPORT
void Property
<bool>::AppendSetValueToWriter(
455 MessageWriter
* writer
);
456 extern template class CHROME_DBUS_EXPORT Property
<bool>;
459 CHROME_DBUS_EXPORT Property
<int16
>::Property();
461 CHROME_DBUS_EXPORT
bool Property
<int16
>::PopValueFromReader(
462 MessageReader
* reader
);
464 CHROME_DBUS_EXPORT
void Property
<int16
>::AppendSetValueToWriter(
465 MessageWriter
* writer
);
466 extern template class CHROME_DBUS_EXPORT Property
<int16
>;
469 CHROME_DBUS_EXPORT Property
<uint16
>::Property();
471 CHROME_DBUS_EXPORT
bool Property
<uint16
>::PopValueFromReader(
472 MessageReader
* reader
);
474 CHROME_DBUS_EXPORT
void Property
<uint16
>::AppendSetValueToWriter(
475 MessageWriter
* writer
);
476 extern template class CHROME_DBUS_EXPORT Property
<uint16
>;
479 CHROME_DBUS_EXPORT Property
<int32
>::Property();
481 CHROME_DBUS_EXPORT
bool Property
<int32
>::PopValueFromReader(
482 MessageReader
* reader
);
484 CHROME_DBUS_EXPORT
void Property
<int32
>::AppendSetValueToWriter(
485 MessageWriter
* writer
);
486 extern template class CHROME_DBUS_EXPORT Property
<int32
>;
489 CHROME_DBUS_EXPORT Property
<uint32
>::Property();
491 CHROME_DBUS_EXPORT
bool Property
<uint32
>::PopValueFromReader(
492 MessageReader
* reader
);
494 CHROME_DBUS_EXPORT
void Property
<uint32
>::AppendSetValueToWriter(
495 MessageWriter
* writer
);
496 extern template class CHROME_DBUS_EXPORT Property
<uint32
>;
499 CHROME_DBUS_EXPORT Property
<int64
>::Property();
501 CHROME_DBUS_EXPORT
bool Property
<int64
>::PopValueFromReader(
502 MessageReader
* reader
);
504 CHROME_DBUS_EXPORT
void Property
<int64
>::AppendSetValueToWriter(
505 MessageWriter
* writer
);
506 extern template class CHROME_DBUS_EXPORT Property
<int64
>;
509 CHROME_DBUS_EXPORT Property
<uint64
>::Property();
511 CHROME_DBUS_EXPORT
bool Property
<uint64
>::PopValueFromReader(
512 MessageReader
* reader
);
514 CHROME_DBUS_EXPORT
void Property
<uint64
>::AppendSetValueToWriter(
515 MessageWriter
* writer
);
516 extern template class CHROME_DBUS_EXPORT Property
<uint64
>;
519 CHROME_DBUS_EXPORT Property
<double>::Property();
521 CHROME_DBUS_EXPORT
bool Property
<double>::PopValueFromReader(
522 MessageReader
* reader
);
524 CHROME_DBUS_EXPORT
void Property
<double>::AppendSetValueToWriter(
525 MessageWriter
* writer
);
526 extern template class CHROME_DBUS_EXPORT Property
<double>;
529 CHROME_DBUS_EXPORT
bool Property
<std::string
>::PopValueFromReader(
530 MessageReader
* reader
);
532 CHROME_DBUS_EXPORT
void Property
<std::string
>::AppendSetValueToWriter(
533 MessageWriter
* writer
);
534 extern template class CHROME_DBUS_EXPORT Property
<std::string
>;
537 CHROME_DBUS_EXPORT
bool Property
<ObjectPath
>::PopValueFromReader(
538 MessageReader
* reader
);
540 CHROME_DBUS_EXPORT
void Property
<ObjectPath
>::AppendSetValueToWriter(
541 MessageWriter
* writer
);
542 extern template class CHROME_DBUS_EXPORT Property
<ObjectPath
>;
545 CHROME_DBUS_EXPORT
bool Property
<std::vector
<std::string
>>::PopValueFromReader(
546 MessageReader
* reader
);
548 CHROME_DBUS_EXPORT
void Property
<
549 std::vector
<std::string
>>::AppendSetValueToWriter(MessageWriter
* writer
);
550 extern template class CHROME_DBUS_EXPORT Property
<std::vector
<std::string
>>;
553 CHROME_DBUS_EXPORT
bool Property
<std::vector
<ObjectPath
>>::PopValueFromReader(
554 MessageReader
* reader
);
556 CHROME_DBUS_EXPORT
void Property
<
557 std::vector
<ObjectPath
>>::AppendSetValueToWriter(MessageWriter
* writer
);
558 extern template class CHROME_DBUS_EXPORT Property
<std::vector
<ObjectPath
>>;
561 CHROME_DBUS_EXPORT
bool Property
<std::vector
<uint8
>>::PopValueFromReader(
562 MessageReader
* reader
);
564 CHROME_DBUS_EXPORT
void Property
<std::vector
<uint8
>>::AppendSetValueToWriter(
565 MessageWriter
* writer
);
566 extern template class CHROME_DBUS_EXPORT Property
<std::vector
<uint8
>>;
569 CHROME_DBUS_EXPORT
bool
570 Property
<std::map
<std::string
, std::string
>>::PopValueFromReader(
571 MessageReader
* reader
);
573 CHROME_DBUS_EXPORT
void
574 Property
<std::map
<std::string
, std::string
>>::AppendSetValueToWriter(
575 MessageWriter
* writer
);
576 extern template class CHROME_DBUS_EXPORT
577 Property
<std::map
<std::string
, std::string
>>;
580 CHROME_DBUS_EXPORT
bool
581 Property
<std::vector
<std::pair
<std::vector
<uint8_t>, uint16_t>>>::
582 PopValueFromReader(MessageReader
* reader
);
584 CHROME_DBUS_EXPORT
void
585 Property
<std::vector
<std::pair
<std::vector
<uint8_t>, uint16_t>>>::
586 AppendSetValueToWriter(MessageWriter
* writer
);
587 extern template class CHROME_DBUS_EXPORT
588 Property
<std::vector
<std::pair
<std::vector
<uint8_t>, uint16_t>>>;
590 #pragma GCC diagnostic pop
594 #endif // DBUS_PROPERTY_H_