summaryrefslogtreecommitdiffstats
path: root/dbus/property.cc
diff options
context:
space:
mode:
authorkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-15 04:21:08 +0000
committerkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-15 04:21:08 +0000
commitcf910da2d3cb23ac300968212dc8a196a64b2726 (patch)
treeb7975c349ab6aeccee275e630b2ece900000d387 /dbus/property.cc
parentc401049c2ed235c156292b632f43198c44641b65 (diff)
downloadchromium_src-cf910da2d3cb23ac300968212dc8a196a64b2726.zip
chromium_src-cf910da2d3cb23ac300968212dc8a196a64b2726.tar.gz
chromium_src-cf910da2d3cb23ac300968212dc8a196a64b2726.tar.bz2
dbus: add Property handling for clients
D-Bus properties can be tricky to handle due to their reliance on variants, and since they use a common interface, result in a lot of copy and paste code to deal with. Add an API that simplifies matters somewhat; detailed documentation is in dbus/property.h, but fundamentally you add a struct Properties to the client implementation derived from dbus::PropertySet, and in it declare members of dbus::Property<property type> and connect them in the constructor with RegisterProperty(name, ptr). The API works on two levels, from a higher-level each member of the structure is a type-safe way to obtain the current value of the property, update the value, and set a new value. From the lower-level, it uses a generic reader/writer based interface so that the parent structure's GetAll and signal handling methods can update the values without requiring knowledge of the contained type. BUG=chromium:109194 TEST=unit tests included in CL change-Id: I111b9e60a2c6c35edd9e0ea9f6976928c6c6474b Review URL: http://codereview.chromium.org/9380053 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122039 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus/property.cc')
-rw-r--r--dbus/property.cc425
1 files changed, 425 insertions, 0 deletions
diff --git a/dbus/property.cc b/dbus/property.cc
new file mode 100644
index 0000000..9d2adaf
--- /dev/null
+++ b/dbus/property.cc
@@ -0,0 +1,425 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/property.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/logging.h"
+
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+
+namespace dbus {
+
+//
+// PropertyBase implementation.
+//
+
+void PropertyBase::Init(PropertySet* property_set, const std::string& name) {
+ DCHECK(!property_set_);
+ property_set_ = property_set;
+ name_ = name;
+}
+
+
+//
+// PropertySet implementation.
+//
+
+PropertySet::PropertySet(ObjectProxy* object_proxy,
+ const std::string& interface,
+ PropertyChangedCallback property_changed_callback)
+ : object_proxy_(object_proxy),
+ interface_(interface),
+ property_changed_callback_(property_changed_callback),
+ weak_ptr_factory_(this) {}
+
+PropertySet::~PropertySet() {
+}
+
+void PropertySet::RegisterProperty(const std::string& name,
+ PropertyBase* property) {
+ property->Init(this, name);
+ properties_map_[name] = property;
+}
+
+void PropertySet::ConnectSignals() {
+ DCHECK(object_proxy_);
+ object_proxy_->ConnectToSignal(
+ kPropertiesInterface,
+ kPropertiesChanged,
+ base::Bind(&PropertySet::ChangedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&PropertySet::ChangedConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+
+void PropertySet::ChangedReceived(Signal* signal) {
+ VLOG(1) << "ChangedRecieved";
+ DCHECK(signal);
+
+ MessageReader reader(signal);
+
+ std::string interface;
+ if (!reader.PopString(&interface)) {
+ LOG(WARNING) << "Property changed signal has wrong parameters: "
+ << "expected interface name: " << signal->ToString();
+ return;
+ }
+
+ if (interface != this->interface())
+ return;
+
+ if (!UpdatePropertiesFromReader(&reader)) {
+ LOG(WARNING) << "Property changed signal has wrong parameters: "
+ << "expected dictionary: " << signal->ToString();
+ }
+
+ // TODO(keybuk): dbus properties api has invalidated properties array
+ // on the end, we don't handle this right now because I don't know of
+ // any service that sends it - or what they expect us to do with it.
+ // Add later when we need it.
+}
+
+void PropertySet::ChangedConnected(const std::string& interface_name,
+ const std::string& signal_name,
+ bool success) {
+ LOG_IF(WARNING, !success) << "Failed to connect to " << signal_name
+ << "signal.";
+}
+
+
+void PropertySet::GetAll() {
+ MethodCall method_call(kPropertiesInterface, kPropertiesGetAll);
+ MessageWriter writer(&method_call);
+ writer.AppendString(interface());
+
+ DCHECK(object_proxy_);
+ object_proxy_->CallMethod(&method_call,
+ ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&PropertySet::OnGetAll,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PropertySet::OnGetAll(Response* response) {
+ VLOG(1) << "OnGetAll";
+ if (!response) {
+ LOG(WARNING) << "GetAll request failed.";
+ return;
+ }
+
+ MessageReader reader(response);
+ if (!UpdatePropertiesFromReader(&reader)) {
+ LOG(WARNING) << "GetAll response has wrong parameters: "
+ << "expected dictionary: " << response->ToString();
+ }
+}
+
+
+bool PropertySet::UpdatePropertiesFromReader(MessageReader* reader) {
+ DCHECK(reader);
+ MessageReader array_reader(NULL);
+ if (!reader->PopArray(&array_reader))
+ return false;
+
+ while (array_reader.HasMoreData()) {
+ MessageReader dict_entry_reader(NULL);
+ if (!array_reader.PopDictEntry(&dict_entry_reader))
+ continue;
+
+ if (!UpdatePropertyFromReader(&dict_entry_reader))
+ continue;
+ }
+
+ return true;
+}
+
+bool PropertySet::UpdatePropertyFromReader(MessageReader* reader) {
+ DCHECK(reader);
+
+ std::string name;
+ if (!reader->PopString(&name))
+ return false;
+
+ PropertiesMap::iterator it = properties_map_.find(name);
+ if (it == properties_map_.end())
+ return false;
+
+ PropertyBase* property = it->second;
+ if (property->PopValueFromReader(reader)) {
+ NotifyPropertyChanged(name);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+void PropertySet::NotifyPropertyChanged(const std::string& name) {
+ if (!property_changed_callback_.is_null())
+ property_changed_callback_.Run(name);
+}
+
+//
+// Property<Byte> specialization.
+//
+
+template <>
+Property<uint8>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<uint8>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfByte(&value_);
+}
+
+template <>
+void Property<uint8>::AppendToWriter(MessageWriter* writer,
+ const uint8& value) {
+ writer->AppendVariantOfByte(value);
+}
+
+//
+// Property<bool> specialization.
+//
+
+template <>
+Property<bool>::Property() : value_(false),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<bool>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfBool(&value_);
+}
+
+template <>
+void Property<bool>::AppendToWriter(MessageWriter* writer,
+ const bool& value) {
+ writer->AppendVariantOfBool(value);
+}
+
+//
+// Property<int16> specialization.
+//
+
+template <>
+Property<int16>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<int16>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfInt16(&value_);
+}
+
+template <>
+void Property<int16>::AppendToWriter(MessageWriter* writer,
+ const int16& value) {
+ writer->AppendVariantOfInt16(value);
+}
+
+//
+// Property<uint16> specialization.
+//
+
+template <>
+Property<uint16>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<uint16>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfUint16(&value_);
+}
+
+template <>
+void Property<uint16>::AppendToWriter(MessageWriter* writer,
+ const uint16& value) {
+ writer->AppendVariantOfUint16(value);
+}
+
+//
+// Property<int32> specialization.
+//
+
+template <>
+Property<int32>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<int32>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfInt32(&value_);
+}
+
+template <>
+void Property<int32>::AppendToWriter(MessageWriter* writer,
+ const int32& value) {
+ writer->AppendVariantOfInt32(value);
+}
+
+//
+// Property<uint32> specialization.
+//
+
+template <>
+Property<uint32>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<uint32>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfUint32(&value_);
+}
+
+template <>
+void Property<uint32>::AppendToWriter(MessageWriter* writer,
+ const uint32& value) {
+ writer->AppendVariantOfUint32(value);
+}
+
+//
+// Property<int64> specialization.
+//
+
+template <>
+Property<int64>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<int64>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfInt64(&value_);
+}
+
+template <>
+void Property<int64>::AppendToWriter(MessageWriter* writer,
+ const int64& value) {
+ writer->AppendVariantOfInt64(value);
+}
+
+//
+// Property<uint64> specialization.
+//
+
+template <>
+Property<uint64>::Property() : value_(0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<uint64>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfUint64(&value_);
+}
+
+template <>
+void Property<uint64>::AppendToWriter(MessageWriter* writer,
+ const uint64& value) {
+ writer->AppendVariantOfUint64(value);
+}
+
+//
+// Property<double> specialization.
+//
+
+template <>
+Property<double>::Property() : value_(0.0),
+ weak_ptr_factory_(this) {
+}
+
+template <>
+bool Property<double>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfDouble(&value_);
+}
+
+template <>
+void Property<double>::AppendToWriter(MessageWriter* writer,
+ const double& value) {
+ writer->AppendVariantOfDouble(value);
+}
+
+//
+// Property<std::string> specialization.
+//
+
+template <>
+bool Property<std::string>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfString(&value_);
+}
+
+template <>
+void Property<std::string>::AppendToWriter(MessageWriter* writer,
+ const std::string& value) {
+ writer->AppendVariantOfString(value);
+}
+
+//
+// Property<ObjectPath> specialization.
+//
+
+template <>
+bool Property<ObjectPath>::PopValueFromReader(MessageReader* reader) {
+ return reader->PopVariantOfObjectPath(&value_);
+}
+
+template <>
+void Property<ObjectPath>::AppendToWriter(MessageWriter* writer,
+ const ObjectPath& value) {
+ writer->AppendVariantOfObjectPath(value);
+}
+
+//
+// Property<std::vector<std::string> > specialization.
+//
+
+template <>
+bool Property<std::vector<std::string> >::PopValueFromReader(
+ MessageReader* reader) {
+ MessageReader variant_reader(NULL);
+ if (!reader->PopVariant(&variant_reader))
+ return false;
+
+ return variant_reader.PopArrayOfStrings(&value_);
+}
+
+template <>
+void Property<std::vector<std::string> >::AppendToWriter(
+ MessageWriter* writer,
+ const std::vector<std::string>& value) {
+ MessageWriter variant_writer(NULL);
+ writer->OpenVariant("as", &variant_writer);
+ variant_writer.AppendArrayOfStrings(value);
+ writer->CloseContainer(&variant_writer);
+}
+
+//
+// Property<std::vector<ObjectPath> > specialization.
+//
+
+template <>
+bool Property<std::vector<ObjectPath> >::PopValueFromReader(
+ MessageReader* reader) {
+ MessageReader variant_reader(NULL);
+ if (!reader->PopVariant(&variant_reader))
+ return false;
+
+ return variant_reader.PopArrayOfObjectPaths(&value_);
+}
+
+template <>
+void Property<std::vector<ObjectPath> >::AppendToWriter(
+ MessageWriter* writer,
+ const std::vector<ObjectPath>& value) {
+ MessageWriter variant_writer(NULL);
+ writer->OpenVariant("ao", &variant_writer);
+ variant_writer.AppendArrayOfObjectPaths(value);
+ writer->CloseContainer(&variant_writer);
+}
+
+} // namespace dbus