Load state and commands definition by calling methods of device

This allows to have dynamic state and commands expansion and calls
can be places near command handlers code.

BUG:24267885
Change-Id: I1777b321cface7c081258fa62eec272a8a173dc8
Reviewed-on: https://weave-review.googlesource.com/1252
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/libweave/examples/ubuntu/file_config_store.cc b/libweave/examples/ubuntu/file_config_store.cc
index c59de56..b1bb17a 100644
--- a/libweave/examples/ubuntu/file_config_store.cc
+++ b/libweave/examples/ubuntu/file_config_store.cc
@@ -60,48 +60,5 @@
   str << settings;
 }
 
-std::vector<std::string> FileConfigStore::LoadCommandDefs() {
-  return {R"({
-    "base": {
-      "updateBaseConfiguration": {},
-      "identify": {},
-      "updateDeviceInfo": {}
-    },
-    "_greeter": {
-      "_greet": {
-        "minimalRole": "user",
-        "parameters": { "_name": "string"},
-        "results": { "_greeting": "string" }
-      }
-    },
-    "_ledflasher": {
-       "_set":{
-         "parameters": {
-           "_led": {"minimum": 1, "maximum": 3},
-           "_on": "boolean"
-         }
-       },
-       "_toggle":{
-         "parameters": {
-           "_led": {"minimum": 1, "maximum": 3}
-         }
-      }
-    }
-  })"};
-}
-std::vector<std::string> FileConfigStore::LoadStateDefs() {
-  return {R"({
-    "_greeter": {"_greetings_counter":"integer"},
-    "_ledflasher": {"_leds": {"items": "boolean"}}
-  })"};
-}
-
-std::vector<std::string> FileConfigStore::LoadStateDefaults() {
-  return {R"({
-    "_greeter": {"_greetings_counter": 0},
-    "_ledflasher":{"_leds": [false, false, false]}
-  })"};
-}
-
 }  // namespace examples
 }  // namespace weave
diff --git a/libweave/examples/ubuntu/file_config_store.h b/libweave/examples/ubuntu/file_config_store.h
index 926576f..25431e3 100644
--- a/libweave/examples/ubuntu/file_config_store.h
+++ b/libweave/examples/ubuntu/file_config_store.h
@@ -21,9 +21,6 @@
   bool LoadDefaults(Settings* settings) override;
   std::string LoadSettings() override;
   void SaveSettings(const std::string& settings) override;
-  std::vector<std::string> LoadCommandDefs() override;
-  std::vector<std::string> LoadStateDefs() override;
-  std::vector<std::string> LoadStateDefaults() override;
 
  private:
   bool disable_security_{false};
diff --git a/libweave/examples/ubuntu/main.cc b/libweave/examples/ubuntu/main.cc
index c28d164..b53e6c5 100644
--- a/libweave/examples/ubuntu/main.cc
+++ b/libweave/examples/ubuntu/main.cc
@@ -34,6 +34,45 @@
 class CommandHandler {
  public:
   explicit CommandHandler(weave::Device* device) : device_{device} {
+    device->AddCommandDefinitions(R"({
+      "base": {
+        "updateBaseConfiguration": {},
+        "identify": {},
+        "updateDeviceInfo": {}
+      },
+      "_greeter": {
+        "_greet": {
+          "minimalRole": "user",
+          "parameters": { "_name": "string"},
+          "results": { "_greeting": "string" }
+        }
+      },
+      "_ledflasher": {
+         "_set":{
+           "parameters": {
+             "_led": {"minimum": 1, "maximum": 3},
+             "_on": "boolean"
+           }
+         },
+         "_toggle":{
+           "parameters": {
+             "_led": {"minimum": 1, "maximum": 3}
+           }
+        }
+      }
+    })");
+
+    device->AddStateDefinitions(R"({
+      "_greeter": {"_greetings_counter":"integer"},
+      "_ledflasher": {"_leds": {"items": "boolean"}}
+    })");
+
+    device->SetState(R"({
+      "_greeter": {"_greetings_counter": 0},
+    "_ledflasher":{"_leds": [false, false, false]}
+    })",
+                     nullptr);
+
     device->AddCommandHandler("_greeter._greet",
                               base::Bind(&CommandHandler::OnGreetCommand,
                                          weak_ptr_factory_.GetWeakPtr()));
diff --git a/libweave/include/weave/provider/config_store.h b/libweave/include/weave/provider/config_store.h
index aa7c5e5..7bc5d31 100644
--- a/libweave/include/weave/provider/config_store.h
+++ b/libweave/include/weave/provider/config_store.h
@@ -35,15 +35,6 @@
   // recommended to protect data, e.g. using encryption.
   virtual void SaveSettings(const std::string& settings) = 0;
 
-  // Returns command definitions as array of JSONs.
-  virtual std::vector<std::string> LoadCommandDefs() = 0;
-
-  // Returns device state definitions as array of JSONs.
-  virtual std::vector<std::string> LoadStateDefs() = 0;
-
-  // Returns device state defaults as array of JSONs.
-  virtual std::vector<std::string> LoadStateDefaults() = 0;
-
  protected:
   virtual ~ConfigStore() = default;
 };
diff --git a/libweave/include/weave/provider/test/mock_config_store.h b/libweave/include/weave/provider/test/mock_config_store.h
index 6eab802..4aef17e 100644
--- a/libweave/include/weave/provider/test/mock_config_store.h
+++ b/libweave/include/weave/provider/test/mock_config_store.h
@@ -41,10 +41,6 @@
   MOCK_METHOD1(LoadDefaults, bool(Settings*));
   MOCK_METHOD0(LoadSettings, std::string());
   MOCK_METHOD1(SaveSettings, void(const std::string&));
-
-  MOCK_METHOD0(LoadCommandDefs, std::vector<std::string>());
-  MOCK_METHOD0(LoadStateDefs, std::vector<std::string>());
-  MOCK_METHOD0(LoadStateDefaults, std::vector<std::string>());
 };
 
 }  // namespace test
diff --git a/libweave/src/commands/command_manager.cc b/libweave/src/commands/command_manager.cc
index 9aa3385..efca5ff 100644
--- a/libweave/src/commands/command_manager.cc
+++ b/libweave/src/commands/command_manager.cc
@@ -7,7 +7,6 @@
 #include <base/values.h>
 #include <weave/enum_to_string.h>
 #include <weave/error.h>
-#include <weave/provider/config_store.h>
 
 #include "src/commands/schema_constants.h"
 #include "src/utils.h"
@@ -93,15 +92,11 @@
   return LoadCommands(*dict, error);
 }
 
-void CommandManager::Startup(provider::ConfigStore* config_store) {
+void CommandManager::Startup() {
   LOG(INFO) << "Initializing CommandManager.";
 
   // Load global standard GCD command dictionary.
   CHECK(LoadBaseCommands(kBaseCommandDefs, nullptr));
-
-  // Loading the rest of commands.
-  for (const auto& defs : config_store->LoadCommandDefs())
-    CHECK(this->LoadCommands(defs, nullptr));
 }
 
 void CommandManager::AddCommand(
diff --git a/libweave/src/commands/command_manager.h b/libweave/src/commands/command_manager.h
index 97fc73f..f34a907 100644
--- a/libweave/src/commands/command_manager.h
+++ b/libweave/src/commands/command_manager.h
@@ -20,10 +20,6 @@
 
 class CommandInstance;
 
-namespace provider {
-class ConfigStore;
-}
-
 // CommandManager class that will have a list of all the device command
 // schemas as well as the live command queue of pending command instances
 // dispatched to the device.
@@ -71,10 +67,8 @@
                     ErrorPtr* error);
 
   // Startup method to be called by buffet daemon at startup.
-  // Initializes the object and loads:
-  //   1) the standard GCD command dictionary
-  //   2) static vendor-provided command definitions
-  void Startup(weave::provider::ConfigStore* config_store);
+  // Initializes standard GCD command dictionary.
+  void Startup();
 
   // Adds a new command to the command queue.
   void AddCommand(std::unique_ptr<CommandInstance> command_instance);
diff --git a/libweave/src/commands/command_manager_unittest.cc b/libweave/src/commands/command_manager_unittest.cc
index 3e0d383..5101b4e 100644
--- a/libweave/src/commands/command_manager_unittest.cc
+++ b/libweave/src/commands/command_manager_unittest.cc
@@ -115,11 +115,9 @@
 
 TEST(CommandManager, ShouldLoadStandardAndTestDefinitions) {
   CommandManager manager;
-  provider::test::MockConfigStore config_store;
-  EXPECT_CALL(config_store, LoadCommandDefs())
-      .WillOnce(Return(
-          std::vector<std::string>{kTestVendorCommands, kTestTestCommands}));
-  manager.Startup(&config_store);
+  manager.Startup();
+  ASSERT_TRUE(manager.LoadCommands(kTestVendorCommands, nullptr));
+  ASSERT_TRUE(manager.LoadCommands(kTestTestCommands, nullptr));
   EXPECT_EQ(3, manager.GetCommandDictionary().GetSize());
   EXPECT_NE(nullptr, manager.GetCommandDictionary().FindCommand("robot._jump"));
   EXPECT_NE(nullptr,
diff --git a/libweave/src/device_manager.cc b/libweave/src/device_manager.cc
index 9c52912..865825f 100644
--- a/libweave/src/device_manager.cc
+++ b/libweave/src/device_manager.cc
@@ -34,10 +34,10 @@
                              provider::Wifi* wifi,
                              provider::Bluetooth* bluetooth) {
   command_manager_ = std::make_shared<CommandManager>();
-  command_manager_->Startup(config_store);
+  command_manager_->Startup();
   state_change_queue_.reset(new StateChangeQueue(kMaxStateChangeQueueSize));
   state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
-  state_manager_->Startup(config_store);
+  state_manager_->Startup();
 
   std::unique_ptr<Config> config{new Config{config_store}};
   config->Load();
diff --git a/libweave/src/states/state_manager.cc b/libweave/src/states/state_manager.cc
index cd94736..b0dd802 100644
--- a/libweave/src/states/state_manager.cc
+++ b/libweave/src/states/state_manager.cc
@@ -6,7 +6,6 @@
 
 #include <base/logging.h>
 #include <base/values.h>
-#include <weave/provider/config_store.h>
 
 #include "src/json_error_codes.h"
 #include "src/states/error_codes.h"
@@ -54,23 +53,15 @@
   callback.Run();  // Force to read current state.
 }
 
-void StateManager::Startup(provider::ConfigStore* config_store) {
+void StateManager::Startup() {
   LOG(INFO) << "Initializing StateManager.";
 
   // Load standard device state definition.
   CHECK(LoadBaseStateDefinition(kBaseStateDefs, nullptr));
 
-  // Load component-specific device state definitions.
-  for (const auto& state_def : config_store->LoadStateDefs())
-    CHECK(LoadStateDefinition(state_def, nullptr));
-
   // Load standard device state defaults.
   CHECK(LoadStateDefaults(kBaseStateDefaults, nullptr));
 
-  // Load component-specific device state defaults.
-  for (const auto& json : config_store->LoadStateDefaults())
-    CHECK(LoadStateDefaults(json, nullptr));
-
   for (const auto& cb : on_changed_)
     cb.Run();
 }
@@ -176,8 +167,8 @@
 
 bool StateManager::LoadStateDefinition(const base::DictionaryValue& dict,
                                        ErrorPtr* error) {
-  base::DictionaryValue::Iterator iter(dict);
-  while (!iter.IsAtEnd()) {
+  for (base::DictionaryValue::Iterator iter(dict); !iter.IsAtEnd();
+       iter.Advance()) {
     std::string package_name = iter.key();
     if (package_name.empty()) {
       Error::AddTo(error, FROM_HERE, errors::kErrorDomain,
@@ -196,7 +187,6 @@
     CHECK(package) << "Unable to create state package " << package_name;
     if (!package->AddSchemaFromJson(package_dict, error))
       return false;
-    iter.Advance();
   }
 
   return true;
@@ -232,35 +222,39 @@
 
 bool StateManager::LoadStateDefaults(const base::DictionaryValue& dict,
                                      ErrorPtr* error) {
-  base::DictionaryValue::Iterator iter(dict);
-  while (!iter.IsAtEnd()) {
-    std::string package_name = iter.key();
-    if (package_name.empty()) {
+  base::Time timestamp = base::Time::Now();
+  bool all_success = true;
+  for (base::DictionaryValue::Iterator iter(dict); !iter.IsAtEnd();
+       iter.Advance()) {
+    if (iter.key().empty()) {
       Error::AddTo(error, FROM_HERE, errors::kErrorDomain,
                    errors::kInvalidPackageError, "State package name is empty");
-      return false;
+      all_success = false;
+      continue;
     }
+
     const base::DictionaryValue* package_dict = nullptr;
     if (!iter.value().GetAsDictionary(&package_dict)) {
       Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
                          errors::json::kObjectExpected,
                          "State package '%s' must be an object",
-                         package_name.c_str());
-      return false;
+                         iter.key().c_str());
+      all_success = false;
+      continue;
     }
-    StatePackage* package = FindPackage(package_name);
-    if (package == nullptr) {
-      Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
-                         errors::json::kObjectExpected,
-                         "Providing values for undefined state package '%s'",
-                         package_name.c_str());
-      return false;
+
+    for (base::DictionaryValue::Iterator it_prop(*package_dict);
+         !it_prop.IsAtEnd(); it_prop.Advance()) {
+      if (!SetPropertyValue(iter.key() + "." + it_prop.key(), it_prop.value(),
+                            timestamp, error)) {
+        all_success = false;
+        continue;
+      }
     }
-    if (!package->AddValuesFromJson(package_dict, error))
-      return false;
-    iter.Advance();
   }
-  return true;
+  for (const auto& cb : on_changed_)
+    cb.Run();
+  return all_success;
 }
 
 bool StateManager::LoadStateDefaults(const std::string& json, ErrorPtr* error) {
diff --git a/libweave/src/states/state_manager.h b/libweave/src/states/state_manager.h
index 3dbd0d5..72f9ddd 100644
--- a/libweave/src/states/state_manager.h
+++ b/libweave/src/states/state_manager.h
@@ -26,10 +26,6 @@
 
 namespace weave {
 
-namespace provider {
-class ConfigStore;
-}
-
 // StateManager is the class that aggregates the device state fragments
 // provided by device daemons and makes the aggregate device state available
 // to the GCD cloud server and local clients.
@@ -53,7 +49,7 @@
 
   // Initializes the state manager and load device state fragments.
   // Called by Buffet daemon at startup.
-  void Startup(provider::ConfigStore* config_store);
+  void Startup();
 
   // Returns the recorded state changes since last time this method has been
   // called.
diff --git a/libweave/src/states/state_manager_unittest.cc b/libweave/src/states/state_manager_unittest.cc
index 522e0e6..3273a16 100644
--- a/libweave/src/states/state_manager_unittest.cc
+++ b/libweave/src/states/state_manager_unittest.cc
@@ -59,12 +59,12 @@
     // Initial expectations.
     EXPECT_CALL(mock_state_change_queue_, IsEmpty()).Times(0);
     EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(_, _))
-        .Times(0);
+        .WillRepeatedly(Return(true));
     EXPECT_CALL(mock_state_change_queue_, GetAndClearRecordedStateChanges())
         .Times(0);
     mgr_.reset(new StateManager(&mock_state_change_queue_));
 
-    EXPECT_CALL(*this, OnStateChanged()).Times(1);
+    EXPECT_CALL(*this, OnStateChanged()).Times(2);
     mgr_->AddChangedCallback(
         base::Bind(&StateManagerTest::OnStateChanged, base::Unretained(this)));
 
@@ -133,18 +133,13 @@
 }
 
 TEST_F(StateManagerTest, Startup) {
-  provider::test::MockConfigStore config_store;
   StateManager manager(&mock_state_change_queue_);
 
-  EXPECT_CALL(config_store, LoadStateDefs())
-      .WillOnce(Return(std::vector<std::string>{
-          {R"({"power": {"battery_level":"integer"}})"}}));
-
-  EXPECT_CALL(config_store, LoadStateDefaults())
-      .WillOnce(Return(
-          std::vector<std::string>{{R"({"power": {"battery_level":44}})"}}));
-
-  manager.Startup(&config_store);
+  manager.Startup();
+  ASSERT_TRUE(manager.LoadStateDefinition(
+      R"({"power": {"battery_level":"integer"}})", nullptr));
+  ASSERT_TRUE(
+      manager.LoadStateDefaults(R"({"power": {"battery_level":44}})", nullptr));
 
   auto expected = R"({
     'base': {
diff --git a/libweave/src/weave_unittest.cc b/libweave/src/weave_unittest.cc
index f0f8a58..b794fd6 100644
--- a/libweave/src/weave_unittest.cc
+++ b/libweave/src/weave_unittest.cc
@@ -157,15 +157,6 @@
 
   void InitConfigStore() {
     EXPECT_CALL(config_store_, SaveSettings("")).WillRepeatedly(Return());
-
-    EXPECT_CALL(config_store_, LoadCommandDefs())
-        .WillOnce(Return(std::vector<std::string>{kCommandDefs}));
-
-    EXPECT_CALL(config_store_, LoadStateDefs())
-        .WillOnce(Return(std::vector<std::string>{kStateDefs}));
-
-    EXPECT_CALL(config_store_, LoadStateDefaults())
-        .WillOnce(Return(std::vector<std::string>{kStateDefaults}));
   }
 
   void InitNetwork() {
@@ -236,6 +227,10 @@
                                     &http_client_, &network_, &dns_sd_,
                                     &http_server_, &wifi_, &bluetooth_);
 
+    device_->AddCommandDefinitions(kCommandDefs);
+    device_->AddStateDefinitions(kStateDefs);
+    device_->SetState(kStateDefaults, nullptr);
+
     for (const auto& cb : http_server_changed_cb_)
       cb.Run(http_server_);
 
@@ -290,6 +285,7 @@
   device_ = weave::Device::Create(&config_store_, &task_runner_, &http_client_,
                                   &network_, &dns_sd_, &http_server_, nullptr,
                                   &bluetooth_);
+  device_->AddCommandDefinitions(kCommandDefs);
 
   for (const auto& cb : http_server_changed_cb_)
     cb.Run(http_server_);