libweave: Add more Get methods into weave::Command

Added GetID, GetName, GetCategory, GetStatus, GetOrigin, GetParameters,
GetProgress and GetResults methods.
base::DictionaryValue is used as type for complex values.
D-Bus related utilities extracted from schema_utils.* into
dbus_conversion.* files. They will be move out of libweave in future.

BUG=brillo:1245
TEST='FEATURES=test emerge-gizmo buffet'

Change-Id: Iec16b5a820a0a4da8eeef34b73378b35fdc4e638
Reviewed-on: https://chromium-review.googlesource.com/287594
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/buffet.gyp b/buffet/buffet.gyp
index ca9a11d..ee41d23 100644
--- a/buffet/buffet.gyp
+++ b/buffet/buffet.gyp
@@ -39,6 +39,7 @@
         '../libweave/src/commands/command_queue.cc',
         '../libweave/src/commands/dbus_command_dispatcher.cc',
         '../libweave/src/commands/dbus_command_proxy.cc',
+        '../libweave/src/commands/dbus_conversion.cc',
         '../libweave/src/commands/object_schema.cc',
         '../libweave/src/commands/prop_constraints.cc',
         '../libweave/src/commands/prop_types.cc',
diff --git a/libweave/include/weave/command.h b/libweave/include/weave/command.h
index c27b49d..4a3af6b 100644
--- a/libweave/include/weave/command.h
+++ b/libweave/include/weave/command.h
@@ -5,8 +5,9 @@
 #ifndef LIBWEAVE_INCLUDE_WEAVE_COMMAND_H_
 #define LIBWEAVE_INCLUDE_WEAVE_COMMAND_H_
 
+#include <string>
+
 #include <base/values.h>
-#include <chromeos/errors/error.h>
 
 namespace weave {
 
@@ -23,13 +24,38 @@
     virtual void OnCommandDestroyed() = 0;
   };
 
-  // Returns JSON representation of the command.
-  virtual std::unique_ptr<base::DictionaryValue> ToJson() const = 0;
-
   // Adds an observer for this command. The observer object is not owned by this
   // class.
   virtual void AddObserver(Observer* observer) = 0;
 
+  // Returns the full command ID.
+  virtual const std::string& GetID() const = 0;
+
+  // Returns the full name of the command.
+  virtual const std::string& GetName() const = 0;
+
+  // Returns the command category.
+  virtual const std::string& GetCategory() const = 0;
+
+  // Returns the command status.
+  // TODO(vitalybuka): Status should be enum.
+  virtual const std::string& GetStatus() const = 0;
+
+  // Returns the origin of the command.
+  virtual const std::string& GetOrigin() const = 0;
+
+  // Returns the command parameters.
+  virtual std::unique_ptr<base::DictionaryValue> GetParameters() const = 0;
+
+  // Returns the command progress.
+  virtual std::unique_ptr<base::DictionaryValue> GetProgress() const = 0;
+
+  // Returns the command results.
+  virtual std::unique_ptr<base::DictionaryValue> GetResults() const = 0;
+
+  // Returns JSON representation of the command.
+  virtual std::unique_ptr<base::DictionaryValue> ToJson() const = 0;
+
  protected:
   virtual ~Command() = default;
 };
diff --git a/libweave/src/base_api_handler.cc b/libweave/src/base_api_handler.cc
index e6f9f9c..5e3f559 100644
--- a/libweave/src/base_api_handler.cc
+++ b/libweave/src/base_api_handler.cc
@@ -11,43 +11,6 @@
 
 namespace weave {
 
-namespace {
-
-// Helps to get parameters from ValueMap representing
-// CommandInstance parameters.
-class ParametersReader final {
- public:
-  explicit ParametersReader(const ValueMap* parameters)
-      : parameters_{parameters} {}
-
-  bool GetParameter(const std::string& name, std::string* value) const {
-    auto it = parameters_->find(name);
-    if (it == parameters_->end())
-      return false;
-    const StringValue* string_value = it->second->GetString();
-    if (!string_value)
-      return false;
-    *value = string_value->GetValue();
-    return true;
-  }
-
-  bool GetParameter(const std::string& name, bool* value) const {
-    auto it = parameters_->find(name);
-    if (it == parameters_->end())
-      return false;
-    const BooleanValue* bool_value = it->second->GetBoolean();
-    if (!bool_value)
-      return false;
-    *value = bool_value->GetValue();
-    return true;
-  }
-
- private:
-  const ValueMap* parameters_;
-};
-
-}  // namespace
-
 BaseApiHandler::BaseApiHandler(
     const base::WeakPtr<DeviceRegistrationInfo>& device_info,
     const std::shared_ptr<StateManager>& state_manager,
@@ -76,11 +39,10 @@
   bool discovery_enabled{config.local_discovery_enabled()};
   bool pairing_enabled{config.local_pairing_enabled()};
 
-  ParametersReader parameters{&command->GetParameters()};
-  parameters.GetParameter("localAnonymousAccessMaxRole",
-                          &anonymous_access_role);
-  parameters.GetParameter("localDiscoveryEnabled", &discovery_enabled);
-  parameters.GetParameter("localPairingEnabled", &pairing_enabled);
+  auto parameters = command->GetParameters();
+  parameters->GetString("localAnonymousAccessMaxRole", &anonymous_access_role);
+  parameters->GetBoolean("localDiscoveryEnabled", &discovery_enabled);
+  parameters->GetBoolean("localPairingEnabled", &pairing_enabled);
 
   chromeos::VariantDictionary state{
       {"base.localAnonymousAccessMaxRole", anonymous_access_role},
@@ -107,10 +69,10 @@
   std::string description{config.description()};
   std::string location{config.location()};
 
-  ParametersReader parameters(&command->GetParameters());
-  parameters.GetParameter("name", &name);
-  parameters.GetParameter("description", &description);
-  parameters.GetParameter("location", &location);
+  auto parameters = command->GetParameters();
+  parameters->GetString("name", &name);
+  parameters->GetString("description", &description);
+  parameters->GetString("location", &location);
 
   if (!device_info_->UpdateDeviceInfo(name, description, location, nullptr)) {
     return command->Abort();
diff --git a/libweave/src/commands/cloud_command_proxy.cc b/libweave/src/commands/cloud_command_proxy.cc
index cc4d64f..70430c7 100644
--- a/libweave/src/commands/cloud_command_proxy.cc
+++ b/libweave/src/commands/cloud_command_proxy.cc
@@ -31,8 +31,8 @@
 
 void CloudCommandProxy::OnResultsChanged() {
   std::unique_ptr<base::DictionaryValue> patch{new base::DictionaryValue};
-  auto json = TypedValueToJson(command_instance_->GetResults(), nullptr);
-  patch->Set(commands::attributes::kCommand_Results, json.release());
+  patch->Set(commands::attributes::kCommand_Results,
+             command_instance_->GetResults().release());
   QueueCommandUpdate(std::move(patch));
 }
 
@@ -45,8 +45,8 @@
 
 void CloudCommandProxy::OnProgressChanged() {
   std::unique_ptr<base::DictionaryValue> patch{new base::DictionaryValue};
-  auto json = TypedValueToJson(command_instance_->GetProgress(), nullptr);
-  patch->Set(commands::attributes::kCommand_Progress, json.release());
+  patch->Set(commands::attributes::kCommand_Progress,
+             command_instance_->GetProgress().release());
   QueueCommandUpdate(std::move(patch));
 }
 
diff --git a/libweave/src/commands/command_instance.cc b/libweave/src/commands/command_instance.cc
index 2975937..5782695 100644
--- a/libweave/src/commands/command_instance.cc
+++ b/libweave/src/commands/command_instance.cc
@@ -42,13 +42,36 @@
     observer->OnCommandDestroyed();
 }
 
+const std::string& CommandInstance::GetID() const {
+  return id_;
+}
+
+const std::string& CommandInstance::GetName() const {
+  return name_;
+}
+
 const std::string& CommandInstance::GetCategory() const {
   return command_definition_->GetCategory();
 }
 
-const PropValue* CommandInstance::FindParameter(const std::string& name) const {
-  auto p = parameters_.find(name);
-  return (p != parameters_.end()) ? p->second.get() : nullptr;
+const std::string& CommandInstance::GetStatus() const {
+  return status_;
+}
+
+const std::string& CommandInstance::GetOrigin() const {
+  return origin_;
+}
+
+std::unique_ptr<base::DictionaryValue> CommandInstance::GetParameters() const {
+  return TypedValueToJson(parameters_, nullptr);
+}
+
+std::unique_ptr<base::DictionaryValue> CommandInstance::GetProgress() const {
+  return TypedValueToJson(progress_, nullptr);
+}
+
+std::unique_ptr<base::DictionaryValue> CommandInstance::GetResults() const {
+  return TypedValueToJson(results_, nullptr);
 }
 
 namespace {
diff --git a/libweave/src/commands/command_instance.h b/libweave/src/commands/command_instance.h
index 358cd52..0fdc643 100644
--- a/libweave/src/commands/command_instance.h
+++ b/libweave/src/commands/command_instance.h
@@ -42,22 +42,14 @@
   // Command overrides.
   std::unique_ptr<base::DictionaryValue> ToJson() const override;
   void AddObserver(Observer* observer) override;
-
-  // Returns the full command ID.
-  const std::string& GetID() const { return id_; }
-  // Returns the full name of the command.
-  const std::string& GetName() const { return name_; }
-  // Returns the command category.
-  const std::string& GetCategory() const;
-  // Returns the command parameters and their values.
-  const ValueMap& GetParameters() const { return parameters_; }
-  // Returns the command results and their values.
-  const ValueMap& GetResults() const { return results_; }
-  // Finds a command parameter value by parameter |name|. If the parameter
-  // with given name does not exist, returns nullptr.
-  const PropValue* FindParameter(const std::string& name) const;
-  // Returns the full name of the command.
-  const std::string& GetOrigin() const { return origin_; }
+  const std::string& GetID() const override;
+  const std::string& GetName() const override;
+  const std::string& GetCategory() const override;
+  const std::string& GetStatus() const override;
+  const std::string& GetOrigin() const override;
+  std::unique_ptr<base::DictionaryValue> GetParameters() const override;
+  std::unique_ptr<base::DictionaryValue> GetProgress() const override;
+  std::unique_ptr<base::DictionaryValue> GetResults() const override;
 
   // Returns command definition.
   const CommandDefinition* GetCommandDefinition() const {
@@ -100,10 +92,6 @@
   // Marks the command as completed successfully.
   void Done();
 
-  // Command state getters.
-  const ValueMap& GetProgress() const { return progress_; }
-  const std::string& GetStatus() const { return status_; }
-
   // Values for command execution status.
   static const char kStatusQueued[];
   static const char kStatusInProgress[];
diff --git a/libweave/src/commands/command_instance_unittest.cc b/libweave/src/commands/command_instance_unittest.cc
index 9d2c019..9fbe315 100644
--- a/libweave/src/commands/command_instance_unittest.cc
+++ b/libweave/src/commands/command_instance_unittest.cc
@@ -85,12 +85,9 @@
   EXPECT_EQ("robot.speak", instance.GetName());
   EXPECT_EQ("robotd", instance.GetCategory());
   EXPECT_EQ("cloud", instance.GetOrigin());
-  EXPECT_EQ(params, instance.GetParameters());
-  EXPECT_EQ("iPityDaFool",
-            instance.FindParameter("phrase")->GetString()->GetValue());
-  EXPECT_EQ(5, instance.FindParameter("volume")->GetInt()->GetValue());
-  EXPECT_EQ(nullptr, instance.FindParameter("blah"));
-  EXPECT_EQ(results, instance.GetResults());
+  EXPECT_JSON_EQ("{'phrase': 'iPityDaFool', 'volume': 5}",
+                 *instance.GetParameters());
+  EXPECT_JSON_EQ("{'foo': 239}", *instance.GetResults());
 
   CommandInstance instance2{
       "base.reboot", "local", dict_.FindCommand("base.reboot"), {}};
@@ -121,9 +118,8 @@
   EXPECT_EQ("abcd", instance->GetID());
   EXPECT_EQ("robot.jump", instance->GetName());
   EXPECT_EQ("robotd", instance->GetCategory());
-  EXPECT_EQ(53, instance->FindParameter("height")->GetInt()->GetValue());
-  EXPECT_EQ("_withKick",
-            instance->FindParameter("_jumpType")->GetString()->GetValue());
+  EXPECT_JSON_EQ("{'height': 53, '_jumpType': '_withKick'}",
+                 *instance->GetParameters());
 }
 
 TEST_F(CommandInstanceTest, FromJson_ParamsOmitted) {
@@ -132,7 +128,7 @@
       CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, nullptr);
   EXPECT_EQ("base.reboot", instance->GetName());
   EXPECT_EQ("robotd", instance->GetCategory());
-  EXPECT_TRUE(instance->GetParameters().empty());
+  EXPECT_JSON_EQ("{}", *instance->GetParameters());
 }
 
 TEST_F(CommandInstanceTest, FromJson_NotObject) {
diff --git a/libweave/src/commands/dbus_command_dispatcher_unittest.cc b/libweave/src/commands/dbus_command_dispatcher_unittest.cc
index c488d92..b91d24f 100644
--- a/libweave/src/commands/dbus_command_dispatcher_unittest.cc
+++ b/libweave/src/commands/dbus_command_dispatcher_unittest.cc
@@ -148,7 +148,7 @@
   ValueMap progress{{"progress", unittests::make_int_prop_value(50)}};
   SetProgress(command_proxy, progress);
   EXPECT_EQ(CommandInstance::kStatusInProgress, command_instance->GetStatus());
-  EXPECT_EQ(progress, command_instance->GetProgress());
+  EXPECT_JSON_EQ("{'progress': 50}", *command_instance->GetProgress());
 
   // Command must be removed from the queue and proxy destroyed after calling
   // FinishCommand().
@@ -183,7 +183,7 @@
   ValueMap progress{};
   SetProgress(command_proxy, progress);
   EXPECT_EQ(CommandInstance::kStatusInProgress, command_instance->GetStatus());
-  EXPECT_EQ(progress, command_instance->GetProgress());
+  EXPECT_JSON_EQ("{}", *command_instance->GetProgress());
 
   // Command must be removed from the queue and proxy destroyed after calling
   // FinishCommand().
diff --git a/libweave/src/commands/dbus_command_proxy.cc b/libweave/src/commands/dbus_command_proxy.cc
index 5ffcd9d..aadf781 100644
--- a/libweave/src/commands/dbus_command_proxy.cc
+++ b/libweave/src/commands/dbus_command_proxy.cc
@@ -36,13 +36,12 @@
   dbus_adaptor_.SetId(command_instance_->GetID());
   dbus_adaptor_.SetStatus(command_instance_->GetStatus());
   dbus_adaptor_.SetProgress(
-      ObjectToDBusVariant(command_instance_->GetProgress()));
+      DictionaryToDBusVariantDictionary(*command_instance_->GetProgress()));
   dbus_adaptor_.SetOrigin(command_instance_->GetOrigin());
-
   dbus_adaptor_.SetParameters(
-      ObjectToDBusVariant(command_instance_->GetParameters()));
+      DictionaryToDBusVariantDictionary(*command_instance_->GetParameters()));
   dbus_adaptor_.SetResults(
-      ObjectToDBusVariant(command_instance_->GetResults()));
+      DictionaryToDBusVariantDictionary(*command_instance_->GetResults()));
 
   // Register the command DBus object and expose its methods and properties.
   dbus_object_.RegisterAsync(completion_callback);
@@ -50,7 +49,7 @@
 
 void DBusCommandProxy::OnResultsChanged() {
   dbus_adaptor_.SetResults(
-      ObjectToDBusVariant(command_instance_->GetResults()));
+      DictionaryToDBusVariantDictionary(*command_instance_->GetResults()));
 }
 
 void DBusCommandProxy::OnStatusChanged() {
@@ -59,7 +58,7 @@
 
 void DBusCommandProxy::OnProgressChanged() {
   dbus_adaptor_.SetProgress(
-      ObjectToDBusVariant(command_instance_->GetProgress()));
+      DictionaryToDBusVariantDictionary(*command_instance_->GetProgress()));
 }
 
 void DBusCommandProxy::OnCommandDestroyed() {
diff --git a/libweave/src/commands/dbus_command_proxy_unittest.cc b/libweave/src/commands/dbus_command_proxy_unittest.cc
index ed51387..a289cad 100644
--- a/libweave/src/commands/dbus_command_proxy_unittest.cc
+++ b/libweave/src/commands/dbus_command_proxy_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <functional>
 #include <memory>
+#include <vector>
 
 #include <dbus/mock_bus.h>
 #include <dbus/mock_exported_object.h>
@@ -70,6 +71,12 @@
             },
             'bar': {
               'type': 'string'
+            },
+            'resultList': {
+              'type': 'array',
+              'items': {
+                'type': 'integer'
+              }
             }
           },
           'progress': {
@@ -177,11 +184,25 @@
 
 TEST_F(DBusCommandProxyTest, SetResults) {
   EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
-  const VariantDictionary results = {
-      {"foo", int32_t{42}}, {"bar", std::string{"foobar"}},
-  };
+  VariantDictionary results = {{"foo", int32_t{42}},
+                               {"bar", std::string{"foobar"}},
+                               {"resultList", std::vector<int>{1, 2, 3}}};
   EXPECT_TRUE(GetCommandInterface()->SetResults(nullptr, results));
   EXPECT_EQ(results, GetCommandAdaptor()->GetResults());
+  auto list = chromeos::GetVariantValueOrDefault<std::vector<int>>(
+      GetCommandAdaptor()->GetResults(), "resultList");
+  EXPECT_EQ((std::vector<int>{1, 2, 3}), list);
+}
+
+TEST_F(DBusCommandProxyTest, SetResults_WithEmptyList) {
+  EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
+  VariantDictionary results = {{"foo", int32_t{42}},
+                               {"bar", std::string{"foobar"}},
+                               {"resultList", std::vector<int>{}}};
+  EXPECT_TRUE(GetCommandInterface()->SetResults(nullptr, results));
+  auto list = chromeos::GetVariantValueOrDefault<std::vector<int>>(
+      GetCommandAdaptor()->GetResults(), "resultList");
+  EXPECT_EQ(std::vector<int>(), list);
 }
 
 TEST_F(DBusCommandProxyTest, SetResults_UnknownProperty) {
diff --git a/libweave/src/commands/dbus_conversion.cc b/libweave/src/commands/dbus_conversion.cc
new file mode 100644
index 0000000..146a46d
--- /dev/null
+++ b/libweave/src/commands/dbus_conversion.cc
@@ -0,0 +1,243 @@
+// Copyright 2015 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.
+
+#include "libweave/src/commands/dbus_conversion.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "libweave/src/commands/object_schema.h"
+#include "libweave/src/commands/prop_types.h"
+#include "libweave/src/commands/prop_values.h"
+
+namespace weave {
+
+namespace {
+
+// Helpers for JsonToAny().
+template <typename T>
+chromeos::Any ValueToAny(const base::Value& json,
+                         bool (base::Value::*fnc)(T*) const) {
+  T val;
+  CHECK((json.*fnc)(&val));
+  return val;
+}
+
+template <typename T>
+chromeos::Any ListToAny(const base::ListValue& list);
+
+// Converts a JSON value into an Any so it can be sent over D-Bus using
+// UpdateState D-Bus method from Buffet.
+chromeos::Any ValueToAny(const base::Value& json) {
+  chromeos::Any prop_value;
+  switch (json.GetType()) {
+    case base::Value::TYPE_NULL:
+      prop_value = nullptr;
+      break;
+    case base::Value::TYPE_BOOLEAN:
+      prop_value = ValueToAny<bool>(json, &base::Value::GetAsBoolean);
+      break;
+    case base::Value::TYPE_INTEGER:
+      prop_value = ValueToAny<int>(json, &base::Value::GetAsInteger);
+      break;
+    case base::Value::TYPE_DOUBLE:
+      prop_value = ValueToAny<double>(json, &base::Value::GetAsDouble);
+      break;
+    case base::Value::TYPE_STRING:
+      prop_value = ValueToAny<std::string>(json, &base::Value::GetAsString);
+      break;
+    case base::Value::TYPE_BINARY:
+      LOG(FATAL) << "Binary values should not happen";
+      break;
+    case base::Value::TYPE_DICTIONARY: {
+      const base::DictionaryValue* dict = nullptr;
+      CHECK(json.GetAsDictionary(&dict));
+      prop_value = DictionaryToDBusVariantDictionary(*dict);
+      break;
+    }
+    case base::Value::TYPE_LIST: {
+      const base::ListValue* list = nullptr;
+      CHECK(json.GetAsList(&list));
+      if (list->empty()) {
+        prop_value = ListToAny<chromeos::Any>(*list);
+        break;
+      }
+      auto type = (*list->begin())->GetType();
+      for (const base::Value* v : *list)
+        CHECK_EQ(v->GetType(), type);
+
+      switch (type) {
+        case base::Value::TYPE_BOOLEAN:
+          prop_value = ListToAny<bool>(*list);
+          break;
+        case base::Value::TYPE_INTEGER:
+          prop_value = ListToAny<int>(*list);
+          break;
+        case base::Value::TYPE_DOUBLE:
+          prop_value = ListToAny<double>(*list);
+          break;
+        case base::Value::TYPE_STRING:
+          prop_value = ListToAny<std::string>(*list);
+          break;
+        case base::Value::TYPE_DICTIONARY:
+          prop_value = ListToAny<chromeos::VariantDictionary>(*list);
+          break;
+        default:
+          LOG(FATAL) << "Unsupported JSON value type for list element: "
+                     << (*list->begin())->GetType();
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected JSON value type: " << json.GetType();
+      break;
+  }
+  return prop_value;
+}
+
+template <typename T>
+chromeos::Any ListToAny(const base::ListValue& list) {
+  std::vector<T> val;
+  val.reserve(list.GetSize());
+  for (const base::Value* v : list)
+    val.push_back(ValueToAny(*v).Get<T>());
+  return val;
+}
+
+bool ErrorMissingProperty(chromeos::ErrorPtr* error,
+                          const tracked_objects::Location& location,
+                          const char* param_name) {
+  chromeos::Error::AddToPrintf(error, location, errors::commands::kDomain,
+                               errors::commands::kPropertyMissing,
+                               "Required parameter missing: %s", param_name);
+  return false;
+}
+
+}  // namespace
+
+chromeos::Any PropValueToDBusVariant(const PropValue* value) {
+  if (value->GetType() == ValueType::Object)
+    return ObjectToDBusVariant(value->GetObject()->GetValue());
+
+  if (value->GetType() == ValueType::Array) {
+    const PropType* item_type =
+        value->GetPropType()->GetArray()->GetItemTypePtr();
+    return item_type->ConvertArrayToDBusVariant(value->GetArray()->GetValue());
+  }
+  return value->GetValueAsAny();
+}
+
+chromeos::VariantDictionary ObjectToDBusVariant(const ValueMap& object) {
+  chromeos::VariantDictionary dict;
+  for (const auto& pair : object) {
+    // Since we are inserting the elements from ValueMap which is
+    // a map, the keys are already sorted. So use the "end()" position as a hint
+    // for dict.insert() so the destination map can optimize its insertion
+    // time.
+    chromeos::Any prop = PropValueToDBusVariant(pair.second.get());
+    dict.emplace_hint(dict.end(), pair.first, std::move(prop));
+  }
+  return dict;
+}
+
+std::unique_ptr<const PropValue> PropValueFromDBusVariant(
+    const PropType* type,
+    const chromeos::Any& value,
+    chromeos::ErrorPtr* error) {
+  std::unique_ptr<const PropValue> result;
+  if (type->GetType() == ValueType::Array) {
+    // Special case for array types.
+    // We expect the |value| to contain std::vector<T>, while PropValue must use
+    // ValueVector instead. Do the conversion.
+    ValueVector arr;
+    const PropType* item_type = type->GetArray()->GetItemTypePtr();
+    if (item_type->ConvertDBusVariantToArray(value, &arr, error))
+      result = type->CreateValue(arr, error);
+  } else if (type->GetType() == ValueType::Object) {
+    // Special case for object types.
+    // We expect the |value| to contain chromeos::VariantDictionary, while
+    // PropValue must use ValueMap instead. Do the conversion.
+    if (!value.IsTypeCompatible<chromeos::VariantDictionary>()) {
+      type->GenerateErrorValueTypeMismatch(error);
+      return result;
+    }
+    CHECK(nullptr != type->GetObject()->GetObjectSchemaPtr())
+        << "An object type must have a schema defined for it";
+    ValueMap obj;
+    if (!ObjectFromDBusVariant(type->GetObject()->GetObjectSchemaPtr(),
+                               value.Get<chromeos::VariantDictionary>(), &obj,
+                               error)) {
+      return result;
+    }
+
+    result = type->CreateValue(std::move(obj), error);
+  } else {
+    result = type->CreateValue(value, error);
+  }
+
+  return result;
+}
+
+bool ObjectFromDBusVariant(const ObjectSchema* object_schema,
+                           const chromeos::VariantDictionary& dict,
+                           ValueMap* obj,
+                           chromeos::ErrorPtr* error) {
+  std::set<std::string> keys_processed;
+  obj->clear();
+  // First go over all object parameters defined by type's object schema and
+  // extract the corresponding parameters from the source dictionary.
+  for (const auto& pair : object_schema->GetProps()) {
+    const PropValue* def_value = pair.second->GetDefaultValue();
+    auto it = dict.find(pair.first);
+    if (it != dict.end()) {
+      const PropType* prop_type = pair.second.get();
+      CHECK(prop_type) << "Value property type must be available";
+      auto prop_value = PropValueFromDBusVariant(prop_type, it->second, error);
+      if (!prop_value) {
+        chromeos::Error::AddToPrintf(
+            error, FROM_HERE, errors::commands::kDomain,
+            errors::commands::kInvalidPropValue,
+            "Invalid value for property '%s'", pair.first.c_str());
+        return false;
+      }
+      obj->emplace_hint(obj->end(), pair.first, std::move(prop_value));
+    } else if (def_value) {
+      obj->emplace_hint(obj->end(), pair.first, def_value->Clone());
+    } else {
+      ErrorMissingProperty(error, FROM_HERE, pair.first.c_str());
+      return false;
+    }
+    keys_processed.insert(pair.first);
+  }
+
+  // Make sure that we processed all the necessary properties and there weren't
+  // any extra (unknown) ones specified, unless the schema allows them.
+  if (!object_schema->GetExtraPropertiesAllowed()) {
+    for (const auto& pair : dict) {
+      if (keys_processed.find(pair.first) == keys_processed.end()) {
+        chromeos::Error::AddToPrintf(
+            error, FROM_HERE, errors::commands::kDomain,
+            errors::commands::kUnknownProperty, "Unrecognized property '%s'",
+            pair.first.c_str());
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+// TODO(vitalybuka): Use in buffet_client.
+chromeos::VariantDictionary DictionaryToDBusVariantDictionary(
+    const base::DictionaryValue& object) {
+  chromeos::VariantDictionary result;
+
+  for (base::DictionaryValue::Iterator it(object); !it.IsAtEnd(); it.Advance())
+    result.emplace(it.key(), ValueToAny(it.value()));
+
+  return result;
+}
+
+}  // namespace weave
diff --git a/libweave/src/commands/dbus_conversion.h b/libweave/src/commands/dbus_conversion.h
new file mode 100644
index 0000000..ab49f70
--- /dev/null
+++ b/libweave/src/commands/dbus_conversion.h
@@ -0,0 +1,46 @@
+// Copyright 2015 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 LIBWEAVE_SRC_COMMANDS_DBUS_CONVERSION_H_
+#define LIBWEAVE_SRC_COMMANDS_DBUS_CONVERSION_H_
+
+#include <base/values.h>
+#include <chromeos/any.h>
+#include <chromeos/errors/error.h>
+#include <chromeos/variant_dictionary.h>
+
+#include "libweave/src/commands/schema_utils.h"
+
+namespace weave {
+
+// Converts PropValue to Any in a format understood by D-Bus data serialization.
+// Has special handling for Object types where ValueMap are
+// converted to chromeos::VariantDictionary.
+chromeos::Any PropValueToDBusVariant(const PropValue* value);
+
+// Converts ValueMap to chromeos::VariantDictionary
+// with proper conversion of all nested properties.
+chromeos::VariantDictionary ObjectToDBusVariant(const ValueMap& object);
+
+// Converts D-Bus variant to PropValue.
+// Has special handling for Object types where chromeos::VariantDictionary
+// is converted to ValueMap.
+std::unique_ptr<const PropValue> PropValueFromDBusVariant(
+    const PropType* type,
+    const chromeos::Any& value,
+    chromeos::ErrorPtr* error);
+
+// Converts D-Bus variant to ObjectValue.
+bool ObjectFromDBusVariant(const ObjectSchema* object_schema,
+                           const chromeos::VariantDictionary& dict,
+                           ValueMap* obj,
+                           chromeos::ErrorPtr* error);
+
+// Converts DictionaryValue to D-Bus variant dictionary.
+chromeos::VariantDictionary DictionaryToDBusVariantDictionary(
+    const base::DictionaryValue& object);
+
+}  // namespace weave
+
+#endif  // LIBWEAVE_SRC_COMMANDS_DBUS_CONVERSION_H_
diff --git a/libweave/src/commands/prop_types.h b/libweave/src/commands/prop_types.h
index 7a2e695..09420f1 100644
--- a/libweave/src/commands/prop_types.h
+++ b/libweave/src/commands/prop_types.h
@@ -16,6 +16,7 @@
 #include <chromeos/any.h>
 #include <chromeos/errors/error.h>
 
+#include "libweave/src/commands/dbus_conversion.h"
 #include "libweave/src/commands/prop_constraints.h"
 #include "libweave/src/commands/prop_values.h"
 
diff --git a/libweave/src/commands/schema_utils.cc b/libweave/src/commands/schema_utils.cc
index ecfd4da..a171109 100644
--- a/libweave/src/commands/schema_utils.cc
+++ b/libweave/src/commands/schema_utils.cc
@@ -51,6 +51,7 @@
                                "Required parameter missing: %s", param_name);
   return false;
 }
+
 }  // namespace
 
 // Specializations of TypedValueToJson<T>() for supported C++ types.
@@ -276,116 +277,4 @@
   return str;
 }
 
-chromeos::Any PropValueToDBusVariant(const PropValue* value) {
-  if (value->GetType() == ValueType::Object)
-    return ObjectToDBusVariant(value->GetObject()->GetValue());
-
-  if (value->GetType() == ValueType::Array) {
-    const PropType* item_type =
-        value->GetPropType()->GetArray()->GetItemTypePtr();
-    return item_type->ConvertArrayToDBusVariant(value->GetArray()->GetValue());
-  }
-  return value->GetValueAsAny();
-}
-
-chromeos::VariantDictionary ObjectToDBusVariant(const ValueMap& object) {
-  chromeos::VariantDictionary dict;
-  for (const auto& pair : object) {
-    // Since we are inserting the elements from ValueMap which is
-    // a map, the keys are already sorted. So use the "end()" position as a hint
-    // for dict.insert() so the destination map can optimize its insertion
-    // time.
-    chromeos::Any prop = PropValueToDBusVariant(pair.second.get());
-    dict.emplace_hint(dict.end(), pair.first, std::move(prop));
-  }
-  return dict;
-}
-
-std::unique_ptr<const PropValue> PropValueFromDBusVariant(
-    const PropType* type,
-    const chromeos::Any& value,
-    chromeos::ErrorPtr* error) {
-  std::unique_ptr<const PropValue> result;
-  if (type->GetType() == ValueType::Array) {
-    // Special case for array types.
-    // We expect the |value| to contain std::vector<T>, while PropValue must use
-    // ValueVector instead. Do the conversion.
-    ValueVector arr;
-    const PropType* item_type = type->GetArray()->GetItemTypePtr();
-    if (item_type->ConvertDBusVariantToArray(value, &arr, error))
-      result = type->CreateValue(arr, error);
-  } else if (type->GetType() == ValueType::Object) {
-    // Special case for object types.
-    // We expect the |value| to contain chromeos::VariantDictionary, while
-    // PropValue must use ValueMap instead. Do the conversion.
-    if (!value.IsTypeCompatible<chromeos::VariantDictionary>()) {
-      type->GenerateErrorValueTypeMismatch(error);
-      return result;
-    }
-    CHECK(nullptr != type->GetObject()->GetObjectSchemaPtr())
-        << "An object type must have a schema defined for it";
-    ValueMap obj;
-    if (!ObjectFromDBusVariant(type->GetObject()->GetObjectSchemaPtr(),
-                               value.Get<chromeos::VariantDictionary>(), &obj,
-                               error)) {
-      return result;
-    }
-
-    result = type->CreateValue(std::move(obj), error);
-  } else {
-    result = type->CreateValue(value, error);
-  }
-
-  return result;
-}
-
-bool ObjectFromDBusVariant(const ObjectSchema* object_schema,
-                           const chromeos::VariantDictionary& dict,
-                           ValueMap* obj,
-                           chromeos::ErrorPtr* error) {
-  std::set<std::string> keys_processed;
-  obj->clear();
-  // First go over all object parameters defined by type's object schema and
-  // extract the corresponding parameters from the source dictionary.
-  for (const auto& pair : object_schema->GetProps()) {
-    const PropValue* def_value = pair.second->GetDefaultValue();
-    auto it = dict.find(pair.first);
-    if (it != dict.end()) {
-      const PropType* prop_type = pair.second.get();
-      CHECK(prop_type) << "Value property type must be available";
-      auto prop_value = PropValueFromDBusVariant(prop_type, it->second, error);
-      if (!prop_value) {
-        chromeos::Error::AddToPrintf(
-            error, FROM_HERE, errors::commands::kDomain,
-            errors::commands::kInvalidPropValue,
-            "Invalid value for property '%s'", pair.first.c_str());
-        return false;
-      }
-      obj->emplace_hint(obj->end(), pair.first, std::move(prop_value));
-    } else if (def_value) {
-      obj->emplace_hint(obj->end(), pair.first, def_value->Clone());
-    } else {
-      ErrorMissingProperty(error, FROM_HERE, pair.first.c_str());
-      return false;
-    }
-    keys_processed.insert(pair.first);
-  }
-
-  // Make sure that we processed all the necessary properties and there weren't
-  // any extra (unknown) ones specified, unless the schema allows them.
-  if (!object_schema->GetExtraPropertiesAllowed()) {
-    for (const auto& pair : dict) {
-      if (keys_processed.find(pair.first) == keys_processed.end()) {
-        chromeos::Error::AddToPrintf(
-            error, FROM_HERE, errors::commands::kDomain,
-            errors::commands::kUnknownProperty, "Unrecognized property '%s'",
-            pair.first.c_str());
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
 }  // namespace weave
diff --git a/libweave/src/commands/schema_utils.h b/libweave/src/commands/schema_utils.h
index e2efbe3..6d1b342 100644
--- a/libweave/src/commands/schema_utils.h
+++ b/libweave/src/commands/schema_utils.h
@@ -13,9 +13,7 @@
 #include <vector>
 
 #include <base/values.h>
-#include <chromeos/any.h>
 #include <chromeos/errors/error.h>
-#include <chromeos/variant_dictionary.h>
 
 namespace weave {
 
@@ -139,26 +137,6 @@
   return std::abs(v1 - v2) <= std::numeric_limits<T>::epsilon();
 }
 
-// Converts PropValue to Any in a format understood by D-Bus data serialization.
-// Has special handling for Object types where ValueMap are
-// converted to chromeos::VariantDictionary.
-chromeos::Any PropValueToDBusVariant(const PropValue* value);
-// Converts ValueMap to chromeos::VariantDictionary
-// with proper conversion of all nested properties.
-chromeos::VariantDictionary ObjectToDBusVariant(const ValueMap& object);
-// Converts D-Bus variant to PropValue.
-// Has special handling for Object types where chromeos::VariantDictionary
-// is converted to ValueMap.
-std::unique_ptr<const PropValue> PropValueFromDBusVariant(
-    const PropType* type,
-    const chromeos::Any& value,
-    chromeos::ErrorPtr* error);
-// Converts D-Bus variant to ObjectValue.
-bool ObjectFromDBusVariant(const ObjectSchema* object_schema,
-                           const chromeos::VariantDictionary& dict,
-                           ValueMap* obj,
-                           chromeos::ErrorPtr* error);
-
 }  // namespace weave
 
 #endif  // LIBWEAVE_SRC_COMMANDS_SCHEMA_UTILS_H_