buffet: Add ExportedPropertySet delegate
This object makes it easy to export an org.freedesktop.DBus.Properties
interface.
BUG=chromium:356368
TEST=When integrated with the Manager, this correctly exposes
properties. This can be tested with buffet_BasicDBusAPI.
Change-Id: I6c871ebbd225b6305ca9d4a309fb7b47ed305f9b
Reviewed-on: https://chromium-review.googlesource.com/192001
Tested-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Christopher Wiley <wiley@chromium.org>
diff --git a/buffet/exported_property_set.h b/buffet/exported_property_set.h
new file mode 100644
index 0000000..7ed9d9b
--- /dev/null
+++ b/buffet/exported_property_set.h
@@ -0,0 +1,185 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BUFFET_EXPORTED_PROPERTY_SET_H_
+#define BUFFET_EXPORTED_PROPERTY_SET_H_
+
+#include <map>
+#include <string>
+
+#include <base/memory/weak_ptr.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <gtest/gtest_prod.h>
+
+namespace buffet {
+
+namespace dbus_utils {
+
+// This class may be used to implement the org.freedesktop.DBus.Properties
+// interface. It sends the update signal on property updates:
+//
+// org.freedesktop.DBus.Properties.PropertiesChanged (
+// STRING interface_name,
+// DICT<STRING,VARIANT> changed_properties,
+// ARRAY<STRING> invalidated_properties);
+//
+//
+// and implements the required methods of the interface:
+//
+// org.freedesktop.DBus.Properties.Get(in STRING interface_name,
+// in STRING property_name,
+// out VARIANT value);
+// org.freedesktop.DBus.Properties.Set(in STRING interface_name,
+// in STRING property_name,
+// in VARIANT value);
+// org.freedesktop.DBus.Properties.GetAll(in STRING interface_name,
+// out DICT<STRING,VARIANT> props);
+//
+// This class is very similar to the PropertySet class in Chrome, except that
+// it allows objects to expose properties rather than to consume them.
+//
+// Example usage:
+//
+// class ExampleObjectExportingProperties {
+// public:
+// ExampleObjectExportingProperties(ExportedObject* exported_object)
+// : p_(exported_object) {
+// // Initialize properties appropriately. Do this before
+// // claiming the Properties interface so that daemons watching
+// // this object don't see partial or inaccurate state.
+// p_.ClaimPropertiesInterface();
+// }
+//
+// private:
+// struct Properties : public buffet::dbus::ExportedPropertySet {
+// public:
+// buffet::dbus::ExportedProperty<std::string> name_;
+// buffet::dbus::ExportedProperty<uint16> version_;
+// buffet::dbus::ExportedProperty<dbus::ObjectPath> parent_;
+// buffet::dbus::ExportedProperty<std::vector<std::string>> children_;
+//
+// Properties(dbus::ExportedObject* exported_object)
+// : buffet::dbus::ExportedPropertySet(exported_object) {
+// RegisterProperty(kExampleInterfaceName, "Name", &name_);
+// RegisterProperty(kExampleInterfaceName, "Version", &version_);
+// RegisterProperty(kExampleInterfaceName, "Parent", &parent_);
+// RegisterProperty(kExampleInterfaceName, "Children", &children_);
+// }
+// virtual ~Properties() {}
+// };
+//
+// Properties p_;
+// };
+
+class ExportedPropertyBase {
+ public:
+ ExportedPropertyBase() {}
+ virtual ~ExportedPropertyBase() {}
+
+ typedef base::Callback<void(const ExportedPropertyBase*)> OnUpdateCallback;
+
+ // Called by ExportedPropertySet to register a callback. This callback
+ // triggers ExportedPropertySet to send a signal from the properties
+ // interface of the exported object.
+ virtual void SetUpdateCallback(const OnUpdateCallback& cb) = 0;
+
+ // Appends a variant of the contained value to the writer. This is
+ // needed to write out properties to Get and GetAll methods implemented
+ // by the ExportedPropertySet since it doesn't actually know the type
+ // of each property.
+ virtual void AppendValueToWriter(dbus::MessageWriter* writer) = 0;
+};
+
+class ExportedPropertySet {
+ public:
+ ExportedPropertySet(dbus::ExportedObject* exported_object);
+ ~ExportedPropertySet();
+
+ // Claims the org.freedesktop.DBus.Properties interface. This
+ // needs to be done after all properties are initialized to
+ // appropriate values.
+ void ClaimPropertiesInterface();
+
+ protected:
+ void RegisterProperty(const std::string& interface_name,
+ const std::string& property_name,
+ ExportedPropertyBase* exported_property);
+
+ private:
+ void HandleGetAll(dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender);
+ void HandleGet(dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender);
+ // While Properties.Set has a handler to complete the interface, we don't
+ // support writable properties. This is almost a feature, since bindings for
+ // many languages don't support errors coming back from invalid writes.
+ // Instead, use setters in exposed interfaces.
+ void HandleSet(dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender);
+
+ virtual void HandlePropertyUpdated(const std::string& interface,
+ const std::string& name,
+ const ExportedPropertyBase* property);
+
+ dbus::ExportedObject* exported_object_; // weak; owned by the Bus object.
+ // This is a map from interface name -> property name -> pointer to property.
+ std::map<std::string,
+ std::map<std::string, ExportedPropertyBase*>> properties_;
+
+ // D-Bus callbacks may last longer the property set exporting those methods.
+ base::WeakPtrFactory<ExportedPropertySet> weak_ptr_factory_;
+
+ friend class ExportedPropertySetTest;
+ DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet);
+};
+
+template <typename T>
+class ExportedProperty : public ExportedPropertyBase {
+ public:
+ ExportedProperty();
+ virtual ~ExportedProperty() override;
+
+ // Retrieves the current value.
+ const T& value() const;
+
+ // Set the value exposed to remote applications. This triggers notifications
+ // of changes over the Properties interface.
+ void SetValue(const T& new_value);
+
+ // Called by ExportedPropertySet. This update callback triggers
+ // ExportedPropertySet to send a signal from the properties interface of the
+ // exported object.
+ virtual void SetUpdateCallback(const OnUpdateCallback& cb) override;
+
+ // Implementation provided by specialization.
+ virtual void AppendValueToWriter(dbus::MessageWriter* writer) override;
+
+ private:
+ OnUpdateCallback on_update_;
+ T value_{};
+
+ DISALLOW_COPY_AND_ASSIGN(ExportedProperty);
+};
+
+extern template class ExportedProperty<bool>;
+extern template class ExportedProperty<uint8>;
+extern template class ExportedProperty<int16>;
+extern template class ExportedProperty<uint16>;
+extern template class ExportedProperty<int32>;
+extern template class ExportedProperty<uint32>;
+extern template class ExportedProperty<int64>;
+extern template class ExportedProperty<uint64>;
+extern template class ExportedProperty<double>;
+extern template class ExportedProperty<std::string>;
+extern template class ExportedProperty<dbus::ObjectPath>;
+extern template class ExportedProperty<std::vector<std::string>>;
+extern template class ExportedProperty<std::vector<dbus::ObjectPath>>;
+extern template class ExportedProperty<std::vector<uint8>>;
+
+} // namespace dbus_utils
+
+} // namespace buffet
+
+#endif // BUFFET_EXPORTED_PROPERTY_SET_H_