Commit b5d2ddbe authored by Jelte Jansen's avatar Jelte Jansen

added isc::config::ConfigData class for easier client-side usage of...

added isc::config::ConfigData class for easier client-side usage of configuration values (not completely done yet)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@915 e5f2f494-b856-4b98-b285-d166d9295462
parent d4398182
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/ext -Wall -Werror
lib_LIBRARIES = libcfgclient.a
libcfgclient_a_SOURCES = module_spec.h module_spec.cc ccsession.cc ccsession.h
libcfgclient_a_SOURCES = config_data.h config_data.cc module_spec.h module_spec.cc ccsession.cc ccsession.h
CLEANFILES = *.gcno *.gcda
TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = module_spec_unittests.cc run_unittests.cc
run_unittests_SOURCES = module_spec_unittests.cc config_data_unittests.cc run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = libcfgclient.a $(GTEST_LDADD)
......
......@@ -135,7 +135,7 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
read_module_specification(spec_file_name);
sleep(1);
module_name_ = module_specification_.getFullSpec()->get("module_spec")->get("module_name")->stringValue();
module_name_ = module_specification_.getFullSpec()->get("module_name")->stringValue();
config_handler_ = config_handler;
command_handler_ = command_handler;
......@@ -150,7 +150,9 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
//session_.subscribe("Boss", "*");
//session_.subscribe("statistics", "*");
// send the data specification
session_.group_sendmsg(module_specification_.getFullSpec(), "ConfigManager");
ElementPtr spec_msg = Element::createFromString("{}");
spec_msg->set("module_spec", module_specification_.getFullSpec());
session_.group_sendmsg(spec_msg, "ConfigManager");
session_.group_recvmsg(env, answer, false);
// get any stored configuration from the manager
......
......@@ -37,7 +37,11 @@ public:
isc::Exception(file, line, what) {}
};
///
/// \brief This modules keeps a connection to the command channel,
/// holds configuration information, and handles messages from
/// the command channel
///
class ModuleCCSession {
public:
/**
......
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include "config_data.h"
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
using namespace isc::data;
namespace isc {
namespace config {
ElementPtr
find_spec_part(ElementPtr spec, const std::string& identifier)
{
//std::cout << "[XX] find_spec_part" << std::endl;
if (!spec) { return ElementPtr(); }
//std::cout << "in: " << spec << std::endl;
ElementPtr spec_part = spec;
if (identifier == "") {
//std::cout << "[XX] empty id" << std::endl;
return ElementPtr();
}
std::string id = identifier;
size_t sep = id.find('/');
while(sep != std::string::npos) {
std::string part = id.substr(0, sep);
//std::cout << "[XX] id part: " << part << std::endl;
if (spec_part->getType() == Element::list) {
bool found = false;
BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
if (list_el->getType() == Element::map &&
list_el->contains("item_name") &&
list_el->get("item_name")->stringValue() == part) {
spec_part = list_el->get("item_name");
found = true;
}
}
if (!found) {
// raise exception?
return ElementPtr();
}
} else if (spec_part->getType() == Element::map) {
if (spec_part->contains("map_item_spec")) {
bool found = false;
BOOST_FOREACH(ElementPtr list_el, spec_part->get("map_item_spec")->listValue()) {
if (list_el->getType() == Element::map &&
list_el->contains("item_name") &&
list_el->get("item_name")->stringValue() == part) {
spec_part = list_el->get("item_name");
found = true;
}
}
if (!found) {
// raise exception?
return ElementPtr();
}
}
}
id = id.substr(sep + 1);
}
if (id != "" && id != "/") {
if (spec_part->getType() == Element::list) {
bool found = false;
BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
if (list_el->getType() == Element::map &&
list_el->contains("item_name") &&
list_el->get("item_name")->stringValue() == id) {
spec_part = list_el;
found = true;
}
}
if (!found) {
// raise exception?
return ElementPtr();
}
} else if (spec_part->getType() == Element::map) {
if (spec_part->contains("map_item_spec")) {
bool found = false;
BOOST_FOREACH(ElementPtr list_el, spec_part->get("map_item_spec")->listValue()) {
if (list_el->getType() == Element::map &&
list_el->contains("item_name") &&
list_el->get("item_name")->stringValue() == id) {
spec_part = list_el;
found = true;
}
}
if (!found) {
// raise exception?
return ElementPtr();
}
}
}
}
return spec_part;
}
ElementPtr
ConfigData::getValue(const std::string& identifier)
{
bool fake;
return getValue(fake, identifier);
}
ElementPtr
ConfigData::getValue(bool& is_default, const std::string& identifier)
{
ElementPtr value = _config->find(identifier);
if (!value) {
ElementPtr spec_part = find_spec_part(_module_spec.getConfigSpec(), identifier);
if (spec_part) {
value = spec_part->get("item_default");
is_default = true;
} else {
// we should raise an error here
dns_throw(DataNotFoundError, "identifier not found");
}
} else {
is_default = false;
}
return value;
}
void
spec_name_list(ElementPtr result, ElementPtr spec_part, std::string prefix, bool recurse = false)
{
if (spec_part->getType() == Element::list) {
BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
if (list_el->getType() == Element::map &&
list_el->contains("item_name")) {
result->add(Element::create(prefix + "/" + list_el->get("item_name")->stringValue()));
}
}
} else if (spec_part->getType() == Element::map &&
spec_part->contains("map_item_spec")
) {
if (recurse) {
spec_name_list(result, spec_part->get("map_item_spec"), prefix + "/" + spec_part->get("item_name")->stringValue(), recurse);
} else {
result->add(Element::create(prefix + "/" + spec_part->get("item_name")->stringValue()));
}
}
}
ElementPtr
ConfigData::getItemList(const std::string& identifier, bool recurse)
{
ElementPtr result = Element::createFromString("[]");
ElementPtr spec_part = getModuleSpec().getConfigSpec();
if (identifier != "" && identifier != "/") {
spec_part = find_spec_part(spec_part, identifier);
}
spec_name_list(result, spec_part, identifier, recurse);
return result;
}
ElementPtr
ConfigData::getFullConfig()
{
return ElementPtr();
}
}
}
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#ifndef __CONFIG_DATA_H
#define __CONFIG_DATA_H 1
#include <string>
#include <vector>
#include <config/module_spec.h>
#include <exceptions/exceptions.h>
namespace isc {
namespace config {
class DataNotFoundError : public isc::Exception {
public:
DataNotFoundError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
class ConfigData {
public:
ConfigData() { _config = Element::createFromString("{}"); };
ConfigData(const ModuleSpec& module_spec) : _module_spec(module_spec) { _config = Element::createFromString("{}"); }
ElementPtr getValue(const std::string& identifier);
ElementPtr getValue(bool &is_default, const std::string& identifier);
const ModuleSpec getModuleSpec() { return _module_spec; };
void setModuleSpec(ModuleSpec module_spec) { _module_spec = module_spec; };
void setLocalConfig(ElementPtr config) { _config = config; }
ElementPtr getLocalConfig() { return _config; }
ElementPtr getItemList(const std::string& identifier, bool recurse = false);
ElementPtr getFullConfig();
private:
ElementPtr _config;
ModuleSpec _module_spec;
};
}
}
#endif
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include <gtest/gtest.h>
#include "config_data.h"
#include "data_def_unittests_config.h"
#include <iostream>
using namespace isc::data;
using namespace isc::config;
ConfigData
setupSpec2()
{
ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
return ConfigData(spec2);
}
TEST(ConfigData, Creation) {
ConfigData cd = setupSpec2();
EXPECT_TRUE(true);
}
TEST(ConfigData, getValue) {
ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
ConfigData cd = ConfigData(spec2);
//std::cout << "[XX] SPEC2: " << cd.getModuleSpec().getFullSpec() << std::endl;
bool is_default;
//ElementPtr value = cd.getValue(is_default, "item1");
EXPECT_EQ(1, cd.getValue(is_default, "item1")->intValue());
EXPECT_TRUE(is_default);
EXPECT_EQ(1.1, cd.getValue(is_default, "item2")->doubleValue());
EXPECT_TRUE(is_default);
EXPECT_TRUE(cd.getValue(is_default, "item3")->boolValue());
EXPECT_TRUE(is_default);
EXPECT_EQ("test", cd.getValue(is_default, "item4")->stringValue());
EXPECT_TRUE(is_default);
EXPECT_EQ("a", cd.getValue(is_default, "item5")->get(0)->stringValue());
EXPECT_TRUE(is_default);
EXPECT_EQ("b", cd.getValue(is_default, "item5")->get(1)->stringValue());
EXPECT_TRUE(is_default);
EXPECT_EQ("{}", cd.getValue(is_default, "item6")->str());
EXPECT_TRUE(is_default);
}
TEST(ConfigData, setLocalConfig) {
ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
ConfigData cd = ConfigData(spec2);
bool is_default;
ElementPtr my_config = Element::createFromString("{\"item1\": 2}");
ElementPtr my_config2 = Element::createFromString("{\"item6\": { \"value1\": \"a\" } }");
EXPECT_EQ("{}", cd.getValue("item6")->str());
cd.setLocalConfig(my_config);
EXPECT_EQ(2, cd.getValue(is_default, "item1")->intValue());
EXPECT_FALSE(is_default);
EXPECT_EQ("{}", cd.getValue("item6")->str());
EXPECT_EQ(1.1, cd.getValue(is_default, "item2")->doubleValue());
EXPECT_TRUE(is_default);
cd.setLocalConfig(my_config2);
EXPECT_EQ("{\"value1\": \"a\"}", cd.getValue("item6")->str());
}
TEST(ConfigData, getLocalConfig) {
ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
ConfigData cd = ConfigData(spec2);
EXPECT_EQ("{}", cd.getLocalConfig()->str());
ElementPtr my_config = Element::createFromString("{\"item1\": 2}");
cd.setLocalConfig(my_config);
EXPECT_EQ("{\"item1\": 2}", cd.getLocalConfig()->str());
ElementPtr my_config2 = Element::createFromString("{\"item6\": { \"value1\": \"a\" } }");
cd.setLocalConfig(my_config2);
EXPECT_EQ("{\"item6\": {\"value1\": \"a\"}}", cd.getLocalConfig()->str());
}
TEST(ConfigData, getItemList) {
ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec");
ConfigData cd = ConfigData(spec2);
//EXPECT_EQ("", cd.getItemList("")->str());
}
......@@ -160,11 +160,7 @@ check_data_specification(const ElementPtr& spec) {
static void
check_module_specification(const ElementPtr& def)
{
if (!def->contains("module_spec")) {
throw ModuleSpecError("Data specification does not contain module_spec element");
} else {
check_data_specification(def->get("module_spec"));
}
check_data_specification(def);
}
//
......@@ -183,7 +179,7 @@ ModuleSpec::ModuleSpec(ElementPtr module_spec_element,
}
const ElementPtr
ModuleSpec::getCommandsSpec()
ModuleSpec::getCommandsSpec() const
{
if (module_specification->contains("commands")) {
return module_specification->get("commands");
......@@ -193,7 +189,7 @@ ModuleSpec::getCommandsSpec()
}
const ElementPtr
ModuleSpec::getConfigSpec()
ModuleSpec::getConfigSpec() const
{
if (module_specification->contains("config_data")) {
return module_specification->get("config_data");
......@@ -203,7 +199,7 @@ ModuleSpec::getConfigSpec()
}
const std::string
ModuleSpec::getModuleName()
ModuleSpec::getModuleName() const
{
return module_specification->get("module_name")->stringValue();
}
......@@ -211,14 +207,14 @@ ModuleSpec::getModuleName()
bool
ModuleSpec::validate_config(const ElementPtr data, const bool full)
{
ElementPtr spec = module_specification->find("module_spec/config_data");
ElementPtr spec = module_specification->find("config_data");
return validate_spec_list(spec, data, full, ElementPtr());
}
bool
ModuleSpec::validate_config(const ElementPtr data, const bool full, ElementPtr errors)
{
ElementPtr spec = module_specification->find("module_spec/config_data");
ElementPtr spec = module_specification->find("config_data");
return validate_spec_list(spec, data, full, errors);
}
......@@ -236,14 +232,22 @@ moduleSpecFromFile(const std::string& file_name, const bool check)
}
ElementPtr module_spec_element = Element::createFromString(file, file_name);
return ModuleSpec(module_spec_element, check);
if (module_spec_element->contains("module_spec")) {
return ModuleSpec(module_spec_element->get("module_spec"), check);
} else {
throw ModuleSpecError("No module_spec in specification");
}
}
ModuleSpec
moduleSpecFromFile(std::ifstream& in, const bool check)
throw(ParseError, ModuleSpecError) {
ElementPtr module_spec_element = Element::createFromString(in);
return ModuleSpec(module_spec_element, check);
if (module_spec_element->contains("module_spec")) {
return ModuleSpec(module_spec_element->get("module_spec"), check);
} else {
throw ModuleSpecError("No module_spec in specification");
}
}
......
......@@ -62,20 +62,20 @@ namespace isc { namespace config {
/// ElementPtr, returns an empty ElementPtr if there is none
/// \return ElementPtr Shared pointer to the commands
/// part of the specification
const ElementPtr getCommandsSpec();
const ElementPtr getCommandsSpec() const;
/// Returns the configuration part of the specification as an
/// ElementPtr
/// \return ElementPtr Shared pointer to the configuration
/// part of the specification
const ElementPtr getConfigSpec();
const ElementPtr getConfigSpec() const;
/// Returns the full module specification as an ElementPtr
/// \return ElementPtr Shared pointer to the specification
const ElementPtr getFullSpec() { return module_specification; };
const ElementPtr getFullSpec() const { return module_specification; };
/// Returns the module name as specified by the specification
const std::string getModuleName();
const std::string getModuleName() const;
// returns true if the given element conforms to this data
// configuration specification
......
......@@ -48,12 +48,10 @@ TEST(ModuleSpec, ReadingSpecfiles) {
// Tests whether we can open specfiles and if we get the
// right parse errors
ModuleSpec dd = moduleSpecFromFile(specfile("spec1.spec"));
EXPECT_EQ(dd.getFullSpec()->get("module_spec")
->get("module_name")
->stringValue(), "Spec1");
EXPECT_EQ(dd.getFullSpec()->get("module_name")
->stringValue(), "Spec1");
dd = moduleSpecFromFile(specfile("spec2.spec"));
EXPECT_EQ(dd.getFullSpec()->get("module_spec")
->get("config_data")->size(), 6);
EXPECT_EQ(dd.getFullSpec()->get("config_data")->size(), 6);
module_spec_error("doesnotexist",
"Error opening ",
specfile("doesnotexist"),
......@@ -62,9 +60,8 @@ TEST(ModuleSpec, ReadingSpecfiles) {
std::ifstream file;
file.open(specfile("spec1.spec").c_str());
dd = moduleSpecFromFile(file);
EXPECT_EQ(dd.getFullSpec()->get("module_spec")
->get("module_name")
->stringValue(), "Spec1");
EXPECT_EQ(dd.getFullSpec()->get("module_name")
->stringValue(), "Spec1");
}
TEST(ModuleSpec, SpecfileItems) {
......@@ -97,7 +94,7 @@ TEST(ModuleSpec, SpecfileConfigData)
module_spec_error("spec7.spec",
"module_name missing in {}");
module_spec_error("spec8.spec",
"Data specification does not contain module_spec element");
"No module_spec in specification");
module_spec_error("spec16.spec",
"config_data is not a list of elements");
module_spec_error("spec21.spec",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment