Commit 805d4406 authored by Jelte Jansen's avatar Jelte Jansen

start with data specification and validation part

added temporary test.cc and two data files for immediate testing


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jelte-datadef@291 e5f2f494-b856-4b98-b285-d166d9295462
parent 6d172713
AM_CPPFLAGS = -I$(top_srcdir)/src/lib/cc/cpp -I$(top_srcdir)/ext
bin_PROGRAMS = test
test_SOURCES = test.cc
test_LDADD = libcc.a
lib_LIBRARIES = libcc.a
libcc_a_SOURCES = data.cc data.h session.cc session.h
libcc_a_SOURCES = data.cc data.h data_def.h data_def.cc session.cc session.h
......@@ -289,7 +289,9 @@ from_stringstream_map(std::istream &in, int& line, int& pos)
in.get();
pos++;
p.second = Element::create_from_string(in, line, pos);
if (!p.second) { return ElementPtr(); };
if (!p.second) {
throw ParseError(std::string("missing map value for ") + p.first, line, pos);
};
m.insert(p);
skip_to(in, line, pos, ",}", " \t\n");
c = in.get();
......@@ -298,8 +300,6 @@ from_stringstream_map(std::istream &in, int& line, int& pos)
return Element::create(m);
}
//ElementPtr
//Element::create_from_string(std::stringstream &in)
ElementPtr
Element::create_from_string(std::istream &in) throw(ParseError)
{
......@@ -364,7 +364,6 @@ Element::create_from_string(std::istream &in, int& line, int& pos) throw(ParseEr
if (el_read) {
return element;
} else {
// throw exception?
throw ParseError("nothing read");
}
}
......
......@@ -104,6 +104,7 @@ namespace ISC { namespace Data {
virtual ElementPtr get(const std::string& name) { throw TypeError(); } ;
virtual void set(const std::string& name, ElementPtr element) { throw TypeError(); };
virtual void remove(const std::string& name) { throw TypeError(); };
virtual bool contains(const std::string& s) { throw TypeError(); }
virtual ElementPtr find(const std::string& identifier) { throw TypeError(); };
virtual bool find(const std::string& id, ElementPtr& t) { return false; };
......@@ -248,6 +249,7 @@ namespace ISC { namespace Data {
ElementPtr get(const std::string& s) { return m[s]; };
void set(const std::string& s, ElementPtr p) { m[s] = p; };
void remove(const std::string& s) { m.erase(s); }
bool contains(const std::string& s) { return m.find(s) != m.end(); }
std::string str();
std::string str_xml(size_t prefix = 0);
std::string to_wire(int omit_length = 1);
......
#include "data_def.h"
#include <sstream>
#include <boost/foreach.hpp>
using namespace ISC::Data;
DataDefinition::DataDefinition(std::istream& in) throw(ParseError) {
definition = Element::create_from_string(in);
// TODO, make sure the whole structure is complete and valid
if (!definition->contains("data_specification")) {
throw ParseError("Data specification does not contain data_specification element");
}
}
//
// helper functions for validation
//
static bool
check_type(ElementPtr spec, ElementPtr element)
{
std::string cur_item_type;
cur_item_type = spec->get("item_type")->string_value();
if (cur_item_type == "any") {
return true;
}
switch (element->get_type()) {
case Element::integer:
return cur_item_type == "integer";
break;
case Element::real:
return cur_item_type == "real";
break;
case Element::boolean:
return cur_item_type == "boolean";
break;
case Element::string:
return cur_item_type == "string";
break;
case Element::list:
return cur_item_type == "list";
break;
case Element::map:
return cur_item_type == "map";
break;
}
return false;
}
bool
DataDefinition::validate_item(const ElementPtr spec, const ElementPtr data) {
std::cout << "Validating type of " << data << std::endl;
if (!check_type(spec, data)) {
std::cout << "type mismatch; not " << spec->get("item_type") << ": " << data << std::endl;
std::cout << spec << std::endl;
return false;
}
if (data->get_type() == Element::list) {
BOOST_FOREACH(ElementPtr list_el, data->list_value()) {
if (!validate_spec(spec->get("list_item_spec"), list_el)) {
return false;
}
}
}
if (data->get_type() == Element::map) {
if (!validate_spec_list(spec->get("map_item_spec"), data)) {
return false;
}
}
return true;
}
// spec is a map with item_name etc, data is a map
bool
DataDefinition::validate_spec(const ElementPtr spec, const ElementPtr data) {
std::string item_name = spec->get("item_name")->string_value();
bool optional = spec->get("item_optional")->bool_value();
ElementPtr data_el;
std::cout << "check for item with name " << item_name << std::endl;
data_el = data->get(item_name);
if (data_el) {
if (!validate_item(spec, data_el)) {
return false;
}
} else {
if (!optional) {
std::cout << "non-optional value not found" << std::endl;
return false;
}
}
return true;
}
// spec is a list of maps, data is a map
bool
DataDefinition::validate_spec_list(const ElementPtr spec, const ElementPtr data) {
ElementPtr cur_data_el;
std::string cur_item_name;
bool optional;
BOOST_FOREACH(ElementPtr cur_spec_el, spec->list_value()) {
if (!validate_spec(cur_spec_el, data)) {
return false;
}
}
return true;
}
// TODO
// this function does *not* check if the specification is in correct
// form, we should do that in the constructor
bool
DataDefinition::validate(const ElementPtr data) {
ElementPtr spec = definition->find("data_specification/config_data");
return validate_spec_list(spec, data);
}
#ifndef _DATA_DEF_H
#define _DATA_DEF_H 1
#include "data.h"
#include <sstream>
namespace ISC { namespace Data {
class DataDefinition {
public:
explicit DataDefinition() {};
explicit DataDefinition(ElementPtr e) : definition(e) {};
explicit DataDefinition(std::istream& in) throw(ParseError);
const ElementPtr getDefinition() { return definition; };
// returns true if the given element conforms to this data
// definition scheme
bool validate(const ElementPtr data);
private:
bool validate_item(const ElementPtr spec, const ElementPtr data);
bool validate_spec(const ElementPtr spec, const ElementPtr data);
bool validate_spec_list(const ElementPtr spec, const ElementPtr data);
ElementPtr definition;
};
} }
#endif // _DATA_DEF_H
{
"port": 5300,
"zones": [
{
"zone_name": "tjeb.nl"
},
{
"zone_name": "jinmei.org"
}
]
}
{
"data_specification": {
"module_name": "parkinglot",
"config_data": [
{
"item_name": "port",
"item_type": "integer",
"item_optional": false,
"item_default": 5300
},
{
"item_name": "zones",
"item_type": "list",
"item_optional": false,
"item_default": [ ],
"list_item_spec": {
"item_name": "zone_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
}
}
],
"commands": [
{
"command_name": "zone_add",
"command_args": {
"item_name": "zone_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
}
},
{
"command_name": "zone_delete",
"command_args": {
"item_name": "zone_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
}
}
]
}
}
#include "data.h"
#include "data_def.h"
#include <fstream>
using namespace std;
using namespace ISC::Data;
int
main(int argc, char **argv) {
std::ifstream file;
std::stringstream ss;
DataDefinition def;
ElementPtr data;
file.open("parkinglot.spec");
if (!file) {
cout << "error opening parkinglot.spec" << endl;
return 1;
}
try {
def = DataDefinition(file);
cout << "Definition: " << endl;
cout << def.getDefinition() << endl;
} catch (ParseError pe) {
cout << "Error parsing definition file: " << pe.what() << endl;
return 1;
}
file.close();
file.open("parkinglot.data");
if (!file) {
cout << "error opening parkinglot.data" << endl;
return 1;
}
try {
data = Element::create_from_string(file);
cout << "Data: " << endl;
cout << data << endl;
} catch (ParseError pe) {
cout << "Error parsing data file: " << pe.what() << endl;
return 1;
}
if (def.validate(data)) {
cout << "Data validated" << endl;
} else {
cout << "Error in data validation" << endl;
}
file.close();
}
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