blob: 48a323fcb5a2f67aee765694792730c473c9e63f [file] [log] [blame]
// 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.
#include "buffet/commands/command_manager.h"
#include <base/at_exit.h>
#include <base/bind.h>
#include <base/files/file_enumerator.h>
#include <base/file_util.h>
#include <base/values.h>
#include <base/json/json_reader.h>
#include "buffet/commands/schema_constants.h"
#include "buffet/error_codes.h"
namespace buffet {
CommandManager* CommandManager::instance_ = nullptr;
const CommandDictionary& CommandManager::GetCommandDictionary() const {
return dictionary_;
}
bool CommandManager::LoadBaseCommands(const base::DictionaryValue& json,
ErrorPtr* error) {
return base_dictionary_.LoadCommands(json, "", nullptr, error);
}
bool CommandManager::LoadBaseCommands(const base::FilePath& json_file_path,
ErrorPtr* error) {
std::unique_ptr<const base::DictionaryValue> json = LoadJsonDict(
json_file_path, error);
if (!json)
return false;
return LoadBaseCommands(*json, error);
}
bool CommandManager::LoadCommands(const base::DictionaryValue& json,
const std::string& category,
ErrorPtr* error) {
return dictionary_.LoadCommands(json, category, &base_dictionary_, error);
}
bool CommandManager::LoadCommands(const base::FilePath& json_file_path,
ErrorPtr* error) {
std::unique_ptr<const base::DictionaryValue> json = LoadJsonDict(
json_file_path, error);
if (!json)
return false;
std::string category = json_file_path.BaseName().RemoveExtension().value();
return LoadCommands(*json, category, error);
}
CommandManager* CommandManager::GetInstance() {
CHECK(instance_) << "CommandManager instance not initialized.";
return instance_;
}
void CommandManager::Startup() {
CHECK(!instance_) << "CommandManager instance already initialized.";
LOG(INFO) << "Initializing CommandManager.";
std::unique_ptr<CommandManager> inst(new CommandManager);
// Load global standard GCD command dictionary.
base::FilePath base_command_file("/etc/buffet/gcd.json");
LOG(INFO) << "Loading standard commands from " << base_command_file.value();
CHECK(inst->LoadBaseCommands(base_command_file, nullptr))
<< "Failed to load the standard command definitions.";
// Load static device command definitions.
base::FilePath device_command_dir("/etc/buffet/commands");
base::FileEnumerator enumerator(device_command_dir, false,
base::FileEnumerator::FILES,
FILE_PATH_LITERAL("*.json"));
base::FilePath json_file_path = enumerator.Next();
while (!json_file_path.empty()) {
LOG(INFO) << "Loading command schema from " << json_file_path.value();
CHECK(inst->LoadCommands(json_file_path, nullptr))
<< "Failed to load the command definition file.";
json_file_path = enumerator.Next();
}
// Register a cleanup callback to be executed at shut-down.
base::AtExitManager::RegisterTask(base::Bind(&CommandManager::Shutdown));
// Transfer the object instance pointer from the smart pointer to
// the global pointer.
instance_ = inst.release();
}
void CommandManager::Shutdown() {
CHECK(instance_) << "CommandManager instance not initialized.";
LOG(INFO) << "Shutting down CommandManager.";
delete instance_;
instance_ = nullptr;
}
std::unique_ptr<const base::DictionaryValue> CommandManager::LoadJsonDict(
const base::FilePath& json_file_path, ErrorPtr* error) {
std::string json_string;
if (!base::ReadFileToString(json_file_path, &json_string)) {
Error::AddToPrintf(error, errors::file_system::kDomain,
errors::file_system::kFileReadError,
"Failed to read file '%s'",
json_file_path.value().c_str());
return std::unique_ptr<const base::DictionaryValue>();
}
std::string error_message;
base::Value* value = base::JSONReader::ReadAndReturnError(
json_string, base::JSON_PARSE_RFC, nullptr, &error_message);
if (!value) {
Error::AddToPrintf(error, errors::json::kDomain, errors::json::kParseError,
"Error parsing content of JSON file '%s': %s",
json_file_path.value().c_str(), error_message.c_str());
return std::unique_ptr<const base::DictionaryValue>();
}
const base::DictionaryValue* dict_value = nullptr;
if (!value->GetAsDictionary(&dict_value)) {
delete value;
Error::AddToPrintf(error, errors::json::kDomain,
errors::json::kObjectExpected,
"Content of file '%s' is not a JSON object",
json_file_path.value().c_str());
return std::unique_ptr<const base::DictionaryValue>();
}
return std::unique_ptr<const base::DictionaryValue>(dict_value);
}
} // namespace buffet