1 // Copyright 2015 The Weave 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 LIBWEAVE_SRC_COMPONENT_MANAGER_IMPL_H_
6 #define LIBWEAVE_SRC_COMPONENT_MANAGER_IMPL_H_
7 
8 #include <base/time/default_clock.h>
9 
10 #include "src/commands/command_queue.h"
11 #include "src/component_manager.h"
12 #include "src/states/state_change_queue.h"
13 
14 namespace weave {
15 
16 class ComponentManagerImpl final : public ComponentManager {
17  public:
18   explicit ComponentManagerImpl(provider::TaskRunner* task_runner,
19                                 base::Clock* clock = nullptr);
20   ~ComponentManagerImpl() override;
21 
22   // Loads trait definition schema.
23   bool LoadTraits(const base::DictionaryValue& dict, ErrorPtr* error) override;
24 
25   // Same as the overload above, but takes a json string to read the trait
26   // definitions from.
27   bool LoadTraits(const std::string& json, ErrorPtr* error) override;
28 
29   // Sets callback which is called when new trait definitions are added.
30   void AddTraitDefChangedCallback(const base::Closure& callback) override;
31 
32   // Adds a new component instance to device.
33   // |path| is a path to the parent component (or empty string if a root-level
34   // component is being added).
35   // |name| is a component name being added.
36   // |traits| is a list of trait names this component supports.
37   bool AddComponent(const std::string& path,
38                     const std::string& name,
39                     const std::vector<std::string>& traits,
40                     ErrorPtr* error) override;
41 
42   // Adds a new component instance to device, as a part of component array.
43   // |path| is a path to the parent component.
44   // |name| is an array root element inside the child components.
45   // |traits| is a list of trait names this component supports.
46   bool AddComponentArrayItem(const std::string& path,
47                              const std::string& name,
48                              const std::vector<std::string>& traits,
49                              ErrorPtr* error) override;
50 
51   // Removes an existing component instance from device.
52   // |path| is a path to the parent component (or empty string if a root-level
53   // component is being removed).
54   // |name| is a name of the component to be removed.
55   bool RemoveComponent(const std::string& path,
56                        const std::string& name,
57                        ErrorPtr* error) override;
58 
59   // Removes an element from component array.
60   // |path| is a path to the parent component.
61   // |name| is an array root element inside the child components.
62   // |index| is a zero-based element index in the component array.
63   bool RemoveComponentArrayItem(const std::string& path,
64                                 const std::string& name,
65                                 size_t index,
66                                 ErrorPtr* error) override;
67 
68   // Sets callback which is called when new components are added.
69   void AddComponentTreeChangedCallback(const base::Closure& callback) override;
70 
71   // Adds a new command instance to the command queue. The command specified in
72   // |command_instance| must be fully initialized and have its name, component,
73   // id populated.
74   void AddCommand(std::unique_ptr<CommandInstance> command_instance) override;
75 
76   // Parses the command definition from a json dictionary. The resulting command
77   // instance is populated with all the required fields and partially validated
78   // against syntax/schema.
79   // The new command ID is returned through optional |id| param.
80   std::unique_ptr<CommandInstance> ParseCommandInstance(
81       const base::DictionaryValue& command,
82       Command::Origin command_origin,
83       UserRole role,
84       std::string* id,
85       ErrorPtr* error) override;
86 
87   // Find a command instance with the given ID in the command queue.
88   CommandInstance* FindCommand(const std::string& id) override;
89 
90   // Command queue monitoring callbacks (called when a new command is added to
91   // or removed from the queue).
92   void AddCommandAddedCallback(
93       const CommandQueue::CommandCallback& callback) override;
94   void AddCommandRemovedCallback(
95       const CommandQueue::CommandCallback& callback) override;
96 
97   // Adds a command handler for specific component's command.
98   // |component_path| is a path to target component (e.g. "stove.burners[2]").
99   // |command_name| is a full path of the command, including trait name and
100   // command name (e.g. "burner.setPower").
101   void AddCommandHandler(
102       const std::string& component_path,
103       const std::string& command_name,
104       const Device::CommandHandlerCallback& callback) override;
105 
106   // Finds a component instance by its full path.
107   const base::DictionaryValue* FindComponent(const std::string& path,
108                                              ErrorPtr* error) const override;
109   // Finds a definition of trait with the given |name|.
110   const base::DictionaryValue* FindTraitDefinition(
111       const std::string& name) const override;
112 
113   // Finds a command definition, where |command_name| is in the form of
114   // "trait.command".
115   const base::DictionaryValue* FindCommandDefinition(
116       const std::string& command_name) const override;
117 
118   // Checks the minimum required user role for a given command.
119   bool GetMinimalRole(const std::string& command_name,
120                       UserRole* minimal_role,
121                       ErrorPtr* error) const override;
122 
123   // Returns the full JSON dictionary containing trait definitions.
GetTraits()124   const base::DictionaryValue& GetTraits() const override { return traits_; }
125 
126   // Returns the full JSON dictionary containing component instances.
GetComponents()127   const base::DictionaryValue& GetComponents() const override {
128     return components_;
129   }
130 
131   // Component state manipulation methods.
132   bool SetStateProperties(const std::string& component_path,
133                           const base::DictionaryValue& dict,
134                           ErrorPtr* error) override;
135   bool SetStatePropertiesFromJson(const std::string& component_path,
136                                   const std::string& json,
137                                   ErrorPtr* error) override;
138   const base::Value* GetStateProperty(const std::string& component_path,
139                                       const std::string& name,
140                                       ErrorPtr* error) const override;
141   bool SetStateProperty(const std::string& component_path,
142                         const std::string& name,
143                         const base::Value& value,
144                         ErrorPtr* error) override;
145 
146   void AddStateChangedCallback(const base::Closure& callback) override;
147 
148   // Returns the recorded state changes since last time this method was called.
149   StateSnapshot GetAndClearRecordedStateChanges() override;
150 
151   // Called to notify that the state patch with |id| has been successfully sent
152   // to the server and processed.
153   void NotifyStateUpdatedOnServer(UpdateID id) override;
154 
155   // Returns an ID of last state change update. Each SetStatePropertyNNN()
156   // invocation increments this value by 1.
GetLastStateChangeId()157   UpdateID GetLastStateChangeId() const override {
158     return last_state_change_id_;
159   }
160 
161   // Subscribes for device state update notifications from cloud server.
162   // The |callback| will be called every time a state patch with given ID is
163   // successfully received and processed by Weave server.
164   // Returns a subscription token. As soon as this token is destroyed, the
165   // respective callback is removed from the callback list.
166   Token AddServerStateUpdatedCallback(
167       const base::Callback<void(UpdateID)>& callback) override;
168 
169   // Helper method for legacy API to obtain first component that implements
170   // the given trait. This is useful for routing commands that have no component
171   // path specified.
172   // Returns empty string if no components are found.
173   // This method only searches for component on the top level of components
174   // tree. No sub-components are searched.
175   std::string FindComponentWithTrait(const std::string& trait) const override;
176 
177   // Support for legacy APIs. Setting command and state definitions.
178   // This translates into modifying a trait definition.
179   bool AddLegacyCommandDefinitions(const base::DictionaryValue& dict,
180                                    ErrorPtr* error) override;
181   bool AddLegacyStateDefinitions(const base::DictionaryValue& dict,
182                                  ErrorPtr* error) override;
183   // Returns device state for legacy APIs.
184   const base::DictionaryValue& GetLegacyState() const override;
185   // Returns command definitions for legacy APIs.
186   const base::DictionaryValue& GetLegacyCommandDefinitions() const override;
187 
188  private:
189   // A helper method to find a JSON element of component at |path| to add new
190   // sub-components to.
191   base::DictionaryValue* FindComponentGraftNode(const std::string& path,
192                                                 ErrorPtr* error);
193   base::DictionaryValue* FindMutableComponent(const std::string& path,
194                                               ErrorPtr* error);
195 
196   // Legacy API support: Helper function to support state/command definitions.
197   // Adds the given trait to at least one component.
198   // Searches for available components and if none of them already supports this
199   // trait, it adds it to the first available component.
200   void AddTraitToLegacyComponent(const std::string& trait);
201 
202   // Helper method to find a sub-component given a root node and a relative path
203   // from the root to the target component.
204   static const base::DictionaryValue* FindComponentAt(
205       const base::DictionaryValue* root,
206       const std::string& path,
207       ErrorPtr* error);
208 
209   base::DefaultClock default_clock_;
210   base::Clock* clock_{nullptr};
211 
212   // An ID of last state change update. Each NotifyPropertiesUpdated()
213   // invocation increments this value by 1.
214   UpdateID last_state_change_id_{0};
215   // Callback list for state change queue event sinks.
216   // This member must be defined before |command_queue_|.
217   base::CallbackList<void(UpdateID)> on_server_state_updated_;
218 
219   base::DictionaryValue traits_;      // Trait definitions.
220   base::DictionaryValue components_;  // Component instances.
221   CommandQueue command_queue_;  // Command queue containing command instances.
222   std::vector<base::Closure> on_trait_changed_;
223   std::vector<base::Closure> on_componet_tree_changed_;
224   std::vector<base::Closure> on_state_changed_;
225   uint32_t next_command_id_{0};
226   std::map<std::string, std::unique_ptr<StateChangeQueue>> state_change_queues_;
227 
228   // Legacy API support.
229   mutable base::DictionaryValue legacy_state_;         // Device state.
230   mutable base::DictionaryValue legacy_command_defs_;  // Command definitions.
231 
232   DISALLOW_COPY_AND_ASSIGN(ComponentManagerImpl);
233 };
234 
235 }  // namespace weave
236 
237 #endif  // LIBWEAVE_SRC_COMPONENT_MANAGER_IMPL_H_
238