blob: 84dbe2ac97e81a2e6320ec2de7e0d9ef13e93154 [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.
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:
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
Christopher Wiley0ffe3b02014-04-01 17:33:29 -0700126 void WriteSignalForPropertyUpdate(const std::string& interface,
127 const std::string& name,
128 const ExportedPropertyBase* property,
129 dbus::Signal* signal) const;
130
Christopher Wiley639477c2014-03-27 14:49:39 -0700131 dbus::ExportedObject* exported_object_; // weak; owned by the Bus object.
132 // This is a map from interface name -> property name -> pointer to property.
133 std::map<std::string,
134 std::map<std::string, ExportedPropertyBase*>> properties_;
135
136 // D-Bus callbacks may last longer the property set exporting those methods.
137 base::WeakPtrFactory<ExportedPropertySet> weak_ptr_factory_;
138
139 friend class ExportedPropertySetTest;
140 DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet);
141};
142
143template <typename T>
144class ExportedProperty : public ExportedPropertyBase {
145 public:
146 ExportedProperty();
147 virtual ~ExportedProperty() override;
148
149 // Retrieves the current value.
150 const T& value() const;
151
152 // Set the value exposed to remote applications. This triggers notifications
153 // of changes over the Properties interface.
154 void SetValue(const T& new_value);
155
156 // Called by ExportedPropertySet. This update callback triggers
157 // ExportedPropertySet to send a signal from the properties interface of the
158 // exported object.
159 virtual void SetUpdateCallback(const OnUpdateCallback& cb) override;
160
161 // Implementation provided by specialization.
Christopher Wiley0ffe3b02014-04-01 17:33:29 -0700162 virtual void AppendValueToWriter(dbus::MessageWriter* writer) const override;
Christopher Wiley639477c2014-03-27 14:49:39 -0700163
164 private:
165 OnUpdateCallback on_update_;
166 T value_{};
167
168 DISALLOW_COPY_AND_ASSIGN(ExportedProperty);
169};
170
171extern template class ExportedProperty<bool>;
172extern template class ExportedProperty<uint8>;
173extern template class ExportedProperty<int16>;
174extern template class ExportedProperty<uint16>;
175extern template class ExportedProperty<int32>;
176extern template class ExportedProperty<uint32>;
177extern template class ExportedProperty<int64>;
178extern template class ExportedProperty<uint64>;
179extern template class ExportedProperty<double>;
180extern template class ExportedProperty<std::string>;
181extern template class ExportedProperty<dbus::ObjectPath>;
182extern template class ExportedProperty<std::vector<std::string>>;
183extern template class ExportedProperty<std::vector<dbus::ObjectPath>>;
184extern template class ExportedProperty<std::vector<uint8>>;
185
186} // namespace dbus_utils
187
188} // namespace buffet
189
190#endif // BUFFET_EXPORTED_PROPERTY_SET_H_