Material PDF: Add required Polymer 0.8 elements.
[chromium-blink-merge.git] / dbus / property.h
blob321f4dbd078c945fd2d9b98df04b033a349142ad
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_
8 #include <map>
9 #include <string>
10 #include <utility>
11 #include <vector>
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
25 // possible.
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.
34 // Example:
35 // class ExampleClient {
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;
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);
50 // }
51 // virtual ~Properties() {}
52 // };
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;
68 // }
70 // Properties* GetProperties(const dbus::ObjectPath& object_path) {
71 // return GetObject(object_path).second;
72 // }
74 // Object GetObject(const dbus::ObjectPath& object_path) {
75 // ObjectMap::iterator it = object_map_.find(object_path);
76 // if (it != object_map_.end())
77 // return it->second;
79 // dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(...);
80 // // connect signals, etc.
82 // Properties* properties = new Properties(
83 // object_proxy,
84 // base::Bind(&PropertyChanged,
85 // weak_ptr_factory_.GetWeakPtr(),
86 // object_path));
87 // properties->ConnectSignals();
88 // properties->GetAll();
90 // Object object = std::make_pair(object_proxy, properties);
91 // object_map_[object_path] = object;
92 // return object;
93 // }
94 // };
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
108 // value() method.
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))
119 namespace dbus {
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";
129 class PropertySet;
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 PropertyBase {
136 public:
137 PropertyBase() : property_set_(nullptr), is_valid_(false) {}
139 // Initializes the |property_set| and property |name| so that method
140 // calls may be made from this class. This method is called by
141 // PropertySet::RegisterProperty() passing |this| for |property_set| so
142 // there should be no need to call it directly. If you do beware that
143 // no ownership or reference to |property_set| is taken so that object
144 // must outlive this one.
145 void Init(PropertySet* property_set, const std::string& name);
147 // Retrieves the name of this property, this may be useful in observers
148 // to avoid specifying the name in more than once place, e.g.
150 // void Client::PropertyChanged(const dbus::ObjectPath& object_path,
151 // const std::string &property_name) {
152 // Properties& properties = GetProperties(object_path);
153 // if (property_name == properties.version.name()) {
154 // // Handle version property changing
155 // }
156 // }
157 const std::string& name() const { return name_; }
159 // Returns true if property is valid, false otherwise.
160 bool is_valid() const { return is_valid_; }
162 // Allows to mark Property as valid or invalid.
163 void set_valid(bool is_valid) { is_valid_ = is_valid; }
165 // Method used by PropertySet to retrieve the value from a MessageReader,
166 // no knowledge of the contained type is required, this method returns
167 // true if its expected type was found, false if not.
168 // Implementation provided by specialization.
169 virtual bool PopValueFromReader(MessageReader* reader) = 0;
171 // Method used by PropertySet to append the set value to a MessageWriter,
172 // no knowledge of the contained type is required.
173 // Implementation provided by specialization.
174 virtual void AppendSetValueToWriter(MessageWriter* writer) = 0;
176 // Method used by test and stub implementations of dbus::PropertySet::Set
177 // to replace the property value with the set value without using a
178 // dbus::MessageReader.
179 virtual void ReplaceValueWithSetValue() = 0;
181 protected:
182 // Retrieves the associated property set.
183 PropertySet* property_set() { return property_set_; }
185 private:
186 // Pointer to the PropertySet instance that this instance is a member of,
187 // no ownership is taken and |property_set_| must outlive this class.
188 PropertySet* property_set_;
190 bool is_valid_;
192 // Name of the property.
193 std::string name_;
195 DISALLOW_COPY_AND_ASSIGN(PropertyBase);
198 // PropertySet groups a collection of properties for a remote object
199 // together into a single structure, fixing their types and name such
200 // that calls made through it are type-safe.
202 // Clients always sub-class this to add the properties, and should always
203 // provide a constructor that chains up to this and then calls
204 // RegisterProperty() for each property defined.
206 // After creation, client code should call ConnectSignals() and most likely
207 // GetAll() to seed initial values and update as changes occur.
208 class CHROME_DBUS_EXPORT PropertySet {
209 public:
210 // Callback for changes to cached values of properties, either notified
211 // via signal, or as a result of calls to Get() and GetAll(). The |name|
212 // argument specifies the name of the property changed.
213 typedef base::Callback<void(const std::string& name)> PropertyChangedCallback;
215 // Constructs a property set, where |object_proxy| specifies the proxy for
216 // the/ remote object that these properties are for, care should be taken to
217 // ensure that this object does not outlive the lifetime of the proxy;
218 // |interface| specifies the D-Bus interface of these properties, and
219 // |property_changed_callback| specifies the callback for when properties
220 // are changed, this may be a NULL callback.
221 PropertySet(ObjectProxy* object_proxy, const std::string& interface,
222 const PropertyChangedCallback& property_changed_callback);
224 // Destructor; we don't hold on to any references or memory that needs
225 // explicit clean-up, but clang thinks we might.
226 virtual ~PropertySet();
228 // Registers a property, generally called from the subclass constructor;
229 // pass the |name| of the property as used in method calls and signals,
230 // and the pointer to the |property| member of the structure. This will
231 // call the PropertyBase::Init method.
232 void RegisterProperty(const std::string& name, PropertyBase* property);
234 // Connects property change notification signals to the object, generally
235 // called immediately after the object is created and before calls to other
236 // methods. Sub-classes may override to use different D-Bus signals.
237 virtual void ConnectSignals();
239 // Methods connected by ConnectSignals() and called by dbus:: when
240 // a property is changed. Sub-classes may override if the property
241 // changed signal provides different arguments.
242 virtual void ChangedReceived(Signal* signal);
243 virtual void ChangedConnected(const std::string& interface_name,
244 const std::string& signal_name,
245 bool success);
247 // Callback for Get() method, |success| indicates whether or not the
248 // value could be retrived, if true the new value can be obtained by
249 // calling value() on the property.
250 typedef base::Callback<void(bool success)> GetCallback;
252 // Requests an updated value from the remote object for |property|
253 // incurring a round-trip. |callback| will be called when the new
254 // value is available. This may not be implemented by some interfaces,
255 // and may be overriden by sub-classes if interfaces use different
256 // method calls.
257 virtual void Get(PropertyBase* property, GetCallback callback);
258 virtual void OnGet(PropertyBase* property, GetCallback callback,
259 Response* response);
261 // Queries the remote object for values of all properties and updates
262 // initial values. Sub-classes may override to use a different D-Bus
263 // method, or if the remote object does not support retrieving all
264 // properties, either ignore or obtain each property value individually.
265 virtual void GetAll();
266 virtual void OnGetAll(Response* response);
268 // Callback for Set() method, |success| indicates whether or not the
269 // new property value was accepted by the remote object.
270 typedef base::Callback<void(bool success)> SetCallback;
272 // Requests that the remote object for |property| change the property to
273 // its new value. |callback| will be called to indicate the success or
274 // failure of the request, however the new value may not be available
275 // depending on the remote object. This method may be overridden by
276 // sub-classes if interfaces use different method calls.
277 virtual void Set(PropertyBase* property, SetCallback callback);
278 virtual void OnSet(PropertyBase* property, SetCallback callback,
279 Response* response);
281 // Update properties by reading an array of dictionary entries, each
282 // containing a string with the name and a variant with the value, from
283 // |message_reader|. Returns false if message is in incorrect format.
284 bool UpdatePropertiesFromReader(MessageReader* reader);
286 // Updates a single property by reading a string with the name and a
287 // variant with the value from |message_reader|. Returns false if message
288 // is in incorrect format, or property type doesn't match.
289 bool UpdatePropertyFromReader(MessageReader* reader);
291 // Calls the property changed callback passed to the constructor, used
292 // by sub-classes that do not call UpdatePropertiesFromReader() or
293 // UpdatePropertyFromReader(). Takes the |name| of the changed property.
294 void NotifyPropertyChanged(const std::string& name);
296 // Retrieves the object proxy this property set was initialized with,
297 // provided for sub-classes overriding methods that make D-Bus calls
298 // and for Property<>. Not permitted with const references to this class.
299 ObjectProxy* object_proxy() { return object_proxy_; }
301 // Retrieves the interface of this property set.
302 const std::string& interface() const { return interface_; }
304 protected:
305 // Get a weak pointer to this property set, provided so that sub-classes
306 // overriding methods that make D-Bus calls may use the existing (or
307 // override) callbacks without providing their own weak pointer factory.
308 base::WeakPtr<PropertySet> GetWeakPtr() {
309 return weak_ptr_factory_.GetWeakPtr();
312 private:
313 // Invalidates properties by reading an array of names, from
314 // |message_reader|. Returns false if message is in incorrect format.
315 bool InvalidatePropertiesFromReader(MessageReader* reader);
317 // Pointer to object proxy for making method calls, no ownership is taken
318 // so this must outlive this class.
319 ObjectProxy* object_proxy_;
321 // Interface of property, e.g. "org.chromium.ExampleService", this is
322 // distinct from the interface of the method call itself which is the
323 // general D-Bus Properties interface "org.freedesktop.DBus.Properties".
324 std::string interface_;
326 // Callback for property changes.
327 PropertyChangedCallback property_changed_callback_;
329 // Map of properties (as PropertyBase*) defined in the structure to
330 // names as used in D-Bus method calls and signals. The base pointer
331 // restricts property access via this map to type-unsafe and non-specific
332 // actions only.
333 typedef std::map<const std::string, PropertyBase*> PropertiesMap;
334 PropertiesMap properties_map_;
336 // Weak pointer factory as D-Bus callbacks may last longer than these
337 // objects.
338 base::WeakPtrFactory<PropertySet> weak_ptr_factory_;
340 DISALLOW_COPY_AND_ASSIGN(PropertySet);
343 // Property template, this defines the type-specific and type-safe methods
344 // of properties that can be accessed as members of a PropertySet structure.
346 // Properties provide a cached value that has an initial sensible default
347 // until the reply to PropertySet::GetAll() is retrieved and is updated by
348 // all calls to that method, PropertySet::Get() and property changed signals
349 // also handled by PropertySet. It can be obtained by calling value() on the
350 // property.
352 // It is recommended that this cached value be used where necessary, with
353 // code using PropertySet::PropertyChangedCallback to be notified of changes,
354 // rather than incurring a round-trip to the remote object for each property
355 // access.
357 // Where a round-trip is necessary, the Get() method is provided. And to
358 // update the remote object value, the Set() method is also provided; these
359 // both simply call methods on PropertySet.
361 // Handling of particular D-Bus types is performed via specialization,
362 // typically the PopValueFromReader() and AppendSetValueToWriter() methods
363 // will need to be provided, and in rare cases a constructor to provide a
364 // default value. Specializations for basic D-Bus types, strings, object
365 // paths and arrays are provided for you.
366 template <class T>
367 class CHROME_DBUS_EXPORT Property : public PropertyBase {
368 public:
369 Property() {}
371 // Retrieves the cached value.
372 const T& value() const { return value_; }
374 // Requests an updated value from the remote object incurring a
375 // round-trip. |callback| will be called when the new value is available.
376 // This may not be implemented by some interfaces.
377 virtual void Get(dbus::PropertySet::GetCallback callback) {
378 property_set()->Get(this, callback);
381 // Requests that the remote object change the property value to |value|,
382 // |callback| will be called to indicate the success or failure of the
383 // request, however the new value may not be available depending on the
384 // remote object.
385 virtual void Set(const T& value, dbus::PropertySet::SetCallback callback) {
386 set_value_ = value;
387 property_set()->Set(this, callback);
390 // Method used by PropertySet to retrieve the value from a MessageReader,
391 // no knowledge of the contained type is required, this method returns
392 // true if its expected type was found, false if not.
393 bool PopValueFromReader(MessageReader* reader) override;
395 // Method used by PropertySet to append the set value to a MessageWriter,
396 // no knowledge of the contained type is required.
397 // Implementation provided by specialization.
398 void AppendSetValueToWriter(MessageWriter* writer) override;
400 // Method used by test and stub implementations of dbus::PropertySet::Set
401 // to replace the property value with the set value without using a
402 // dbus::MessageReader.
403 void ReplaceValueWithSetValue() override {
404 value_ = set_value_;
405 property_set()->NotifyPropertyChanged(name());
408 // Method used by test and stub implementations to directly set the
409 // value of a property.
410 void ReplaceValue(const T& value) {
411 value_ = value;
412 property_set()->NotifyPropertyChanged(name());
415 // Method used by test and stub implementations to directly set the
416 // |set_value_| of a property.
417 void ReplaceSetValueForTesting(const T& value) { set_value_ = value; }
419 private:
420 // Current cached value of the property.
421 T value_;
423 // Replacement value of the property.
424 T set_value_;
427 template <> Property<uint8>::Property();
428 template <> bool Property<uint8>::PopValueFromReader(MessageReader* reader);
429 template <> void Property<uint8>::AppendSetValueToWriter(MessageWriter* writer);
430 extern template class Property<uint8>;
432 template <> Property<bool>::Property();
433 template <> bool Property<bool>::PopValueFromReader(MessageReader* reader);
434 template <> void Property<bool>::AppendSetValueToWriter(MessageWriter* writer);
435 extern template class Property<bool>;
437 template <> Property<int16>::Property();
438 template <> bool Property<int16>::PopValueFromReader(MessageReader* reader);
439 template <> void Property<int16>::AppendSetValueToWriter(MessageWriter* writer);
440 extern template class Property<int16>;
442 template <> Property<uint16>::Property();
443 template <> bool Property<uint16>::PopValueFromReader(MessageReader* reader);
444 template <> void Property<uint16>::AppendSetValueToWriter(
445 MessageWriter* writer);
446 extern template class Property<uint16>;
448 template <> Property<int32>::Property();
449 template <> bool Property<int32>::PopValueFromReader(MessageReader* reader);
450 template <> void Property<int32>::AppendSetValueToWriter(MessageWriter* writer);
451 extern template class Property<int32>;
453 template <> Property<uint32>::Property();
454 template <> bool Property<uint32>::PopValueFromReader(MessageReader* reader);
455 template <> void Property<uint32>::AppendSetValueToWriter(
456 MessageWriter* writer);
457 extern template class Property<uint32>;
459 template <> Property<int64>::Property();
460 template <> bool Property<int64>::PopValueFromReader(MessageReader* reader);
461 template <> void Property<int64>::AppendSetValueToWriter(MessageWriter* writer);
462 extern template class Property<int64>;
464 template <> Property<uint64>::Property();
465 template <> bool Property<uint64>::PopValueFromReader(MessageReader* reader);
466 template <> void Property<uint64>::AppendSetValueToWriter(
467 MessageWriter* writer);
468 extern template class Property<uint64>;
470 template <> Property<double>::Property();
471 template <> bool Property<double>::PopValueFromReader(MessageReader* reader);
472 template <> void Property<double>::AppendSetValueToWriter(
473 MessageWriter* writer);
474 extern template class Property<double>;
476 template <> bool Property<std::string>::PopValueFromReader(
477 MessageReader* reader);
478 template <> void Property<std::string>::AppendSetValueToWriter(
479 MessageWriter* writer);
480 extern template class Property<std::string>;
482 template <> bool Property<ObjectPath>::PopValueFromReader(
483 MessageReader* reader);
484 template <> void Property<ObjectPath>::AppendSetValueToWriter(
485 MessageWriter* writer);
486 extern template class Property<ObjectPath>;
488 template <> bool Property<std::vector<std::string> >::PopValueFromReader(
489 MessageReader* reader);
490 template <> void Property<std::vector<std::string> >::AppendSetValueToWriter(
491 MessageWriter* writer);
492 extern template class Property<std::vector<std::string> >;
494 template <> bool Property<std::vector<ObjectPath> >::PopValueFromReader(
495 MessageReader* reader);
496 template <> void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
497 MessageWriter* writer);
498 extern template class Property<std::vector<ObjectPath> >;
500 template <> bool Property<std::vector<uint8> >::PopValueFromReader(
501 MessageReader* reader);
502 template <> void Property<std::vector<uint8> >::AppendSetValueToWriter(
503 MessageWriter* writer);
504 extern template class Property<std::vector<uint8> >;
506 template <>
507 bool Property<std::map<std::string, std::string>>::PopValueFromReader(
508 MessageReader* reader);
509 template <>
510 void Property<std::map<std::string, std::string>>::AppendSetValueToWriter(
511 MessageWriter* writer);
512 extern template class Property<std::map<std::string, std::string>>;
514 template <>
515 bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
516 PopValueFromReader(MessageReader* reader);
517 template <>
518 void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
519 AppendSetValueToWriter(MessageWriter* writer);
520 extern template class Property<
521 std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
523 } // namespace dbus
525 #endif // DBUS_PROPERTY_H_