blob: d91415f4d22236c9a45a5ee2655251e63b034ca2 [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>
Alex Vakulenko33797062014-05-12 15:55:25 -070010#include <vector>
Christopher Wiley639477c2014-03-27 14:49:39 -070011
12#include <base/memory/weak_ptr.h>
13#include <dbus/exported_object.h>
14#include <dbus/message.h>
Christopher Wiley639477c2014-03-27 14:49:39 -070015
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.
Christopher Wiley0ffe3b02014-04-01 17:33:29 -070092 virtual void AppendValueToWriter(dbus::MessageWriter* writer) const = 0;
Christopher Wiley639477c2014-03-27 14:49:39 -070093};
94
95class ExportedPropertySet {
96 public:
Christopher Wiley90016242014-04-01 17:33:29 -070097 typedef base::Callback<void(bool success)> OnInitFinish;
Christopher Wileyadb901d2014-05-07 09:58:45 -070098 typedef base::Callback<void(dbus::MessageWriter* writer)> PropertyWriter;
Christopher Wiley639477c2014-03-27 14:49:39 -070099
Christopher Wiley90016242014-04-01 17:33:29 -0700100 ExportedPropertySet(dbus::Bus* bus, const dbus::ObjectPath& path);
Christopher Wileyadb901d2014-05-07 09:58:45 -0700101 virtual ~ExportedPropertySet() = default;
Christopher Wiley90016242014-04-01 17:33:29 -0700102
103 // Claims the method associated with the org.freedesktop.DBus.Properties
104 // interface. This needs to be done after all properties are initialized to
105 // appropriate values. This method will call |cb| when all methods
106 // are exported to the DBus object. |cb| will be called on the origin
107 // thread.
108 void Init(const OnInitFinish& cb);
Christopher Wileyadb901d2014-05-07 09:58:45 -0700109
110 // Return a callback that knows how to write this property set's properties
111 // to a message. This writer retains a weak pointer to this, and must
112 // only be invoked on the same thread as the rest of ExportedPropertySet.
113 PropertyWriter GetPropertyWriter(const std::string& interface);
Christopher Wiley639477c2014-03-27 14:49:39 -0700114
115 protected:
116 void RegisterProperty(const std::string& interface_name,
117 const std::string& property_name,
118 ExportedPropertyBase* exported_property);
119
120 private:
Christopher Wileycec927c2014-04-15 16:26:47 -0700121 // Used to write the dictionary of string->variant to a message.
122 // This dictionary represents the property name/value pairs for the
123 // given interface.
124 void WritePropertiesDictToMessage(const std::string& interface_name,
125 dbus::MessageWriter* writer);
Christopher Wiley639477c2014-03-27 14:49:39 -0700126 void HandleGetAll(dbus::MethodCall* method_call,
127 dbus::ExportedObject::ResponseSender response_sender);
128 void HandleGet(dbus::MethodCall* method_call,
129 dbus::ExportedObject::ResponseSender response_sender);
130 // While Properties.Set has a handler to complete the interface, we don't
131 // support writable properties. This is almost a feature, since bindings for
132 // many languages don't support errors coming back from invalid writes.
133 // Instead, use setters in exposed interfaces.
134 void HandleSet(dbus::MethodCall* method_call,
135 dbus::ExportedObject::ResponseSender response_sender);
Christopher Wiley90016242014-04-01 17:33:29 -0700136 void HandlePropertyUpdated(const std::string& interface,
137 const std::string& name,
138 const ExportedPropertyBase* property);
Christopher Wiley639477c2014-03-27 14:49:39 -0700139
Christopher Wiley90016242014-04-01 17:33:29 -0700140 dbus::Bus* bus_;
Christopher Wiley639477c2014-03-27 14:49:39 -0700141 dbus::ExportedObject* exported_object_; // weak; owned by the Bus object.
142 // This is a map from interface name -> property name -> pointer to property.
143 std::map<std::string,
144 std::map<std::string, ExportedPropertyBase*>> properties_;
145
146 // D-Bus callbacks may last longer the property set exporting those methods.
147 base::WeakPtrFactory<ExportedPropertySet> weak_ptr_factory_;
148
149 friend class ExportedPropertySetTest;
150 DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet);
151};
152
153template <typename T>
154class ExportedProperty : public ExportedPropertyBase {
155 public:
156 ExportedProperty();
157 virtual ~ExportedProperty() override;
158
159 // Retrieves the current value.
160 const T& value() const;
161
162 // Set the value exposed to remote applications. This triggers notifications
163 // of changes over the Properties interface.
164 void SetValue(const T& new_value);
165
166 // Called by ExportedPropertySet. This update callback triggers
167 // ExportedPropertySet to send a signal from the properties interface of the
168 // exported object.
169 virtual void SetUpdateCallback(const OnUpdateCallback& cb) override;
170
171 // Implementation provided by specialization.
Christopher Wiley0ffe3b02014-04-01 17:33:29 -0700172 virtual void AppendValueToWriter(dbus::MessageWriter* writer) const override;
Christopher Wiley639477c2014-03-27 14:49:39 -0700173
174 private:
175 OnUpdateCallback on_update_;
Alex Vakulenkoa0424dd2014-06-13 16:10:17 -0700176 T value_{};
Christopher Wiley639477c2014-03-27 14:49:39 -0700177
178 DISALLOW_COPY_AND_ASSIGN(ExportedProperty);
179};
180
181extern template class ExportedProperty<bool>;
182extern template class ExportedProperty<uint8>;
183extern template class ExportedProperty<int16>;
184extern template class ExportedProperty<uint16>;
185extern template class ExportedProperty<int32>;
186extern template class ExportedProperty<uint32>;
187extern template class ExportedProperty<int64>;
188extern template class ExportedProperty<uint64>;
189extern template class ExportedProperty<double>;
190extern template class ExportedProperty<std::string>;
191extern template class ExportedProperty<dbus::ObjectPath>;
192extern template class ExportedProperty<std::vector<std::string>>;
193extern template class ExportedProperty<std::vector<dbus::ObjectPath>>;
194extern template class ExportedProperty<std::vector<uint8>>;
195
196} // namespace dbus_utils
197
198} // namespace buffet
199
200#endif // BUFFET_EXPORTED_PROPERTY_SET_H_