blob: 7ed9d9bf55c1dba8007c954233bbaca7a01365c9 [file] [log] [blame]
Christopher Wiley639477c2014-03-27 14:49:39 -07001// Copyright 2014 The Chromium OS 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 BUFFET_EXPORTED_PROPERTY_SET_H_
6#define BUFFET_EXPORTED_PROPERTY_SET_H_
7
8#include <map>
9#include <string>
10
11#include <base/memory/weak_ptr.h>
12#include <dbus/exported_object.h>
13#include <dbus/message.h>
14#include <gtest/gtest_prod.h>
15
16namespace buffet {
17
18namespace dbus_utils {
19
20// This class may be used to implement the org.freedesktop.DBus.Properties
21// interface. It sends the update signal on property updates:
22//
23// org.freedesktop.DBus.Properties.PropertiesChanged (
24// STRING interface_name,
25// DICT<STRING,VARIANT> changed_properties,
26// ARRAY<STRING> invalidated_properties);
27//
28//
29// and implements the required methods of the interface:
30//
31// org.freedesktop.DBus.Properties.Get(in STRING interface_name,
32// in STRING property_name,
33// out VARIANT value);
34// org.freedesktop.DBus.Properties.Set(in STRING interface_name,
35// in STRING property_name,
36// in VARIANT value);
37// org.freedesktop.DBus.Properties.GetAll(in STRING interface_name,
38// out DICT<STRING,VARIANT> props);
39//
40// This class is very similar to the PropertySet class in Chrome, except that
41// it allows objects to expose properties rather than to consume them.
42//
43// Example usage:
44//
45// class ExampleObjectExportingProperties {
46// public:
47// ExampleObjectExportingProperties(ExportedObject* exported_object)
48// : p_(exported_object) {
49// // Initialize properties appropriately. Do this before
50// // claiming the Properties interface so that daemons watching
51// // this object don't see partial or inaccurate state.
52// p_.ClaimPropertiesInterface();
53// }
54//
55// private:
56// struct Properties : public buffet::dbus::ExportedPropertySet {
57// public:
58// buffet::dbus::ExportedProperty<std::string> name_;
59// buffet::dbus::ExportedProperty<uint16> version_;
60// buffet::dbus::ExportedProperty<dbus::ObjectPath> parent_;
61// buffet::dbus::ExportedProperty<std::vector<std::string>> children_;
62//
63// Properties(dbus::ExportedObject* exported_object)
64// : buffet::dbus::ExportedPropertySet(exported_object) {
65// RegisterProperty(kExampleInterfaceName, "Name", &name_);
66// RegisterProperty(kExampleInterfaceName, "Version", &version_);
67// RegisterProperty(kExampleInterfaceName, "Parent", &parent_);
68// RegisterProperty(kExampleInterfaceName, "Children", &children_);
69// }
70// virtual ~Properties() {}
71// };
72//
73// Properties p_;
74// };
75
76class ExportedPropertyBase {
77 public:
78 ExportedPropertyBase() {}
79 virtual ~ExportedPropertyBase() {}
80
81 typedef base::Callback<void(const ExportedPropertyBase*)> OnUpdateCallback;
82
83 // Called by ExportedPropertySet to register a callback. This callback
84 // triggers ExportedPropertySet to send a signal from the properties
85 // interface of the exported object.
86 virtual void SetUpdateCallback(const OnUpdateCallback& cb) = 0;
87
88 // Appends a variant of the contained value to the writer. This is
89 // needed to write out properties to Get and GetAll methods implemented
90 // by the ExportedPropertySet since it doesn't actually know the type
91 // of each property.
92 virtual void AppendValueToWriter(dbus::MessageWriter* writer) = 0;
93};
94
95class ExportedPropertySet {
96 public:
97 ExportedPropertySet(dbus::ExportedObject* exported_object);
98 ~ExportedPropertySet();
99
100 // Claims the org.freedesktop.DBus.Properties interface. This
101 // needs to be done after all properties are initialized to
102 // appropriate values.
103 void ClaimPropertiesInterface();
104
105 protected:
106 void RegisterProperty(const std::string& interface_name,
107 const std::string& property_name,
108 ExportedPropertyBase* exported_property);
109
110 private:
111 void HandleGetAll(dbus::MethodCall* method_call,
112 dbus::ExportedObject::ResponseSender response_sender);
113 void HandleGet(dbus::MethodCall* method_call,
114 dbus::ExportedObject::ResponseSender response_sender);
115 // While Properties.Set has a handler to complete the interface, we don't
116 // support writable properties. This is almost a feature, since bindings for
117 // many languages don't support errors coming back from invalid writes.
118 // Instead, use setters in exposed interfaces.
119 void HandleSet(dbus::MethodCall* method_call,
120 dbus::ExportedObject::ResponseSender response_sender);
121
122 virtual void HandlePropertyUpdated(const std::string& interface,
123 const std::string& name,
124 const ExportedPropertyBase* property);
125
126 dbus::ExportedObject* exported_object_; // weak; owned by the Bus object.
127 // This is a map from interface name -> property name -> pointer to property.
128 std::map<std::string,
129 std::map<std::string, ExportedPropertyBase*>> properties_;
130
131 // D-Bus callbacks may last longer the property set exporting those methods.
132 base::WeakPtrFactory<ExportedPropertySet> weak_ptr_factory_;
133
134 friend class ExportedPropertySetTest;
135 DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet);
136};
137
138template <typename T>
139class ExportedProperty : public ExportedPropertyBase {
140 public:
141 ExportedProperty();
142 virtual ~ExportedProperty() override;
143
144 // Retrieves the current value.
145 const T& value() const;
146
147 // Set the value exposed to remote applications. This triggers notifications
148 // of changes over the Properties interface.
149 void SetValue(const T& new_value);
150
151 // Called by ExportedPropertySet. This update callback triggers
152 // ExportedPropertySet to send a signal from the properties interface of the
153 // exported object.
154 virtual void SetUpdateCallback(const OnUpdateCallback& cb) override;
155
156 // Implementation provided by specialization.
157 virtual void AppendValueToWriter(dbus::MessageWriter* writer) override;
158
159 private:
160 OnUpdateCallback on_update_;
161 T value_{};
162
163 DISALLOW_COPY_AND_ASSIGN(ExportedProperty);
164};
165
166extern template class ExportedProperty<bool>;
167extern template class ExportedProperty<uint8>;
168extern template class ExportedProperty<int16>;
169extern template class ExportedProperty<uint16>;
170extern template class ExportedProperty<int32>;
171extern template class ExportedProperty<uint32>;
172extern template class ExportedProperty<int64>;
173extern template class ExportedProperty<uint64>;
174extern template class ExportedProperty<double>;
175extern template class ExportedProperty<std::string>;
176extern template class ExportedProperty<dbus::ObjectPath>;
177extern template class ExportedProperty<std::vector<std::string>>;
178extern template class ExportedProperty<std::vector<dbus::ObjectPath>>;
179extern template class ExportedProperty<std::vector<uint8>>;
180
181} // namespace dbus_utils
182
183} // namespace buffet
184
185#endif // BUFFET_EXPORTED_PROPERTY_SET_H_