]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2355] Initial commit of refactoring bin/dchp4 and bin/dchp6
authorThomas Markwalder <tmark@isc.org>
Wed, 10 Apr 2013 21:02:10 +0000 (17:02 -0400)
committerThomas Markwalder <tmark@isc.org>
Wed, 10 Apr 2013 21:02:10 +0000 (17:02 -0400)
configuration parsing classes into a common set of classes
in lib/dhcpsrv.  Moved most of the parsers classes into
new files dhcp_parsers.h/cc. Eliminated use of global
variables within common parsers.

src/bin/dhcp4/config_parser.cc
src/bin/dhcp4/config_parser.h
src/bin/dhcp6/config_parser.cc
src/bin/dhcp6/config_parser.h
src/lib/dhcpsrv/Makefile.am
src/lib/dhcpsrv/dhcp_parsers.cc [new file with mode: 0644]
src/lib/dhcpsrv/dhcp_parsers.h [new file with mode: 0644]

index 2391dff0855d1e97f68f8f802ac2f49187f6720b..e5317451bab0fe31e59a60e69674e685d22eb67a 100644 (file)
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config/ccsession.h>
-#include <dhcp4/config_parser.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option_definition.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcp4/config_parser.h>
 #include <dhcpsrv/dbaccess_parser.h>
-#include <dhcpsrv/dhcp_config_parser.h>
+#include <dhcpsrv/dhcp_parsers.h>
 #include <dhcpsrv/option_space_container.h>
 #include <util/encode/hex.h>
 #include <util/strutil.h>
+
 #include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
+
 #include <limits>
 #include <iostream>
 #include <vector>
@@ -39,37 +41,17 @@ using namespace isc::asiolink;
 
 namespace {
 
-// Forward declarations of some of the parser classes.
-// They are used to define pointer types for these classes.
-class BooleanParser;
-class StringParser;
-class Uint32Parser;
-
 // Pointers to various parser objects.
 typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
 typedef boost::shared_ptr<StringParser> StringParserPtr;
 typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
 
-/// @brief a factory method that will create a parser for a given element name
-typedef isc::dhcp::DhcpConfigParser* ParserFactory(const std::string& config_id);
-
-/// @brief a collection of factories that creates parsers for specified element names
-typedef std::map<std::string, ParserFactory*> FactoryMap;
-
-/// @brief Storage for option definitions.
-typedef OptionSpaceContainer<OptionDefContainer,
-                             OptionDefinitionPtr> OptionDefStorage;
-
 /// @brief a collection of pools
 ///
 /// That type is used as intermediate storage, when pools are parsed, but there is
 /// no subnet object created yet to store them.
 typedef std::vector<Pool4Ptr> PoolStorage;
 
-/// Collection of containers holding option spaces. Each container within
-/// a particular option space holds so-called option descriptors.
-typedef OptionSpaceContainer<Subnet::OptionContainer,
-                             Subnet::OptionDescriptor> OptionStorage;
 
 /// @brief Global uint32 parameters that will be used as defaults.
 Uint32Storage uint32_defaults;
@@ -83,365 +65,6 @@ OptionStorage option_defaults;
 /// @brief Global storage for option definitions.
 OptionDefStorage option_def_intermediate;
 
-/// @brief a dummy configuration parser
-///
-/// It is a debugging parser. It does not configure anything,
-/// will accept any configuration and will just print it out
-/// on commit. Useful for debugging existing configurations and
-/// adding new ones.
-class DebugParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor
-    ///
-    /// See @ref DhcpConfigParser class for details.
-    ///
-    /// @param param_name name of the parsed parameter
-    DebugParser(const std::string& param_name)
-        :param_name_(param_name) {
-    }
-
-    /// @brief builds parameter value
-    ///
-    /// See @ref DhcpConfigParser class for details.
-    ///
-    /// @param new_config pointer to the new configuration
-    virtual void build(ConstElementPtr new_config) {
-        std::cout << "Build for token: [" << param_name_ << "] = ["
-                  << value_->str() << "]" << std::endl;
-        value_ = new_config;
-    }
-
-    /// @brief pretends to apply the configuration
-    ///
-    /// This is a method required by base class. It pretends to apply the
-    /// configuration, but in fact it only prints the parameter out.
-    ///
-    /// See @ref DhcpConfigParser class for details.
-    virtual void commit() {
-        // Debug message. The whole DebugParser class is used only for parser
-        // debugging, and is not used in production code. It is very convenient
-        // to keep it around. Please do not turn this cout into logger calls.
-        std::cout << "Commit for token: [" << param_name_ << "] = ["
-                  << value_->str() << "]" << std::endl;
-    }
-
-    /// @brief factory that constructs DebugParser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* Factory(const std::string& param_name) {
-        return (new DebugParser(param_name));
-    }
-
-private:
-    /// name of the parsed parameter
-    std::string param_name_;
-
-    /// pointer to the actual value of the parameter
-    ConstElementPtr value_;
-};
-
-/// @brief A boolean value parser.
-///
-/// This parser handles configuration values of the boolean type.
-/// Parsed values are stored in a provided storage. If no storage
-/// is provided then the build function throws an exception.
-class BooleanParser : public DhcpConfigParser {
-public:
-    /// @brief Constructor.
-    ///
-    /// @param param_name name of the parameter.
-    BooleanParser(const std::string& param_name)
-        : storage_(NULL),
-          param_name_(param_name),
-          value_(false) {
-        // Empty parameter name is invalid.
-        if (param_name_.empty()) {
-            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-    }
-
-    /// @brief Parse a boolean value.
-    ///
-    /// @param value a value to be parsed.
-    ///
-    /// @throw isc::InvalidOperation if a storage has not been set
-    ///        prior to calling this function
-    /// @throw isc::dhcp::DhcpConfigError if a provided parameter's
-    ///        name is empty.
-    virtual void build(ConstElementPtr value) {
-        if (storage_ == NULL) {
-            isc_throw(isc::InvalidOperation, "parser logic error:"
-                      << " storage for the " << param_name_
-                      << " value has not been set");
-        } else if (param_name_.empty()) {
-            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-        // The Config Manager checks if user specified a
-        // valid value for a boolean parameter: True or False.
-        // It is then ok to assume that if str() does not return
-        // 'true' the value is 'false'.
-        value_ = (value->str() == "true") ? true : false;
-    }
-
-    /// @brief Put a parsed value to the storage.
-    virtual void commit() {
-        if (storage_ != NULL && !param_name_.empty()) {
-            storage_->setParam(param_name_, value_);
-        }
-    }
-
-    /// @brief Create an instance of the boolean parser.
-    ///
-    /// @param param_name name of the parameter for which the
-    ///        parser is created.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new BooleanParser(param_name));
-    }
-
-    /// @brief Set the storage for parsed value.
-    ///
-    /// This function must be called prior to calling build.
-    ///
-    /// @param storage a pointer to the storage where parsed data
-    ///        is to be stored.
-    void setStorage(BooleanStorage* storage) {
-        storage_ = storage;
-    }
-
-private:
-    /// Pointer to the storage where parsed value is stored.
-    BooleanStorage* storage_;
-    /// Name of the parameter which value is parsed with this parser.
-    std::string param_name_;
-    /// Parsed value.
-    bool value_;
-};
-
-/// @brief Configuration parser for uint32 parameters
-///
-/// This class is a generic parser that is able to handle any uint32 integer
-/// type. By default it stores the value in external global container
-/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
-/// in subnet config), it can be pointed to a different storage, using
-/// setStorage() method. This class follows the parser interface, laid out
-/// in its base class, @ref DhcpConfigParser.
-///
-/// For overview of usability of this generic purpose parser, see
-/// @ref dhcpv4ConfigInherit page.
-class Uint32Parser : public DhcpConfigParser {
-public:
-
-    /// @brief constructor for Uint32Parser
-    /// @param param_name name of the configuration parameter being parsed
-    Uint32Parser(const std::string& param_name)
-        : storage_(&uint32_defaults),
-          param_name_(param_name) {
-        // Empty parameter name is invalid.
-        if (param_name_.empty()) {
-            isc_throw(DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-    }
-
-    /// @brief Parses configuration configuration parameter as uint32_t.
-    ///
-    /// @param value pointer to the content of parsed values
-    /// @throw BadValue if supplied value could not be base to uint32_t
-    ///        or the parameter name is empty.
-    virtual void build(ConstElementPtr value) {
-        if (param_name_.empty()) {
-            isc_throw(DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-
-        int64_t check;
-        string x = value->str();
-        try {
-            check = boost::lexical_cast<int64_t>(x);
-        } catch (const boost::bad_lexical_cast &) {
-            isc_throw(BadValue, "Failed to parse value " << value->str()
-                      << " as unsigned 32-bit integer.");
-        }
-        if (check > std::numeric_limits<uint32_t>::max()) {
-            isc_throw(BadValue, "Value " << value->str() << "is too large"
-                      << " for unsigned 32-bit integer.");
-        }
-        if (check < 0) {
-            isc_throw(BadValue, "Value " << value->str() << "is negative."
-                      << " Only 0 or larger are allowed for unsigned 32-bit integer.");
-        }
-
-        // value is small enough to fit
-        value_ = static_cast<uint32_t>(check);
-    }
-
-    /// @brief Stores the parsed uint32_t value in a storage.
-    virtual void commit() {
-        if (storage_ != NULL && !param_name_.empty()) {
-            // If a given parameter already exists in the storage we override
-            // its value. If it doesn't we insert a new element.
-            storage_->setParam(param_name_, value_);
-        }
-    }
-
-    /// @brief factory that constructs Uint32Parser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new Uint32Parser(param_name));
-    }
-
-    /// @brief sets storage for value of this parameter
-    ///
-    /// See @ref dhcpv4ConfigInherit for details.
-    ///
-    /// @param storage pointer to the storage container
-    void setStorage(Uint32Storage* storage) {
-        storage_ = storage;
-    }
-
-private:
-    /// pointer to the storage, where parsed value will be stored
-    Uint32Storage* storage_;
-
-    /// name of the parameter to be parsed
-    std::string param_name_;
-
-    /// the actual parsed value
-    uint32_t value_;
-};
-
-/// @brief Configuration parser for string parameters
-///
-/// This class is a generic parser that is able to handle any string
-/// parameter. By default it stores the value in external global container
-/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
-/// in subnet config), it can be pointed to a different storage, using
-/// setStorage() method. This class follows the parser interface, laid out
-/// in its base class, @ref DhcpConfigParser.
-///
-/// For overview of usability of this generic purpose parser, see
-/// @ref dhcpv4ConfigInherit page.
-class StringParser : public DhcpConfigParser {
-public:
-
-    /// @brief constructor for StringParser
-    /// @param param_name name of the configuration parameter being parsed
-    StringParser(const std::string& param_name)
-        :storage_(&string_defaults), param_name_(param_name) {
-        // Empty parameter name is invalid.
-        if (param_name_.empty()) {
-            isc_throw(DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-    }
-
-    /// @brief parses parameter value
-    ///
-    /// Parses configuration entry and stores it in storage. See
-    /// @ref setStorage() for details.
-    ///
-    /// @param value pointer to the content of parsed values
-    virtual void build(ConstElementPtr value) {
-        value_ = value->str();
-        boost::erase_all(value_, "\"");
-    }
-
-    /// @brief Stores the parsed value in a storage.
-    virtual void commit() {
-        if (storage_ != NULL && !param_name_.empty()) {
-            // If a given parameter already exists in the storage we override
-            // its value. If it doesn't we insert a new element.
-            storage_->setParam(param_name_, value_);
-        }
-    }
-
-    /// @brief factory that constructs StringParser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new StringParser(param_name));
-    }
-
-    /// @brief sets storage for value of this parameter
-    ///
-    /// See \ref dhcpv4ConfigInherit for details.
-    ///
-    /// @param storage pointer to the storage container
-    void setStorage(StringStorage* storage) {
-        storage_ = storage;
-    }
-
-private:
-    /// pointer to the storage, where parsed value will be stored
-    StringStorage* storage_;
-
-    /// name of the parameter to be parsed
-    std::string param_name_;
-
-    /// the actual parsed value
-    std::string value_;
-};
-
-
-/// @brief parser for interface list definition
-///
-/// This parser handles Dhcp4/interface entry.
-/// It contains a list of network interfaces that the server listens on.
-/// In particular, it can contain an entry called "all" or "any" that
-/// designates all interfaces.
-///
-/// It is useful for parsing Dhcp4/interface parameter.
-class InterfaceListConfigParser : public DhcpConfigParser {
-public:
-
-    /// @brief constructor
-    ///
-    /// As this is a dedicated parser, it must be used to parse
-    /// "interface" parameter only. All other types will throw exception.
-    ///
-    /// @param param_name name of the configuration parameter being parsed
-    /// @throw BadValue if supplied parameter name is not "interface"
-    InterfaceListConfigParser(const std::string& param_name) {
-        if (param_name != "interface") {
-            isc_throw(BadValue, "Internal error. Interface configuration "
-                      "parser called for the wrong parameter: " << param_name);
-        }
-    }
-
-    /// @brief parses parameters value
-    ///
-    /// Parses configuration entry (list of parameters) and adds each element
-    /// to the interfaces list.
-    ///
-    /// @param value pointer to the content of parsed values
-    virtual void build(ConstElementPtr value) {
-        BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
-            interfaces_.push_back(iface->str());
-        }
-    }
-
-    /// @brief commits interfaces list configuration
-    virtual void commit() {
-        /// @todo: Implement per interface listening. Currently always listening
-        /// on all interfaces.
-    }
-
-    /// @brief factory that constructs InterfaceListConfigParser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new InterfaceListConfigParser(param_name));
-    }
-
-private:
-    /// contains list of network interfaces
-    vector<string> interfaces_;
-};
-
 /// @brief parser for pool definition
 ///
 /// This parser handles pool definitions, i.e. a list of entries of one
@@ -461,6 +84,12 @@ public:
         // ignore parameter name, it is always Dhcp4/subnet4[X]/pool
     }
 
+    /// @brief constructor.
+    PoolParser(const std::string& /*param_name*/,  PoolStorage* pools)
+        :pools_(pools) {
+        // ignore parameter name, it is always Dhcp4/subnet4[X]/pool
+    }
+
     /// @brief parses the actual list
     ///
     /// This method parses the actual list of interfaces.
@@ -575,675 +204,6 @@ private:
     PoolStorage local_pools_;
 };
 
-/// @brief Parser for option data value.
-///
-/// This parser parses configuration entries that specify value of
-/// a single option. These entries include option name, option code
-/// and data carried by the option. The option data can be specified
-/// in one of the two available formats: binary value represented as
-/// a string of hexadecimal digits or a list of comma separated values.
-/// The format being used is controlled by csv-format configuration
-/// parameter. When setting this value to True, the latter format is
-/// used. The subsequent values in the CSV format apply to relevant
-/// option data fields in the configured option. For example the
-/// configuration: "data" : "192.168.2.0, 56, hello world" can be
-/// used to set values for the option comprising IPv4 address,
-/// integer and string data field. Note that order matters. If the
-/// order of values does not match the order of data fields within
-/// an option the configuration will not be accepted. If parsing
-/// is successful then an instance of an option is created and
-/// added to the storage provided by the calling class.
-class OptionDataParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// Class constructor.
-    OptionDataParser(const std::string&)
-        : options_(NULL),
-          // initialize option to NULL ptr
-          option_descriptor_(false) { }
-
-    /// @brief Parses the single option data.
-    ///
-    /// This method parses the data of a single option from the configuration.
-    /// The option data includes option name, option code and data being
-    /// carried by this option. Eventually it creates the instance of the
-    /// option.
-    ///
-    /// @warning setStorage must be called with valid storage pointer prior
-    /// to calling this method.
-    ///
-    /// @param option_data_entries collection of entries that define value
-    /// for a particular option.
-    /// @throw DhcpConfigError if invalid parameter specified in
-    /// the configuration.
-    /// @throw isc::InvalidOperation if failed to set storage prior to
-    /// calling build.
-    virtual void build(ConstElementPtr option_data_entries) {
-        if (options_ == NULL) {
-            isc_throw(isc::InvalidOperation, "Parser logic error: storage must be set before "
-                      "parsing option data.");
-        }
-        BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
-            ParserPtr parser;
-            if (param.first == "name" || param.first == "data" ||
-                param.first == "space") {
-                boost::shared_ptr<StringParser>
-                    name_parser(dynamic_cast<StringParser*>(StringParser::factory(param.first)));
-                if (name_parser) {
-                    name_parser->setStorage(&string_values_);
-                    parser = name_parser;
-                }
-            } else if (param.first == "code") {
-                boost::shared_ptr<Uint32Parser>
-                    code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::factory(param.first)));
-                if (code_parser) {
-                    code_parser->setStorage(&uint32_values_);
-                    parser = code_parser;
-                }
-            } else if (param.first == "csv-format") {
-                boost::shared_ptr<BooleanParser>
-                    value_parser(dynamic_cast<BooleanParser*>(BooleanParser::factory(param.first)));
-                if (value_parser) {
-                    value_parser->setStorage(&boolean_values_);
-                    parser = value_parser;
-                }
-            } else {
-                isc_throw(DhcpConfigError,
-                          "Parser error: option-data parameter not supported: "
-                          << param.first);
-            }
-            parser->build(param.second);
-            // Before we can create an option we need to get the data from
-            // the child parsers. The only way to do it is to invoke commit
-            // on them so as they store the values in appropriate storages
-            // that this class provided to them. Note that this will not
-            // modify values stored in the global storages so the configuration
-            // will remain consistent even parsing fails somewhere further on.
-            parser->commit();
-        }
-        // Try to create the option instance.
-        createOption();
-    }
-
-    /// @brief Commits option value.
-    ///
-    /// This function adds a new option to the storage or replaces an existing option
-    /// with the same code.
-    ///
-    /// @throw isc::InvalidOperation if failed to set pointer to storage or failed
-    /// to call build() prior to commit. If that happens data in the storage
-    /// remain un-modified.
-    virtual void commit() {
-        if (options_ == NULL) {
-            isc_throw(isc::InvalidOperation, "parser logic error: storage must be set before "
-                      "committing option data.");
-        } else  if (!option_descriptor_.option) {
-            // Before we can commit the new option should be configured. If it is not
-            // than somebody must have called commit() before build().
-            isc_throw(isc::InvalidOperation, "parser logic error: no option has been configured and"
-                      " thus there is nothing to commit. Has build() been called?");
-        }
-        uint16_t opt_type = option_descriptor_.option->getType();
-        Subnet::OptionContainerPtr options = options_->getItems(option_space_);
-        // The getItems() should never return NULL pointer. If there are no
-        // options configured for the particular option space a pointer
-        // to an empty container should be returned.
-        assert(options);
-        Subnet::OptionContainerTypeIndex& idx = options->get<1>();
-        // Try to find options with the particular option code in the main
-        // storage. If found, remove these options because they will be
-        // replaced with new one.
-        Subnet::OptionContainerTypeRange range =
-            idx.equal_range(opt_type);
-        if (std::distance(range.first, range.second) > 0) {
-            idx.erase(range.first, range.second);
-        }
-        // Append new option to the main storage.
-        options_->addItem(option_descriptor_, option_space_);
-    }
-
-    /// @brief Set storage for the parser.
-    ///
-    /// Sets storage for the parser. This storage points to the
-    /// vector of options and is used by multiple instances of
-    /// OptionDataParser. Each instance creates exactly one object
-    /// of dhcp::Option or derived type and appends it to this
-    /// storage.
-    ///
-    /// @param storage pointer to the options storage
-    void setStorage(OptionStorage* storage) {
-        options_ = storage;
-    }
-
-private:
-
-    /// @brief Create option instance.
-    ///
-    /// Creates an instance of an option and adds it to the provided
-    /// options storage. If the option data parsed by \ref build function
-    /// are invalid or insufficient this function emits an exception.
-    ///
-    /// @warning this function does not check if options_ storage pointer
-    /// is intitialized but this check is not needed here because it is done
-    /// in the \ref build function.
-    ///
-    /// @throw DhcpConfigError if parameters provided in the configuration
-    /// are invalid.
-    void createOption() {
-        // Option code is held in the uint32_t storage but is supposed to
-        // be uint16_t value. We need to check that value in the configuration
-        // does not exceed range of uint8_t and is not zero.
-        uint32_t option_code = uint32_values_.getParam("code");
-        if (option_code == 0) {
-            isc_throw(DhcpConfigError, "option code must not be zero."
-                      << " Option code '0' is reserved in DHCPv4.");
-        } else if (option_code > std::numeric_limits<uint8_t>::max()) {
-            isc_throw(DhcpConfigError, "invalid option code '" << option_code
-                      << "', it must not exceed '"
-                      << std::numeric_limits<uint8_t>::max() << "'");
-        }
-
-        // Check that the option name has been specified, is non-empty and does not
-        // contain spaces
-        std::string option_name = string_values_.getParam("name"); 
-        if (option_name.empty()) {
-            isc_throw(DhcpConfigError, "name of the option with code '"
-                      << option_code << "' is empty");
-        } else if (option_name.find(" ") != std::string::npos) {
-            isc_throw(DhcpConfigError, "invalid option name '" << option_name
-                      << "', space character is not allowed");
-        }
-
-        std::string option_space = string_values_.getParam("space"); 
-        if (!OptionSpace::validateName(option_space)) {
-            isc_throw(DhcpConfigError, "invalid option space name '"
-                      << option_space << "' specified for option '"
-                      << option_name << "' (code '" << option_code
-                      << "')");
-        }
-
-        OptionDefinitionPtr def;
-        if (option_space == "dhcp4" &&
-            LibDHCP::isStandardOption(Option::V4, option_code)) {
-            def = LibDHCP::getOptionDef(Option::V4, option_code);
-
-        } else if (option_space == "dhcp6") {
-            isc_throw(DhcpConfigError, "'dhcp6' option space name is reserved"
-                      << " for DHCPv6 server");
-        } else {
-            // If we are not dealing with a standard option then we
-            // need to search for its definition among user-configured
-            // options. They are expected to be in the global storage
-            // already.
-            OptionDefContainerPtr defs = option_def_intermediate.getItems(option_space);
-            // The getItems() should never return the NULL pointer. If there are
-            // no option definitions for the particular option space a pointer
-            // to an empty container should be returned.
-            assert(defs);
-            const OptionDefContainerTypeIndex& idx = defs->get<1>();
-            OptionDefContainerTypeRange range = idx.equal_range(option_code);
-            if (std::distance(range.first, range.second) > 0) {
-                def = *range.first;
-            }
-            if (!def) {
-                isc_throw(DhcpConfigError, "definition for the option '"
-                          << option_space << "." << option_name
-                          << "' having code '" <<  option_code
-                          << "' does not exist");
-            }
-
-        }
-
-        // Get option data from the configuration database ('data' field).
-        const std::string option_data = string_values_.getParam("data");
-        const bool csv_format = boolean_values_.getParam("csv-format");
-
-        // Transform string of hexadecimal digits into binary format.
-        std::vector<uint8_t> binary;
-        std::vector<std::string> data_tokens;
-
-        if (csv_format) {
-            // If the option data is specified as a string of comma
-            // separated values then we need to split this string into
-            // individual values - each value will be used to initialize
-            // one data field of an option.
-            data_tokens = isc::util::str::tokens(option_data, ",");
-        } else {
-            // Otherwise, the option data is specified as a string of
-            // hexadecimal digits that we have to turn into binary format.
-            try {
-                util::encode::decodeHex(option_data, binary);
-            } catch (...) {
-                isc_throw(DhcpConfigError, "option data is not a valid"
-                          << " string of hexadecimal digits: " << option_data);
-            }
-        }
-
-        OptionPtr option;
-        if (!def) {
-            if (csv_format) {
-                isc_throw(DhcpConfigError, "the CSV option data format can be"
-                          " used to specify values for an option that has a"
-                          " definition. The option with code " << option_code
-                          << " does not have a definition.");
-            }
-
-            // @todo We have a limited set of option definitions intiialized at the moment.
-            // In the future we want to initialize option definitions for all options.
-            // Consequently an error will be issued if an option definition does not exist
-            // for a particular option code. For now it is ok to create generic option
-            // if definition does not exist.
-            OptionPtr option(new Option(Option::V4, static_cast<uint16_t>(option_code),
-                                        binary));
-            // The created option is stored in option_descriptor_ class member until the
-            // commit stage when it is inserted into the main storage. If an option with the
-            // same code exists in main storage already the old option is replaced.
-            option_descriptor_.option = option;
-            option_descriptor_.persistent = false;
-        } else {
-
-            // Option name should match the definition. The option name
-            // may seem to be redundant but in the future we may want
-            // to reference options and definitions using their names
-            // and/or option codes so keeping the option name in the
-            // definition of option value makes sense.
-            if (def->getName() != option_name) {
-                isc_throw(DhcpConfigError, "specified option name '"
-                          << option_name << "' does not match the "
-                          << "option definition: '" << option_space
-                          << "." << def->getName() << "'");
-            }
-
-            // Option definition has been found so let's use it to create
-            // an instance of our option.
-            try {
-                OptionPtr option = csv_format ?
-                    def->optionFactory(Option::V4, option_code, data_tokens) :
-                    def->optionFactory(Option::V4, option_code, binary);
-                Subnet::OptionDescriptor desc(option, false);
-                option_descriptor_.option = option;
-                option_descriptor_.persistent = false;
-            } catch (const isc::Exception& ex) {
-                isc_throw(DhcpConfigError, "option data does not match"
-                          << " option definition (space: " << option_space
-                          << ", code: " << option_code << "): "
-                          << ex.what());
-            }
-
-        }
-        // All went good, so we can set the option space name.
-        option_space_ = option_space;
-    }
-
-    /// Storage for uint32 values (e.g. option code).
-    Uint32Storage uint32_values_;
-    /// Storage for string values (e.g. option name or data).
-    StringStorage string_values_;
-    /// Storage for boolean values.
-    BooleanStorage boolean_values_;
-    /// Pointer to options storage. This storage is provided by
-    /// the calling class and is shared by all OptionDataParser objects.
-    OptionStorage* options_;
-    /// Option descriptor holds newly configured option.
-    Subnet::OptionDescriptor option_descriptor_;
-    /// Option space name where the option belongs to.
-    std::string option_space_;
-};
-
-/// @brief Parser for option data values within a subnet.
-///
-/// This parser iterates over all entries that define options
-/// data for a particular subnet and creates a collection of options.
-/// If parsing is successful, all these options are added to the Subnet
-/// object.
-class OptionDataListParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// Unless otherwise specified, parsed options will be stored in
-    /// a global option container (option_default). That storage location
-    /// is overriden on a subnet basis.
-    OptionDataListParser(const std::string&)
-        : options_(&option_defaults), local_options_() { }
-
-    /// @brief Parses entries that define options' data for a subnet.
-    ///
-    /// This method iterates over all entries that define option data
-    /// for options within a single subnet and creates options' instances.
-    ///
-    /// @param option_data_list pointer to a list of options' data sets.
-    /// @throw DhcpConfigError if option parsing failed.
-    void build(ConstElementPtr option_data_list) {
-        BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
-            boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
-            // options_ member will hold instances of all options thus
-            // each OptionDataParser takes it as a storage.
-            parser->setStorage(&local_options_);
-            // Build the instance of a single option.
-            parser->build(option_value);
-            // Store a parser as it will be used to commit.
-            parsers_.push_back(parser);
-        }
-    }
-
-    /// @brief Set storage for option instances.
-    ///
-    /// @param storage pointer to options storage.
-    void setStorage(OptionStorage* storage) {
-        options_ = storage;
-    }
-
-
-    /// @brief Commit all option values.
-    ///
-    /// This function invokes commit for all option values.
-    void commit() {
-        BOOST_FOREACH(ParserPtr parser, parsers_) {
-            parser->commit();
-        }
-        // Parsing was successful and we have all configured
-        // options in local storage. We can now replace old values
-        // with new values.
-        std::swap(local_options_, *options_);
-    }
-
-    /// @brief Create DhcpDataListParser object
-    ///
-    /// @param param_name param name.
-    ///
-    /// @return DhcpConfigParser object.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new OptionDataListParser(param_name));
-    }
-
-    /// Pointer to options instances storage.
-    OptionStorage* options_;
-    /// Intermediate option storage. This storage is used by
-    /// lower level parsers to add new options.  Values held
-    /// in this storage are assigned to main storage (options_)
-    /// if overall parsing was successful.
-    OptionStorage local_options_;
-    /// Collection of parsers;
-    ParserCollection parsers_;
-};
-
-/// @brief Parser for a single option definition.
-///
-/// This parser creates an instance of a single option definition.
-class OptionDefParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// This constructor sets the pointer to the option definitions
-    /// storage to NULL. It must be set to point to the actual storage
-    /// before \ref build is called.
-    OptionDefParser(const std::string&)
-        : storage_(NULL) {
-    }
-
-    /// @brief Parses an entry that describes single option definition.
-    ///
-    /// @param option_def a configuration entry to be parsed.
-    ///
-    /// @throw DhcpConfigError if parsing was unsuccessful.
-    void build(ConstElementPtr option_def) {
-        if (storage_ == NULL) {
-            isc_throw(DhcpConfigError, "parser logic error: storage must be set"
-                      " before parsing option definition data");
-        }
-        // Parse the elements that make up the option definition.
-        BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
-            std::string entry(param.first);
-            ParserPtr parser;
-            if (entry == "name" || entry == "type" ||
-                entry == "record-types" || entry == "space" ||
-                entry == "encapsulate") {
-                StringParserPtr
-                    str_parser(dynamic_cast<StringParser*>(StringParser::factory(entry)));
-                if (str_parser) {
-                    str_parser->setStorage(&string_values_);
-                    parser = str_parser;
-                }
-            } else if (entry == "code") {
-                Uint32ParserPtr
-                    code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::factory(entry)));
-                if (code_parser) {
-                    code_parser->setStorage(&uint32_values_);
-                    parser = code_parser;
-                }
-            } else if (entry == "array") {
-                BooleanParserPtr
-                    array_parser(dynamic_cast<BooleanParser*>(BooleanParser::factory(entry)));
-                if (array_parser) {
-                    array_parser->setStorage(&boolean_values_);
-                    parser = array_parser;
-                }
-            } else {
-                isc_throw(DhcpConfigError, "invalid parameter: " << entry);
-            }
-
-            parser->build(param.second);
-            parser->commit();
-        }
-
-        // Create an instance of option definition.
-        createOptionDef();
-
-        // Get all items we collected so far for the particular option space.
-        OptionDefContainerPtr defs = storage_->getItems(option_space_name_);
-        // Check if there are any items with option code the same as the
-        // one specified for the definition we are now creating.
-        const OptionDefContainerTypeIndex& idx = defs->get<1>();
-        const OptionDefContainerTypeRange& range =
-            idx.equal_range(option_definition_->getCode());
-        // If there are any items with this option code already we need
-        // to issue an error because we don't allow duplicates for
-        // option definitions within an option space.
-        if (std::distance(range.first, range.second) > 0) {
-            isc_throw(DhcpConfigError, "duplicated option definition for"
-                      << " code '" << option_definition_->getCode() << "'");
-        }
-    }
-
-    /// @brief Stores the parsed option definition in a storage.
-    void commit() {
-        if (storage_ && option_definition_ &&
-            OptionSpace::validateName(option_space_name_)) {
-            storage_->addItem(option_definition_, option_space_name_);
-        }
-    }
-
-    /// @brief Sets a pointer to the data store.
-    ///
-    /// The newly created instance of an option definition will be
-    /// added to the data store given by the argument.
-    ///
-    /// @param storage pointer to the data store where the option definition
-    /// will be added to.
-    void setStorage(OptionDefStorage* storage) {
-        storage_ = storage;
-    }
-
-private:
-
-    /// @brief Create option definition from the parsed parameters.
-    void createOptionDef() {
-
-        // Get the option space name and validate it.
-        std::string space = string_values_.getParam("space");
-        if (!OptionSpace::validateName(space)) {
-            isc_throw(DhcpConfigError, "invalid option space name '"
-                      << space << "'");
-        }
-
-        // Get other parameters that are needed to create the
-        // option definition.
-        std::string name = string_values_.getParam("name");
-        uint32_t code = uint32_values_.getParam("code");
-        std::string type = string_values_.getParam("type");
-        bool array_type = boolean_values_.getParam("array");
-        std::string encapsulates = string_values_.getParam("encapsulate");
-
-        // Create option definition.
-        OptionDefinitionPtr def;
-        // We need to check if user has set encapsulated option space
-        // name. If so, different constructor will be used.
-        if (!encapsulates.empty()) {
-            // Arrays can't be used together with sub-options.
-            if (array_type) {
-                isc_throw(DhcpConfigError, "option '" << space << "."
-                          << "name" << "', comprising an array of data"
-                          << " fields may not encapsulate any option space");
-
-            } else if (encapsulates == space) {
-                isc_throw(DhcpConfigError, "option must not encapsulate"
-                          << " an option space it belongs to: '"
-                          << space << "." << name << "' is set to"
-                          << " encapsulate '" << space << "'");
-
-            } else {
-                def.reset(new OptionDefinition(name, code, type,
-                                               encapsulates.c_str()));
-            }
-
-        } else {
-            def.reset(new OptionDefinition(name, code, type, array_type));
-
-        }
-        // The record-types field may carry a list of comma separated names
-        // of data types that form a record.
-        std::string record_types = string_values_.getParam("record-types");
-
-        // Split the list of record types into tokens.
-        std::vector<std::string> record_tokens =
-            isc::util::str::tokens(record_types, ",");
-        // Iterate over each token and add a record type into
-        // option definition.
-        BOOST_FOREACH(std::string record_type, record_tokens) {
-            try {
-                boost::trim(record_type);
-                if (!record_type.empty()) {
-                    def->addRecordField(record_type);
-                }
-            } catch (const Exception& ex) {
-                isc_throw(DhcpConfigError, "invalid record type values"
-                          << " specified for the option definition: "
-                          << ex.what());
-            }
-        }
-
-        // Check the option definition parameters are valid.
-        try {
-            def->validate();
-        } catch (const isc::Exception& ex) {
-            isc_throw(DhcpConfigError, "invalid option definition"
-                      << " parameters: " << ex.what());
-        }
-        // Option definition has been created successfully.
-        option_space_name_ = space;
-        option_definition_ = def;
-    }
-
-    /// Instance of option definition being created by this parser.
-    OptionDefinitionPtr option_definition_;
-    /// Name of the space the option definition belongs to.
-    std::string option_space_name_;
-
-    /// Pointer to a storage where the option definition will be
-    /// added when \ref commit is called.
-    OptionDefStorage* storage_;
-
-    /// Storage for boolean values.
-    BooleanStorage boolean_values_;
-    /// Storage for string values.
-    StringStorage string_values_;
-    /// Storage for uint32 values.
-    Uint32Storage uint32_values_;
-};
-
-/// @brief Parser for a list of option definitions.
-///
-/// This parser iterates over all configuration entries that define
-/// option definitions and creates instances of these definitions.
-/// If the parsing is successful, the collection of created definitions
-/// is put into the provided storage.
-class OptionDefListParser : DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// This constructor initializes the pointer to option definitions
-    /// storage to NULL value. This pointer has to be set to point to
-    /// the actual storage before the \ref build function is called.
-    OptionDefListParser(const std::string&) {
-    }
-
-    /// @brief Parse configuration entries.
-    ///
-    /// This function parses configuration entries and creates instances
-    /// of option definitions.
-    ///
-    /// @param option_def_list pointer to an element that holds entries
-    /// that define option definitions.
-    /// @throw DhcpConfigError if configuration parsing fails.
-    void build(ConstElementPtr option_def_list) {
-        // Clear existing items in the global storage.
-        // We are going to replace all of them.
-        option_def_intermediate.clearItems();
-
-        if (!option_def_list) {
-            isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
-                      << " option definitions is NULL");
-        }
-
-        BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
-            boost::shared_ptr<OptionDefParser>
-                parser(new OptionDefParser("single-option-def"));
-            parser->setStorage(&option_def_intermediate);
-            parser->build(option_def);
-            parser->commit();
-        }
-    }
-
-    /// @brief Stores option definitions in the CfgMgr.
-    void commit() {
-
-        CfgMgr& cfg_mgr = CfgMgr::instance();
-
-        cfg_mgr.deleteOptionDefs();
-
-        // We need to move option definitions from the temporary
-        // storage to the global storage.
-        std::list<std::string> space_names =
-            option_def_intermediate.getOptionSpaceNames();
-        BOOST_FOREACH(std::string space_name, space_names) {
-
-            BOOST_FOREACH(OptionDefinitionPtr def,
-                          *option_def_intermediate.getItems(space_name)) {
-                // All option definitions should be initialized to non-NULL
-                // values. The validation is expected to be made by the
-                // OptionDefParser when creating an option definition.
-                assert(def);
-                cfg_mgr.addOptionDef(def, space_name);
-            }
-        }
-    }
-
-    /// @brief Create an OptionDefListParser object.
-    ///
-    /// @param param_name configuration entry holding option definitions.
-    ///
-    /// @return OptionDefListParser object.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new OptionDefListParser(param_name));
-    }
-
-};
-
 /// @brief this class parses a single subnet
 ///
 /// This class parses the whole subnet definition. It creates parsers
@@ -1264,30 +224,10 @@ public:
 
         BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
             ParserPtr parser(createSubnet4ConfigParser(param.first));
-            // The actual type of the parser is unknown here. We have to discover
-            // the parser type here to invoke the corresponding setStorage function
-            // on it.  We discover parser type by trying to cast the parser to various
-            // parser types and checking which one was successful. For this one
-            // a setStorage and build methods are invoked.
-
-            // Try uint32 type parser.
-            if (!buildParser<Uint32Parser, Uint32Storage >(parser, uint32_values_,
-                                                          param.second) &&
-                // Try string type parser.
-                !buildParser<StringParser, StringStorage >(parser, string_values_,
-                                                           param.second) &&
-                // Try pool parser.
-                !buildParser<PoolParser, PoolStorage >(parser, pools_,
-                                                       param.second) &&
-                // Try option data parser.
-                !buildParser<OptionDataListParser, OptionStorage >(parser, options_,
-                                                                   param.second)) {
-                // Appropriate parsers are created in the createSubnet6ConfigParser
-                // and they should be limited to those that we check here for. Thus,
-                // if we fail to find a matching parser here it is a programming error.
-                isc_throw(DhcpConfigError, "failed to find suitable parser");
-            }
+            parser->build(param.second);
+            parsers_.push_back(parser);
         }
+
         // In order to create new subnet we need to get the data out
         // of the child parsers first. The only way to do it is to
         // invoke commit on them because it will make them write
@@ -1319,40 +259,6 @@ public:
 
 private:
 
-    /// @brief Set storage for a parser and invoke build.
-    ///
-    /// This helper method casts the provided parser pointer to the specified
-    /// type. If the cast is successful it sets the corresponding storage for
-    /// this parser, invokes build on it and saves the parser.
-    ///
-    /// @tparam T parser type to which parser argument should be cast.
-    /// @tparam Y storage type for the specified parser type.
-    /// @param parser parser on which build must be invoked.
-    /// @param storage reference to a storage that will be set for a parser.
-    /// @param subnet subnet element read from the configuration and being parsed.
-    /// @return true if parser pointer was successfully cast to specialized
-    /// parser type provided as Y.
-    template<typename T, typename Y>
-    bool buildParser(const ParserPtr& parser, Y& storage, const ConstElementPtr& subnet) {
-        // We need to cast to T in order to set storage for the parser.
-        boost::shared_ptr<T> cast_parser = boost::dynamic_pointer_cast<T>(parser);
-        // It is common that this cast is not successful because we try to cast to all
-        // supported parser types as we don't know the type of a parser in advance.
-        if (cast_parser) {
-            // Cast, successful so we go ahead with setting storage and actual parse.
-            cast_parser->setStorage(&storage);
-            parser->build(subnet);
-            parsers_.push_back(parser);
-            // We indicate that cast was successful so as the calling function
-            // may skip attempts to cast to other parser types and proceed to
-            // next element.
-            return (true);
-        }
-        // It was not successful. Indicate that another parser type
-        // should be tried.
-        return (false);
-    }
-
     /// @brief Append sub-options to an option.
     ///
     /// @param option_space a name of the encapsulated option space.
@@ -1418,7 +324,7 @@ private:
         try {
             subnet_txt = string_values_.getParam("subnet"); 
         } catch (DhcpConfigError) {
-            // Rethrow with precise error.
+            // rethrow with precise error
             isc_throw(DhcpConfigError,
                       "Mandatory subnet definition in subnet missing");
         }
@@ -1534,24 +440,27 @@ private:
     /// @return parser object for specified entry name
     /// @throw NotImplemented if trying to create a parser for unknown config element
     DhcpConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
-        FactoryMap factories;
-        factories["valid-lifetime"] = Uint32Parser::factory;
-        factories["renew-timer"] = Uint32Parser::factory;
-        factories["rebind-timer"] = Uint32Parser::factory;
-        factories["subnet"] = StringParser::factory;
-        factories["pool"] = PoolParser::factory;
-        factories["option-data"] = OptionDataListParser::factory;
-
-        FactoryMap::iterator f = factories.find(config_id);
-        if (f == factories.end()) {
-            // Used for debugging only.
-            // return new DebugParser(config_id);
-
+        DhcpConfigParser *parser = NULL;
+        if ((config_id.compare("valid-lifetime") == 0)  ||
+            (config_id.compare("renew-timer") == 0)  ||
+            (config_id.compare("rebind-timer") == 0))  {
+            parser = new Uint32Parser(config_id, &uint32_values_);
+        }
+        else if (config_id.compare("subnet") == 0) {
+            parser = new StringParser(config_id, &string_values_);
+        }
+        else if (config_id.compare("pool") == 0) {
+            parser = new PoolParser(config_id, &pools_);
+        }
+        else if (config_id.compare("option-data") == 0) {
+           parser = new OptionDataListParser(config_id, &options_, &option_def_intermediate,
+                                            Dhcp4OptionDataParser::factory);
+        } else {
             isc_throw(NotImplemented,
-                      "parser error: Subnet4 parameter not supported: "
-                      << config_id);
+                "parser error: Subnet4 parameter not supported: " << config_id);
         }
-        return (f->second(config_id));
+
+        return (parser);
     }
 
     /// @brief Returns value for a given parameter (after using inheritance)
@@ -1622,16 +531,11 @@ public:
     ///
     /// @param subnets_list pointer to a list of IPv4 subnets
     void build(ConstElementPtr subnets_list) {
-
-        // No need to define FactoryMap here. There's only one type
-        // used: Subnet4ConfigParser
-
         BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
             ParserPtr parser(new Subnet4ConfigParser("subnet"));
             parser->build(subnet);
             subnets_.push_back(parser);
         }
-
     }
 
     /// @brief commits subnets definitions.
@@ -1668,6 +572,34 @@ public:
 namespace isc {
 namespace dhcp {
 
+//************** Dhcp4OptionDataParser methods *******************************
+
+Dhcp4OptionDataParser::Dhcp4OptionDataParser(const std::string& param_name, 
+    OptionStorage *options, OptionDefStorage *option_defs)
+    :OptionDataParser(param_name, options, option_defs, Option::V4) {
+}
+
+OptionDataParser* Dhcp4OptionDataParser::factory(const std::string& param_name,
+    OptionStorage *options, OptionDefStorage *option_defs) {
+    return new Dhcp4OptionDataParser(param_name, options, option_defs);
+}
+
+OptionDefinitionPtr Dhcp4OptionDataParser::findServerSpaceOptionDefinition (
+    std::string& option_space, uint32_t option_code) {
+    OptionDefinitionPtr def;
+
+    if (option_space == "dhcp4" &&
+        LibDHCP::isStandardOption(Option::V4, option_code)) {
+        def = LibDHCP::getOptionDef(Option::V4, option_code);
+
+    } else if (option_space == "dhcp6") {
+        isc_throw(DhcpConfigError, "'dhcp6' option space name is reserved"
+                << " for DHCPv6 server");
+    }
+
+    return def;
+}
+
 /// @brief creates global parsers
 ///
 /// This method creates global parsers that parse global parameters, i.e.
@@ -1677,28 +609,39 @@ namespace dhcp {
 /// @return parser for specified global DHCPv4 parameter
 /// @throw NotImplemented if trying to create a parser for unknown config element
 DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
-    FactoryMap factories;
-
-    factories["valid-lifetime"] = Uint32Parser::factory;
-    factories["renew-timer"] = Uint32Parser::factory;
-    factories["rebind-timer"] = Uint32Parser::factory;
-    factories["interface"] = InterfaceListConfigParser::factory;
-    factories["subnet4"] = Subnets4ListConfigParser::factory;
-    factories["option-data"] = OptionDataListParser::factory;
-    factories["option-def"] = OptionDefListParser::factory;
-    factories["version"] = StringParser::factory;
-    factories["lease-database"] = DbAccessParser::factory;
-
-    FactoryMap::iterator f = factories.find(config_id);
-    if (f == factories.end()) {
-        // Used for debugging only.
-        // return new DebugParser(config_id);
-
+    DhcpConfigParser *parser = NULL;
+    if ((config_id.compare("valid-lifetime") == 0)  ||
+        (config_id.compare("renew-timer") == 0)  ||
+        (config_id.compare("rebind-timer") == 0))  {
+        parser = new Uint32Parser(config_id, &uint32_defaults);
+    }
+    else if (config_id.compare("interface") == 0) {
+        parser = new InterfaceListConfigParser(config_id);
+    }
+    else if (config_id.compare("subnet4") == 0) {
+        parser = new Subnets4ListConfigParser(config_id);
+    }
+    else if (config_id.compare("option-data") == 0) {
+        parser = new OptionDataListParser(config_id, &option_defaults, 
+                                          &option_def_intermediate,
+                                          Dhcp4OptionDataParser::factory);
+    }
+    else if (config_id.compare("option-def") == 0) {
+        parser  = new OptionDefListParser(config_id, &option_def_intermediate);
+    }
+    else if (config_id.compare("version") == 0) {
+        parser  = new StringParser(config_id, &string_defaults);
+    }
+    else if (config_id.compare("lease-database") == 0) {
+        parser = new DbAccessParser(config_id); 
+    }
+    else {
         isc_throw(NotImplemented,
-                  "Parser error: Global configuration parameter not supported: "
-                  << config_id);
+                "Parser error: Global configuration parameter not supported: "
+                << config_id);
     }
-    return (f->second(config_id));
+
+    return (parser);
 }
 
 isc::data::ConstElementPtr
@@ -1790,6 +733,7 @@ configureDhcp4Server(Dhcpv4Srv&, ConstElementPtr config_set) {
     } catch (const isc::Exception& ex) {
         LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
                   .arg(config_pair.first).arg(ex.what());
+        std::cout << "parse failed on:" << config_pair.first << std::endl;
         answer = isc::config::createAnswer(1,
                      string("Configuration parsing failed: ") + ex.what());
 
@@ -1834,6 +778,13 @@ configureDhcp4Server(Dhcpv4Srv&, ConstElementPtr config_set) {
 
     // Rollback changes as the configuration parsing failed.
     if (rollback) {
+
+    // TKM - take this out, its just here for diagnostics
+    std::cout << "***************" <<  std::endl;
+    std::cout << "answer is:" <<  std::endl;
+    answer->toJSON(std::cout);
+    std::cout << std::endl << "***************" <<  std::endl;
+
         std::swap(uint32_defaults, uint32_local);
         std::swap(string_defaults, string_local);
         std::swap(option_defaults, option_local);
@@ -1854,3 +805,4 @@ const Uint32Storage& getUint32Defaults() {
 
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
+
index 51a7556204509e47b5383243bdd1f6f8c69a31d0..578b637ce40c556879b0d7f30bdde3c4ab6391cd 100644 (file)
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <exceptions/exceptions.h>
-#include <dhcpsrv/dhcp_config_parser.h>
 #include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/dhcp_parsers.h>
+
 #include <stdint.h>
 #include <string>
 
@@ -69,6 +70,49 @@ configureDhcp4Server(Dhcpv4Srv&,
 /// @return a reference to a global uint32 values storage.
 const Uint32Storage& getUint32Defaults();
 
+
+/// @brief Parser for DHCP4 option data value.
+///
+/// This parser parses configuration entries that specify value of
+/// a single option specific to DHCP4.  It provides the DHCP4-specific
+/// implementation of the abstract class OptionDataParser.
+class Dhcp4OptionDataParser : public OptionDataParser {
+public:
+    /// @brief Constructor.
+    ///
+    /// Class constructor.
+    Dhcp4OptionDataParser(const std::string&, OptionStorage *options,
+        OptionDefStorage *option_defs);
+
+    /// @brief static factory method for instantiating Dhcp4OptionDataParsers
+    ///
+    /// @param param_name name fo the parameter to be parsed.
+    /// @param options storage where the parameter value is to be stored.
+    /// @param global_option_defs global option definitions storage 
+    static OptionDataParser* factory(const std::string& param_name, OptionStorage *options,
+        OptionDefStorage *global_option_defs);
+
+protected:
+    /// @brief Finds an option definition within the server's option space
+    /// 
+    /// Given an option space and an option code, find the correpsonding 
+    /// option defintion within the server's option defintion storage.
+    ///
+    /// @param option_space name of the parameter option space 
+    /// @param option_code numeric value of the parameter to find 
+    /// @return OptionDefintionPtr of the option defintion or an 
+    /// empty OptionDefinitionPtr if not found.
+    /// @throw DhcpConfigError if the option space requested is not valid 
+    /// for this server. 
+    virtual OptionDefinitionPtr findServerSpaceOptionDefinition (
+        std::string& option_space, uint32_t option_code);
+
+private:
+    // Private default Constructor declared for safety.
+    Dhcp4OptionDataParser() :OptionDataParser("",NULL,NULL,Option::V4) {}
+};
+
+
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 
index e99deeb7ffa02dc5c9316728424e370580131822..8e746076d7d279c0748fd8bc7a113be376a35adc 100644 (file)
@@ -22,6 +22,7 @@
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/dbaccess_parser.h>
 #include <dhcpsrv/dhcp_config_parser.h>
+#include <dhcpsrv/dhcp_parsers.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/triplet.h>
@@ -49,38 +50,17 @@ using namespace isc::asiolink;
 
 namespace {
 
-// Forward declarations of some of the parser classes.
-// They are used to define pointer types for these classes.
-class BooleanParser;
-class StringParser;
-class Uint32Parser;
-
 // Pointers to various parser objects.
 typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
 typedef boost::shared_ptr<StringParser> StringParserPtr;
 typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
 
-/// @brief Factory method that will create a parser for a given element name
-typedef isc::dhcp::DhcpConfigParser* ParserFactory(const std::string& config_id);
-
-/// @brief Collection of factories that create parsers for specified element names
-typedef std::map<std::string, ParserFactory*> FactoryMap;
-
-/// @brief Storage for option definitions.
-typedef OptionSpaceContainer<OptionDefContainer,
-                             OptionDefinitionPtr> OptionDefStorage;
-
 /// @brief Collection of address pools.
 ///
 /// This type is used as intermediate storage, when pools are parsed, but there is
 /// no subnet object created yet to store them.
 typedef std::vector<isc::dhcp::Pool6Ptr> PoolStorage;
 
-/// Collection of containers holding option spaces. Each container within
-/// a particular option space holds so-called option descriptors.
-typedef OptionSpaceContainer<Subnet::OptionContainer,
-                             Subnet::OptionDescriptor> OptionStorage;
-
 /// @brief Global uint32 parameters that will be used as defaults.
 Uint32Storage uint32_defaults;
 
@@ -93,381 +73,6 @@ OptionStorage option_defaults;
 /// @brief Global storage for option definitions.
 OptionDefStorage option_def_intermediate;
 
-/// @brief a dummy configuration parser
-///
-/// This is a debugging parser. It does not configure anything,
-/// will accept any configuration and will just print it out
-/// on commit.  Useful for debugging existing configurations and
-/// adding new ones.
-class DebugParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor
-    ///
-    /// See @ref DhcpConfigParser class for details.
-    ///
-    /// @param param_name name of the parsed parameter
-    DebugParser(const std::string& param_name)
-        :param_name_(param_name) {
-    }
-
-    /// @brief builds parameter value
-    ///
-    /// See @ref DhcpConfigParser class for details.
-    ///
-    /// @param new_config pointer to the new configuration
-    virtual void build(ConstElementPtr new_config) {
-        std::cout << "Build for token: [" << param_name_ << "] = ["
-                  << value_->str() << "]" << std::endl;
-        value_ = new_config;
-    }
-
-    /// @brief Pretends to apply the configuration.
-    ///
-    /// This is a method required by the base class. It pretends to apply the
-    /// configuration, but in fact it only prints the parameter out.
-    ///
-    /// See @ref DhcpConfigParser class for details.
-    virtual void commit() {
-        // Debug message. The whole DebugParser class is used only for parser
-        // debugging, and is not used in production code. It is very convenient
-        // to keep it around. Please do not turn this cout into logger calls.
-        std::cout << "Commit for token: [" << param_name_ << "] = ["
-                  << value_->str() << "]" << std::endl;
-    }
-
-    /// @brief factory that constructs DebugParser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new DebugParser(param_name));
-    }
-
-private:
-    /// name of the parsed parameter
-    std::string param_name_;
-
-    /// pointer to the actual value of the parameter
-    ConstElementPtr value_;
-};
-
-
-/// @brief A boolean value parser.
-///
-/// This parser handles configuration values of the boolean type.
-/// Parsed values are stored in a provided storage. If no storage
-/// is provided then the build function throws an exception.
-class BooleanParser : public DhcpConfigParser {
-public:
-    /// @brief Constructor.
-    ///
-    /// @param param_name name of the parameter.
-    BooleanParser(const std::string& param_name)
-        : storage_(NULL),
-          param_name_(param_name),
-          value_(false) {
-        // Empty parameter name is invalid.
-        if (param_name_.empty()) {
-            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-    }
-
-    /// @brief Parse a boolean value.
-    ///
-    /// @param value a value to be parsed.
-    ///
-    /// @throw isc::InvalidOperation if a storage has not been set
-    ///        prior to calling this function
-    /// @throw isc::dhcp::DhcpConfigError if a provided parameter's
-    ///        name is empty.
-    virtual void build(ConstElementPtr value) {
-        if (storage_ == NULL) {
-            isc_throw(isc::InvalidOperation, "parser logic error:"
-                      << " storage for the " << param_name_
-                      << " value has not been set");
-        } else if (param_name_.empty()) {
-            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-        // The Config Manager checks if user specified a
-        // valid value for a boolean parameter: True or False.
-        // It is then ok to assume that if str() does not return
-        // 'true' the value is 'false'.
-        value_ = (value->str() == "true") ? true : false;
-    }
-
-    /// @brief Put a parsed value to the storage.
-    virtual void commit() {
-        if (storage_ != NULL && !param_name_.empty()) {
-            storage_->setParam(param_name_, value_);
-        }
-    }
-
-    /// @brief Create an instance of the boolean parser.
-    ///
-    /// @param param_name name of the parameter for which the
-    ///        parser is created.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new BooleanParser(param_name));
-    }
-
-    /// @brief Set the storage for parsed value.
-    ///
-    /// This function must be called prior to calling build.
-    ///
-    /// @param storage a pointer to the storage where parsed data
-    ///        is to be stored.
-    void setStorage(BooleanStorage* storage) {
-        storage_ = storage;
-    }
-
-private:
-    /// Pointer to the storage where parsed value is stored.
-    BooleanStorage* storage_;
-    /// Name of the parameter which value is parsed with this parser.
-    std::string param_name_;
-    /// Parsed value.
-    bool value_;
-};
-
-/// @brief Configuration parser for uint32 parameters
-///
-/// This class is a generic parser that is able to handle any uint32 integer
-/// type. By default it stores the value in external global container
-/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
-/// in subnet config), it can be pointed to a different storage, using
-/// setStorage() method. This class follows the parser interface, laid out
-/// in its base class, @ref DhcpConfigParser.
-///
-/// For overview of usability of this generic purpose parser, see
-/// @ref dhcpv6ConfigInherit page.
-///
-/// @todo this class should be turned into the template class which
-/// will handle all uintX_types of data (see ticket #2415).
-class Uint32Parser : public DhcpConfigParser {
-public:
-
-    /// @brief constructor for Uint32Parser
-    ///
-    /// @param param_name name of the configuration parameter being parsed
-    Uint32Parser(const std::string& param_name)
-        : storage_(&uint32_defaults),
-          param_name_(param_name) {
-        // Empty parameter name is invalid.
-        if (param_name_.empty()) {
-            isc_throw(DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-    }
-
-    /// @brief Parses configuration configuration parameter as uint32_t.
-    ///
-    /// @param value pointer to the content of parsed values
-    /// @throw isc::dhcp::DhcpConfigError if failed to parse
-    ///        the configuration parameter as uint32_t value.
-    virtual void build(ConstElementPtr value) {
-        if (param_name_.empty()) {
-            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-
-        bool parse_error = false;
-        // Cast the provided value to int64 value to check.
-        int64_t int64value = 0;
-        try {
-            // Parsing the value as a int64 value allows to
-            // check if the provided value is within the range
-            // of uint32_t (is not negative or greater than
-            // maximal uint32_t value).
-            int64value = boost::lexical_cast<int64_t>(value->str());
-        } catch (const boost::bad_lexical_cast&) {
-            parse_error = true;
-        }
-        if (!parse_error) {
-            // Check that the value is not out of bounds.
-            if ((int64value < 0) ||
-                (int64value > std::numeric_limits<uint32_t>::max())) {
-                parse_error = true;
-            } else {
-                // A value is not out of bounds so let's cast it to
-                // the uint32_t type.
-                value_ = static_cast<uint32_t>(int64value);
-            }
-
-        }
-        // Invalid value provided.
-        if (parse_error) {
-            isc_throw(isc::dhcp::DhcpConfigError, "Failed to parse value " << value->str()
-                      << " as unsigned 32-bit integer.");
-        }
-    }
-
-    /// @brief Stores the parsed uint32_t value in a storage.
-    virtual void commit() {
-        if (storage_ != NULL) {
-            // If a given parameter already exists in the storage we override
-            // its value. If it doesn't we insert a new element.
-            storage_->setParam(param_name_, value_);
-        }
-    }
-
-    /// @brief Factory that constructs Uint32Parser objects.
-    ///
-    /// @param param_name name of the parameter to be parsed.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new Uint32Parser(param_name));
-    }
-
-    /// @brief Sets storage for value of this parameter.
-    ///
-    /// See @ref dhcpv6ConfigInherit for details.
-    ///
-    /// @param storage pointer to the storage container.
-    void setStorage(Uint32Storage* storage) {
-        storage_ = storage;
-    }
-
-private:
-    /// pointer to the storage, where parsed value will be stored
-    Uint32Storage* storage_;
-    /// name of the parameter to be parsed
-    std::string param_name_;
-    /// the actual parsed value
-    uint32_t value_;
-};
-
-/// @brief Configuration parser for string parameters
-///
-/// This class is a generic parser that is able to handle any string
-/// parameter. By default it stores the value in an external global container
-/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
-/// in subnet config), it can be pointed to a different storage, using the
-/// setStorage() method. This class follows the parser interface, laid out
-/// in its base class, @ref DhcpConfigParser.
-///
-/// For overview of usability of this generic purpose parser, see
-/// @ref dhcpv6ConfigInherit page.
-class StringParser : public DhcpConfigParser {
-public:
-
-    /// @brief constructor for StringParser
-    ///
-    /// @param param_name name of the configuration parameter being parsed
-    StringParser(const std::string& param_name)
-        : storage_(&string_defaults),
-          param_name_(param_name) {
-        // Empty parameter name is invalid.
-        if (param_name_.empty()) {
-            isc_throw(DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-    }
-
-    /// @brief parses parameter value
-    ///
-    /// Parses configuration parameter's value as string.
-    ///
-    /// @param value pointer to the content of parsed values
-    /// @throws DhcpConfigError if the parsed parameter's name is empty.
-    virtual void build(ConstElementPtr value) {
-        if (param_name_.empty()) {
-            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
-                      << "empty parameter name provided");
-        }
-        value_ = value->str();
-        boost::erase_all(value_, "\"");
-    }
-
-    /// @brief Stores the parsed value in a storage.
-    virtual void commit() {
-        if (storage_ != NULL && !param_name_.empty()) {
-            // If a given parameter already exists in the storage we override
-            // its value. If it doesn't we insert a new element.
-            storage_->setParam(param_name_, value_);
-        }
-    }
-
-    /// @brief Factory that constructs StringParser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new StringParser(param_name));
-    }
-
-    /// @brief Sets storage for value of this parameter.
-    ///
-    /// See @ref dhcpv6ConfigInherit for details.
-    ///
-    /// @param storage pointer to the storage container
-    void setStorage(StringStorage* storage) {
-        storage_ = storage;
-    }
-
-private:
-    /// Pointer to the storage, where parsed value will be stored
-    StringStorage* storage_;
-    /// Name of the parameter to be parsed
-    std::string param_name_;
-    /// The actual parsed value
-    std::string value_;
-};
-
-/// @brief parser for interface list definition
-///
-/// This parser handles Dhcp6/interface entry.
-/// It contains a list of network interfaces that the server listens on.
-/// In particular, it can contain an entry called "all" or "any" that
-/// designates all interfaces.
-///
-/// It is useful for parsing Dhcp6/interface parameter.
-class InterfaceListConfigParser : public DhcpConfigParser {
-public:
-
-    /// @brief constructor
-    ///
-    /// As this is a dedicated parser, it must be used to parse
-    /// "interface" parameter only. All other types will throw exception.
-    ///
-    /// @param param_name name of the configuration parameter being parsed
-    /// @throw BadValue if supplied parameter name is not "interface"
-    InterfaceListConfigParser(const std::string& param_name) {
-        if (param_name != "interface") {
-            isc_throw(isc::BadValue, "Internal error. Interface configuration "
-                      "parser called for the wrong parameter: " << param_name);
-        }
-    }
-
-    /// @brief parses parameters value
-    ///
-    /// Parses configuration entry (list of parameters) and stores it in
-    /// storage.
-    ///
-    /// @param value pointer to the content of parsed values
-    virtual void build(ConstElementPtr value) {
-        BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
-            interfaces_.push_back(iface->str());
-        }
-    }
-
-    /// @brief commits interfaces list configuration
-    virtual void commit() {
-        /// @todo: Implement per interface listening. Currently always listening
-        /// on all interfaces.
-    }
-
-    /// @brief factory that constructs InterfaceListConfigParser objects
-    ///
-    /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new InterfaceListConfigParser(param_name));
-    }
-
-private:
-    /// contains list of network interfaces
-    vector<string> interfaces_;
-};
-
 /// @brief parser for pool definition
 ///
 /// This parser handles pool definitions, i.e. a list of entries of one
@@ -487,6 +92,12 @@ public:
         // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
     }
 
+    /// @brief constructor.
+    PoolParser(const std::string& /*param_name*/,  PoolStorage* pools)
+        :pools_(pools) {
+        // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
+    }
+
     /// @brief parses the actual list
     ///
     /// This method parses the actual list of interfaces.
@@ -602,674 +213,6 @@ private:
     PoolStorage local_pools_;
 };
 
-
-/// @brief Parser for option data value.
-///
-/// This parser parses configuration entries that specify value of
-/// a single option. These entries include option name, option code
-/// and data carried by the option. The option data can be specified
-/// in one of the two available formats: binary value represented as
-/// a string of hexadecimal digits or a list of comma separated values.
-/// The format being used is controlled by csv-format configuration
-/// parameter. When setting this value to True, the latter format is
-/// used. The subsequent values in the CSV format apply to relevant
-/// option data fields in the configured option. For example the
-/// configuration: "data" : "192.168.2.0, 56, hello world" can be
-/// used to set values for the option comprising IPv4 address,
-/// integer and string data field. Note that order matters. If the
-/// order of values does not match the order of data fields within
-/// an option the configuration will not be accepted. If parsing
-/// is successful then an instance of an option is created and
-/// added to the storage provided by the calling class.
-class OptionDataParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// Class constructor.
-    OptionDataParser(const std::string&)
-        : options_(NULL),
-          // initialize option to NULL ptr
-          option_descriptor_(false) { }
-
-    /// @brief Parses the single option data.
-    ///
-    /// This method parses the data of a single option from the configuration.
-    /// The option data includes option name, option code and data being
-    /// carried by this option. Eventually it creates the instance of the
-    /// option.
-    ///
-    /// @warning setStorage must be called with valid storage pointer prior
-    /// to calling this method.
-    ///
-    /// @param option_data_entries collection of entries that define value
-    /// for a particular option.
-    /// @throw DhcpConfigError if invalid parameter specified in
-    /// the configuration.
-    /// @throw isc::InvalidOperation if failed to set storage prior to
-    /// calling build.
-    virtual void build(ConstElementPtr option_data_entries) {
-
-        if (options_ == NULL) {
-            isc_throw(isc::InvalidOperation, "Parser logic error: storage must be set before "
-                      "parsing option data.");
-        }
-        BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
-            ParserPtr parser;
-            if (param.first == "name" || param.first == "data" ||
-                param.first == "space") {
-                boost::shared_ptr<StringParser>
-                    name_parser(dynamic_cast<StringParser*>(StringParser::factory(param.first)));
-                if (name_parser) {
-                    name_parser->setStorage(&string_values_);
-                    parser = name_parser;
-                }
-            } else if (param.first == "code") {
-                boost::shared_ptr<Uint32Parser>
-                    code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::factory(param.first)));
-                if (code_parser) {
-                    code_parser->setStorage(&uint32_values_);
-                    parser = code_parser;
-                }
-            } else if (param.first == "csv-format") {
-                boost::shared_ptr<BooleanParser>
-                    value_parser(dynamic_cast<BooleanParser*>(BooleanParser::factory(param.first)));
-                if (value_parser) {
-                    value_parser->setStorage(&boolean_values_);
-                    parser = value_parser;
-                }
-            } else {
-                isc_throw(DhcpConfigError,
-                          "parser error: option-data parameter not supported: "
-                          << param.first);
-            }
-            parser->build(param.second);
-            // Before we can create an option we need to get the data from
-            // the child parsers. The only way to do it is to invoke commit
-            // on them so as they store the values in appropriate storages
-            // that this class provided to them. Note that this will not
-            // modify values stored in the global storages so the configuration
-            // will remain consistent even parsing fails somewhere further on.
-            parser->commit();
-        }
-        // Try to create the option instance.
-        createOption();
-    }
-
-    /// @brief Commits option value.
-    ///
-    /// This function adds a new option to the storage or replaces an existing option
-    /// with the same code.
-    ///
-    /// @throw isc::InvalidOperation if failed to set pointer to storage or failed
-    /// to call build() prior to commit. If that happens data in the storage
-    /// remain un-modified.
-    virtual void commit() {
-        if (options_ == NULL) {
-            isc_throw(isc::InvalidOperation, "parser logic error: storage must be set before "
-                      "committing option data.");
-        } else  if (!option_descriptor_.option) {
-            // Before we can commit the new option should be configured. If it is not
-            // than somebody must have called commit() before build().
-            isc_throw(isc::InvalidOperation, "parser logic error: no option has been configured and"
-                      " thus there is nothing to commit. Has build() been called?");
-        }
-        uint16_t opt_type = option_descriptor_.option->getType();
-        Subnet::OptionContainerPtr options = options_->getItems(option_space_);
-        // The getItems() should never return NULL pointer. If there are no
-        // options configured for the particular option space a pointer
-        // to an empty container should be returned.
-        assert(options);
-        Subnet::OptionContainerTypeIndex& idx = options->get<1>();
-        // Try to find options with the particular option code in the main
-        // storage. If found, remove these options because they will be
-        // replaced with new one.
-        Subnet::OptionContainerTypeRange range =
-            idx.equal_range(opt_type);
-        if (std::distance(range.first, range.second) > 0) {
-            idx.erase(range.first, range.second);
-        }
-        // Append new option to the main storage.
-        options_->addItem(option_descriptor_, option_space_);
-    }
-
-    /// @brief Set storage for the parser.
-    ///
-    /// Sets storage for the parser. This storage points to the
-    /// vector of options and is used by multiple instances of
-    /// OptionDataParser. Each instance creates exactly one object
-    /// of dhcp::Option or derived type and appends it to this
-    /// storage.
-    ///
-    /// @param storage pointer to the options storage
-    void setStorage(OptionStorage* storage) {
-        options_ = storage;
-    }
-
-private:
-
-    /// @brief Create option instance.
-    ///
-    /// Creates an instance of an option and adds it to the provided
-    /// options storage. If the option data parsed by \ref build function
-    /// are invalid or insufficient this function emits an exception.
-    ///
-    /// @warning this function does not check if options_ storage pointer
-    /// is intitialized but this check is not needed here because it is done
-    /// in the \ref build function.
-    ///
-    /// @throw DhcpConfigError if parameters provided in the configuration
-    /// are invalid.
-    void createOption() {
-
-        // Option code is held in the uint32_t storage but is supposed to
-        // be uint16_t value. We need to check that value in the configuration
-        // does not exceed range of uint16_t and is not zero.
-        uint32_t option_code = uint32_values_.getParam("code");
-        if (option_code == 0) {
-            isc_throw(DhcpConfigError, "option code must not be zero."
-                      << " Option code '0' is reserved in DHCPv6.");
-        } else if (option_code > std::numeric_limits<uint16_t>::max()) {
-            isc_throw(DhcpConfigError, "invalid option code '" << option_code
-                      << "', it must not exceed '"
-                      << std::numeric_limits<uint16_t>::max() << "'");
-        }
-        // Check that the option name has been specified, is non-empty and does not
-        // contain spaces.
-        std::string option_name = string_values_.getParam("name");
-        if (option_name.empty()) {
-            isc_throw(DhcpConfigError, "name of the option with code '"
-                      << option_code << "' is empty");
-        } else if (option_name.find(" ") != std::string::npos) {
-            isc_throw(DhcpConfigError, "invalid option name '" << option_name
-                      << "', space character is not allowed");
-        }
-
-        std::string option_space = string_values_.getParam("space");
-        if (!OptionSpace::validateName(option_space)) {
-            isc_throw(DhcpConfigError, "invalid option space name '"
-                      << option_space << "' specified for option '"
-                      << option_name << "' (code '" << option_code
-                      << "')");
-        }
-
-        OptionDefinitionPtr def;
-        if (option_space == "dhcp6" &&
-            LibDHCP::isStandardOption(Option::V6, option_code)) {
-            def = LibDHCP::getOptionDef(Option::V6, option_code);
-
-        } else if (option_space == "dhcp4") {
-            isc_throw(DhcpConfigError, "'dhcp4' option space name is reserved"
-                      << " for DHCPv4 server");
-        } else {
-            // If we are not dealing with a standard option then we
-            // need to search for its definition among user-configured
-            // options. They are expected to be in the global storage
-            // already.
-            OptionDefContainerPtr defs = option_def_intermediate.getItems(option_space);
-            // The getItems() should never return the NULL pointer. If there are
-            // no option definitions for the particular option space a pointer
-            // to an empty container should be returned.
-            assert(defs);
-            const OptionDefContainerTypeIndex& idx = defs->get<1>();
-            OptionDefContainerTypeRange range = idx.equal_range(option_code);
-            if (std::distance(range.first, range.second) > 0) {
-                def = *range.first;
-            }
-            if (!def) {
-                isc_throw(DhcpConfigError, "definition for the option '"
-                          << option_space << "." << option_name
-                          << "' having code '" <<  option_code
-                          << "' does not exist");
-            }
-
-        }
-
-        // Get option data from the configuration database ('data' field).
-        const std::string option_data = string_values_.getParam("data");
-        const bool csv_format = boolean_values_.getParam("csv-format");
-
-        // Transform string of hexadecimal digits into binary format.
-        std::vector<uint8_t> binary;
-        std::vector<std::string> data_tokens;
-
-        if (csv_format) {
-            // If the option data is specified as a string of comma
-            // separated values then we need to split this string into
-            // individual values - each value will be used to initialize
-            // one data field of an option.
-            data_tokens = isc::util::str::tokens(option_data, ",");
-        } else {
-            // Otherwise, the option data is specified as a string of
-            // hexadecimal digits that we have to turn into binary format.
-            try {
-                util::encode::decodeHex(option_data, binary);
-            } catch (...) {
-                isc_throw(DhcpConfigError, "Parser error: option data is not a valid"
-                          << " string of hexadecimal digits: " << option_data);
-            }
-        }
-
-        OptionPtr option;
-        if (!def) {
-            if (csv_format) {
-                isc_throw(DhcpConfigError, "the CSV option data format can be"
-                          " used to specify values for an option that has a"
-                          " definition. The option with code " << option_code
-                          << " does not have a definition.");
-            }
-
-            // @todo We have a limited set of option definitions intiialized at the moment.
-            // In the future we want to initialize option definitions for all options.
-            // Consequently an error will be issued if an option definition does not exist
-            // for a particular option code. For now it is ok to create generic option
-            // if definition does not exist.
-            OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
-                                        binary));
-            // The created option is stored in option_descriptor_ class member until the
-            // commit stage when it is inserted into the main storage. If an option with the
-            // same code exists in main storage already the old option is replaced.
-            option_descriptor_.option = option;
-            option_descriptor_.persistent = false;
-        } else {
-
-            // Option name should match the definition. The option name
-            // may seem to be redundant but in the future we may want
-            // to reference options and definitions using their names
-            // and/or option codes so keeping the option name in the
-            // definition of option value makes sense.
-            if (def->getName() != option_name) {
-                isc_throw(DhcpConfigError, "specified option name '"
-                          << option_name << "' does not match the "
-                          << "option definition: '" << option_space
-                          << "." << def->getName() << "'");
-            }
-
-            // Option definition has been found so let's use it to create
-            // an instance of our option.
-            try {
-                OptionPtr option = csv_format ?
-                    def->optionFactory(Option::V6, option_code, data_tokens) :
-                    def->optionFactory(Option::V6, option_code, binary);
-                Subnet::OptionDescriptor desc(option, false);
-                option_descriptor_.option = option;
-                option_descriptor_.persistent = false;
-            } catch (const isc::Exception& ex) {
-                isc_throw(DhcpConfigError, "option data does not match"
-                          << " option definition (space: " << option_space
-                          << ", code: " << option_code << "): "
-                          << ex.what());
-            }
-        }
-        // All went good, so we can set the option space name.
-        option_space_ = option_space;
-    }
-
-    /// Storage for uint32 values (e.g. option code).
-    Uint32Storage uint32_values_;
-    /// Storage for string values (e.g. option name or data).
-    StringStorage string_values_;
-    /// Storage for boolean values.
-    BooleanStorage boolean_values_;
-    /// Pointer to options storage. This storage is provided by
-    /// the calling class and is shared by all OptionDataParser objects.
-    OptionStorage* options_;
-    /// Option descriptor holds newly configured option.
-    isc::dhcp::Subnet::OptionDescriptor option_descriptor_;
-    /// Option space name where the option belongs to.
-    std::string option_space_;
-};
-
-/// @brief Parser for option data values within a subnet.
-///
-/// This parser iterates over all entries that define options
-/// data for a particular subnet and creates a collection of options.
-/// If parsing is successful, all these options are added to the Subnet
-/// object.
-class OptionDataListParser : public DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// Unless otherwise specified, parsed options will be stored in
-    /// a global option container (option_default). That storage location
-    /// is overriden on a subnet basis.
-    OptionDataListParser(const std::string&)
-        : options_(&option_defaults), local_options_() { }
-
-    /// @brief Parses entries that define options' data for a subnet.
-    ///
-    /// This method iterates over all entries that define option data
-    /// for options within a single subnet and creates options' instances.
-    ///
-    /// @param option_data_list pointer to a list of options' data sets.
-    /// @throw DhcpConfigError if option parsing failed.
-    void build(ConstElementPtr option_data_list) {
-        BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
-            boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
-            // options_ member will hold instances of all options thus
-            // each OptionDataParser takes it as a storage.
-            parser->setStorage(&local_options_);
-            // Build the instance of a single option.
-            parser->build(option_value);
-            // Store a parser as it will be used to commit.
-            parsers_.push_back(parser);
-        }
-    }
-
-    /// @brief Set storage for option instances.
-    ///
-    /// @param storage pointer to options storage.
-    void setStorage(OptionStorage* storage) {
-        options_ = storage;
-    }
-
-
-    /// @brief Commit all option values.
-    ///
-    /// This function invokes commit for all option values.
-    void commit() {
-        BOOST_FOREACH(ParserPtr parser, parsers_) {
-            parser->commit();
-        }
-        // Parsing was successful and we have all configured
-        // options in local storage. We can now replace old values
-        // with new values.
-        std::swap(local_options_, *options_);
-    }
-
-    /// @brief Create DhcpDataListParser object
-    ///
-    /// @param param_name param name.
-    ///
-    /// @return DhcpConfigParser object.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new OptionDataListParser(param_name));
-    }
-
-    /// Pointer to options instances storage.
-    OptionStorage* options_;
-    /// Intermediate option storage. This storage is used by
-    /// lower level parsers to add new options.  Values held
-    /// in this storage are assigned to main storage (options_)
-    /// if overall parsing was successful.
-    OptionStorage local_options_;
-    /// Collection of parsers;
-    ParserCollection parsers_;
-};
-
-/// @brief Parser for a single option definition.
-///
-/// This parser creates an instance of a single option definition.
-class OptionDefParser: DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// This constructor sets the pointer to the option definitions
-    /// storage to NULL. It must be set to point to the actual storage
-    /// before \ref build is called.
-    OptionDefParser(const std::string&)
-        : storage_(NULL) {
-    }
-
-    /// @brief Parses an entry that describes single option definition.
-    ///
-    /// @param option_def a configuration entry to be parsed.
-    ///
-    /// @throw DhcpConfigError if parsing was unsuccessful.
-    void build(ConstElementPtr option_def) {
-        if (storage_ == NULL) {
-            isc_throw(DhcpConfigError, "parser logic error: storage must be set"
-                      " before parsing option definition data");
-        }
-        // Parse the elements that make up the option definition.
-        BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
-            std::string entry(param.first);
-            ParserPtr parser;
-            if (entry == "name" || entry == "type" || entry == "record-types" ||
-                entry == "space" || entry == "encapsulate") {
-                StringParserPtr
-                    str_parser(dynamic_cast<StringParser*>(StringParser::factory(entry)));
-                if (str_parser) {
-                    str_parser->setStorage(&string_values_);
-                    parser = str_parser;
-                }
-            } else if (entry == "code") {
-                Uint32ParserPtr
-                    code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::factory(entry)));
-                if (code_parser) {
-                    code_parser->setStorage(&uint32_values_);
-                    parser = code_parser;
-                }
-            } else if (entry == "array") {
-                BooleanParserPtr
-                    array_parser(dynamic_cast<BooleanParser*>(BooleanParser::factory(entry)));
-                if (array_parser) {
-                    array_parser->setStorage(&boolean_values_);
-                    parser = array_parser;
-                }
-            } else {
-                isc_throw(DhcpConfigError, "invalid parameter: " << entry);
-            }
-
-            parser->build(param.second);
-            parser->commit();
-        }
-
-        // Create an instance of option definition.
-        createOptionDef();
-
-        // Get all items we collected so far for the particular option space.
-        OptionDefContainerPtr defs = storage_->getItems(option_space_name_);
-        // Check if there are any items with option code the same as the
-        // one specified for the definition we are now creating.
-        const OptionDefContainerTypeIndex& idx = defs->get<1>();
-        const OptionDefContainerTypeRange& range =
-            idx.equal_range(option_definition_->getCode());
-        // If there are any items with this option code already we need
-        // to issue an error because we don't allow duplicates for
-        // option definitions within an option space.
-        if (std::distance(range.first, range.second) > 0) {
-            isc_throw(DhcpConfigError, "duplicated option definition for"
-                      << " code '" << option_definition_->getCode() << "'");
-        }
-    }
-
-    /// @brief Stores the parsed option definition in the data store.
-    void commit() {
-        if (storage_ && option_definition_ &&
-            OptionSpace::validateName(option_space_name_)) {
-            storage_->addItem(option_definition_, option_space_name_);
-        }
-    }
-
-    /// @brief Sets a pointer to the data store.
-    ///
-    /// The newly created instance of an option definition will be
-    /// added to the data store given by the argument.
-    ///
-    /// @param storage pointer to the data store where the option definition
-    /// will be added to.
-    void setStorage(OptionDefStorage* storage) {
-        storage_ = storage;
-    }
-
-private:
-
-    /// @brief Create option definition from the parsed parameters.
-    void createOptionDef() {
-        // Get the option space name and validate it.
-        std::string space = string_values_.getParam("space");
-        if (!OptionSpace::validateName(space)) {
-            isc_throw(DhcpConfigError, "invalid option space name '"
-                      << space << "'");
-        }
-
-        // Get other parameters that are needed to create the
-        // option definition.
-        std::string name = string_values_.getParam("name");
-        uint32_t code = uint32_values_.getParam("code");
-        std::string type = string_values_.getParam("type");
-        bool array_type = boolean_values_.getParam("array");
-        std::string encapsulates = string_values_.getParam("encapsulate");
-
-        // Create option definition.
-        OptionDefinitionPtr def;
-        // We need to check if user has set encapsulated option space
-        // name. If so, different constructor will be used.
-        if (!encapsulates.empty()) {
-            // Arrays can't be used together with sub-options.
-            if (array_type) {
-                isc_throw(DhcpConfigError, "option '" << space << "."
-                          << "name" << "', comprising an array of data"
-                          << " fields may not encapsulate any option space");
-
-            } else if (encapsulates == space) {
-                isc_throw(DhcpConfigError, "option must not encapsulate"
-                          << " an option space it belongs to: '"
-                          << space << "." << name << "' is set to"
-                          << " encapsulate '" << space << "'");
-
-            } else {
-                def.reset(new OptionDefinition(name, code, type,
-                                               encapsulates.c_str()));
-            }
-
-        } else {
-            def.reset(new OptionDefinition(name, code, type, array_type));
-
-        }
-
-        // The record-types field may carry a list of comma separated names
-        // of data types that form a record.
-        std::string record_types = string_values_.getParam("record-types");
-        // Split the list of record types into tokens.
-        std::vector<std::string> record_tokens =
-            isc::util::str::tokens(record_types, ",");
-        // Iterate over each token and add a record type into
-        // option definition.
-        BOOST_FOREACH(std::string record_type, record_tokens) {
-            try {
-                boost::trim(record_type);
-                if (!record_type.empty()) {
-                    def->addRecordField(record_type);
-                }
-            } catch (const Exception& ex) {
-                isc_throw(DhcpConfigError, "invalid record type values"
-                          << " specified for the option definition: "
-                          << ex.what());
-            }
-        }
-
-        // Check the option definition parameters are valid.
-        try {
-            def->validate();
-        } catch (const isc::Exception& ex) {
-            isc_throw(DhcpConfigError, "invalid option definition"
-                      << " parameters: " << ex.what());
-        }
-        // Option definition has been created successfully.
-        option_space_name_ = space;
-        option_definition_ = def;
-    }
-
-    /// Instance of option definition being created by this parser.
-    OptionDefinitionPtr option_definition_;
-    /// Name of the space the option definition belongs to.
-    std::string option_space_name_;
-
-    /// Pointer to a storage where the option definition will be
-    /// added when \ref commit is called.
-    OptionDefStorage* storage_;
-
-    /// Storage for boolean values.
-    BooleanStorage boolean_values_;
-    /// Storage for string values.
-    StringStorage string_values_;
-    /// Storage for uint32 values.
-    Uint32Storage uint32_values_;
-};
-
-/// @brief Parser for a list of option definitions.
-///
-/// This parser iterates over all configuration entries that define
-/// option definitions and creates instances of these definitions.
-/// If the parsing is successful, the collection of created definitions
-/// is put into the provided storage.
-class OptionDefListParser : DhcpConfigParser {
-public:
-
-    /// @brief Constructor.
-    ///
-    /// This constructor initializes the pointer to option definitions
-    /// storage to NULL value. This pointer has to be set to point to
-    /// the actual storage before the \ref build function is called.
-    OptionDefListParser(const std::string&) {
-    }
-
-    /// @brief Parse configuration entries.
-    ///
-    /// This function parses configuration entries and creates instances
-    /// of option definitions.
-    ///
-    /// @param option_def_list pointer to an element that holds entries
-    /// that define option definitions.
-    /// @throw DhcpConfigError if configuration parsing fails.
-    void build(ConstElementPtr option_def_list) {
-        // Clear existing items in the global storage.
-        // We are going to replace all of them.
-        option_def_intermediate.clearItems();
-
-        if (!option_def_list) {
-            isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
-                      << " option definitions is NULL");
-        }
-
-        BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
-            boost::shared_ptr<OptionDefParser>
-                parser(new OptionDefParser("single-option-def"));
-            parser->setStorage(&option_def_intermediate);
-            parser->build(option_def);
-            parser->commit();
-        }
-    }
-
-    /// @brief Stores option definitions in the CfgMgr.
-    void commit() {
-
-        CfgMgr& cfg_mgr = CfgMgr::instance();
-
-        cfg_mgr.deleteOptionDefs();
-
-        // We need to move option definitions from the temporary
-        // storage to the global storage.
-        std::list<std::string> space_names =
-            option_def_intermediate.getOptionSpaceNames();
-        BOOST_FOREACH(std::string space_name, space_names) {
-
-            BOOST_FOREACH(OptionDefinitionPtr def,
-                          *option_def_intermediate.getItems(space_name)) {
-                // All option definitions should be initialized to non-NULL
-                // values. The validation is expected to be made by the
-                // OptionDefParser when creating an option definition.
-                assert(def);
-                cfg_mgr.addOptionDef(def, space_name);
-            }
-        }
-    }
-
-    /// @brief Create an OptionDefListParser object.
-    ///
-    /// @param param_name configuration entry holding option definitions.
-    ///
-    /// @return OptionDefListParser object.
-    static DhcpConfigParser* factory(const std::string& param_name) {
-        return (new OptionDefListParser(param_name));
-    }
-
-};
-
 /// @brief this class parses a single subnet
 ///
 /// This class parses the whole subnet definition. It creates parsers
@@ -1292,29 +235,8 @@ public:
 
         BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
             ParserPtr parser(createSubnet6ConfigParser(param.first));
-            // The actual type of the parser is unknown here. We have to discover
-            // the parser type here to invoke the corresponding setStorage function
-            // on it.  We discover parser type by trying to cast the parser to various
-            // parser types and checking which one was successful. For this one
-            // a setStorage and build methods are invoked.
-
-            // Try uint32 type parser.
-            if (!buildParser<Uint32Parser, Uint32Storage >(parser, uint32_values_,
-                                                           param.second) &&
-                // Try string type parser.
-                !buildParser<StringParser, StringStorage >(parser, string_values_,
-                                                           param.second) &&
-                // Try pool parser.
-                !buildParser<PoolParser, PoolStorage >(parser, pools_,
-                                                       param.second) &&
-                // Try option data parser.
-                !buildParser<OptionDataListParser, OptionStorage >(parser, options_,
-                                                                   param.second)) {
-                // Appropriate parsers are created in the createSubnet6ConfigParser
-                // and they should be limited to those that we check here for. Thus,
-                // if we fail to find a matching parser here it is a programming error.
-                isc_throw(DhcpConfigError, "failed to find suitable parser");
-            }
+            parser->build(param.second);
+            parsers_.push_back(parser);
         }
 
         // In order to create new subnet we need to get the data out
@@ -1342,40 +264,6 @@ public:
 
 private:
 
-    /// @brief Set storage for a parser and invoke build.
-    ///
-    /// This helper method casts the provided parser pointer to the specified
-    /// type. If the cast is successful it sets the corresponding storage for
-    /// this parser, invokes build on it and saves the parser.
-    ///
-    /// @tparam T parser type to which parser argument should be cast.
-    /// @tparam Y storage type for the specified parser type.
-    /// @param parser parser on which build must be invoked.
-    /// @param storage reference to a storage that will be set for a parser.
-    /// @param subnet subnet element read from the configuration and being parsed.
-    /// @return true if parser pointer was successfully cast to specialized
-    /// parser type provided as Y.
-    template<typename T, typename Y>
-    bool buildParser(const ParserPtr& parser, Y& storage, const ConstElementPtr& subnet) {
-        // We need to cast to T in order to set storage for the parser.
-        boost::shared_ptr<T> cast_parser = boost::dynamic_pointer_cast<T>(parser);
-        // It is common that this cast is not successful because we try to cast to all
-        // supported parser types as we don't know the type of a parser in advance.
-        if (cast_parser) {
-            // Cast, successful so we go ahead with setting storage and actual parse.
-            cast_parser->setStorage(&storage);
-            parser->build(subnet);
-            parsers_.push_back(parser);
-            // We indicate that cast was successful so as the calling function
-            // may skip attempts to cast to other parser types and proceed to
-            // next element.
-            return (true);
-        }
-        // It was not successful. Indicate that another parser type
-        // should be tried.
-        return (false);
-    }
-
     /// @brief Append sub-options to an option.
     ///
     /// @param option_space a name of the encapsulated option space.
@@ -1581,27 +469,30 @@ private:
     /// @throw isc::dhcp::DhcpConfigError if trying to create a parser
     ///        for unknown config element
     DhcpConfigParser* createSubnet6ConfigParser(const std::string& config_id) {
-        FactoryMap factories;
-
-        factories["preferred-lifetime"] = Uint32Parser::factory;
-        factories["valid-lifetime"] = Uint32Parser::factory;
-        factories["renew-timer"] = Uint32Parser::factory;
-        factories["rebind-timer"] = Uint32Parser::factory;
-        factories["subnet"] = StringParser::factory;
-        factories["pool"] = PoolParser::factory;
-        factories["option-data"] = OptionDataListParser::factory;
-        factories["interface"] = StringParser::factory;
-
-        FactoryMap::iterator f = factories.find(config_id);
-        if (f == factories.end()) {
-            // Used for debugging only.
-            // return new DebugParser(config_id);
-
-            isc_throw(isc::dhcp::DhcpConfigError,
-                      "parser error: subnet6 parameter not supported: "
-                      << config_id);
+        DhcpConfigParser *parser = NULL;
+        if ((config_id.compare("preferred-lifetime") == 0)  ||
+            (config_id.compare("valid-lifetime") == 0)  ||
+            (config_id.compare("renew-timer") == 0)  ||
+            (config_id.compare("rebind-timer") == 0))  {
+            parser = new Uint32Parser(config_id, &uint32_values_);
+        }
+        else if ((config_id.compare("subnet") == 0) ||
+                 (config_id.compare("interface") == 0)) {
+            parser = new StringParser(config_id, &string_values_);
+        }
+        else if (config_id.compare("pool") == 0) {
+            parser = new PoolParser(config_id, &pools_);
+        }
+        else if (config_id.compare("option-data") == 0) {
+           parser = new OptionDataListParser(config_id, &options_, 
+                                             &option_def_intermediate,
+                                             Dhcp6OptionDataParser::factory);
+        } else {
+            isc_throw(NotImplemented,
+                "parser error: Subnet6 parameter not supported: " << config_id);
         }
-        return (f->second(config_id));
+
+        return (parser);
     }
 
     /// @brief Returns value for a given parameter (after using inheritance)
@@ -1718,6 +609,34 @@ public:
 namespace isc {
 namespace dhcp {
 
+//************** Dhcp6OptionDataParser methods ****************************
+
+Dhcp6OptionDataParser::Dhcp6OptionDataParser(const std::string& param_name, 
+    OptionStorage *options, OptionDefStorage *option_defs)
+    :OptionDataParser(param_name, options, option_defs, Option::V6) {
+}
+
+OptionDataParser* Dhcp6OptionDataParser::factory(const std::string& param_name,
+    OptionStorage *options, OptionDefStorage *option_defs) {
+    return new Dhcp6OptionDataParser(param_name, options, option_defs);
+}
+
+OptionDefinitionPtr Dhcp6OptionDataParser::findServerSpaceOptionDefinition (
+    std::string& option_space, uint32_t option_code) {
+    OptionDefinitionPtr def;
+
+    if (option_space == "dhcp6" &&
+        LibDHCP::isStandardOption(Option::V6, option_code)) {
+        def = LibDHCP::getOptionDef(Option::V6, option_code);
+
+    } else if (option_space == "dhcp4") {
+        isc_throw(DhcpConfigError, "'dhcp4' option space name is reserved"
+                << " for DHCPv4 server");
+    }
+
+    return def;
+}
+
 /// @brief creates global parsers
 ///
 /// This method creates global parsers that parse global parameters, i.e.
@@ -1727,29 +646,40 @@ namespace dhcp {
 /// @return parser for specified global DHCPv6 parameter
 /// @throw NotImplemented if trying to create a parser for unknown config element
 DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
-    FactoryMap factories;
-
-    factories["preferred-lifetime"] = Uint32Parser::factory;
-    factories["valid-lifetime"] = Uint32Parser::factory;
-    factories["renew-timer"] = Uint32Parser::factory;
-    factories["rebind-timer"] = Uint32Parser::factory;
-    factories["interface"] = InterfaceListConfigParser::factory;
-    factories["subnet6"] = Subnets6ListConfigParser::factory;
-    factories["option-data"] = OptionDataListParser::factory;
-    factories["option-def"] = OptionDefListParser::factory;
-    factories["version"] = StringParser::factory;
-    factories["lease-database"] = DbAccessParser::factory;
-
-    FactoryMap::iterator f = factories.find(config_id);
-    if (f == factories.end()) {
-        // Used for debugging only.
-        // return new DebugParser(config_id);
-
+    DhcpConfigParser *parser = NULL;
+    if ((config_id.compare("preferred-lifetime") == 0)  ||
+        (config_id.compare("valid-lifetime") == 0)  ||
+        (config_id.compare("renew-timer") == 0)  ||
+        (config_id.compare("rebind-timer") == 0))  {
+        parser = new Uint32Parser(config_id, &uint32_defaults);
+    }
+    else if (config_id.compare("interface") == 0) {
+        parser = new InterfaceListConfigParser(config_id);
+    }
+    else if (config_id.compare("subnet6") == 0) {
+        parser = new Subnets6ListConfigParser(config_id);
+    }
+    else if (config_id.compare("option-data") == 0) {
+        parser = new OptionDataListParser(config_id, &option_defaults, 
+                                          &option_def_intermediate,
+                                          Dhcp6OptionDataParser::factory);
+    }
+    else if (config_id.compare("option-def") == 0) {
+        parser  = new OptionDefListParser(config_id, &option_def_intermediate);
+    }
+    else if (config_id.compare("version") == 0) {
+        parser  = new StringParser(config_id, &string_defaults);
+    }
+    else if (config_id.compare("lease-database") == 0) {
+        parser = new DbAccessParser(config_id);
+    }
+    else {
         isc_throw(NotImplemented,
-                  "Parser error: Global configuration parameter not supported: "
-                  << config_id);
+                "Parser error: Global configuration parameter not supported: "
+                << config_id);
     }
-    return (f->second(config_id));
+
+    return (parser);
 }
 
 ConstElementPtr
index 6d7a807b80f2df9d33a056cb7f8adc79161fd007..6840ecce8afef4de69098760571d2dd6453db899 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
+#include <dhcpsrv/dhcp_parsers.h>
+
 #include <string>
 
 namespace isc {
@@ -47,6 +49,48 @@ class Dhcpv6Srv;
 isc::data::ConstElementPtr
 configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set);
 
+/// @brief Parser for DHCP6 option data value.
+///
+/// This parser parses configuration entries that specify value of
+/// a single option specific to DHCP6.  It provides the DHCP6-specific
+/// implementation of the abstract class OptionDataParser.
+class Dhcp6OptionDataParser : public OptionDataParser {
+public:
+    /// @brief Constructor.
+    ///
+    /// Class constructor.
+    Dhcp6OptionDataParser(const std::string&, OptionStorage *options,
+        OptionDefStorage *option_defs);
+
+    /// @brief static factory method for instantiating Dhcp4OptionDataParsers
+    ///
+    /// @param param_name name fo the parameter to be parsed.
+    /// @param options storage where the parameter value is to be stored.
+    /// @param global_option_defs global option definitions storage 
+    static OptionDataParser* factory(const std::string& param_name, OptionStorage *options,
+        OptionDefStorage *global_option_defs);
+
+protected:
+    /// @brief Finds an option definition within the server's option space
+    /// 
+    /// Given an option space and an option code, find the correpsonding 
+    /// option defintion within the server's option defintion storage.
+    ///
+    /// @param option_space name of the parameter option space 
+    /// @param option_code numeric value of the parameter to find 
+    /// @return OptionDefintionPtr of the option defintion or an 
+    /// empty OptionDefinitionPtr if not found.
+    /// @throw DhcpConfigError if the option space requested is not valid 
+    /// for this server. 
+    virtual OptionDefinitionPtr findServerSpaceOptionDefinition (
+        std::string& option_space, uint32_t option_code);
+
+private:
+    // Private default Constructor declared for safety.
+    Dhcp6OptionDataParser() :OptionDataParser("",NULL,NULL,Option::V6) {}
+};
+
+
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 
index db82513f5283c4731025af665000d9607c0b4d00..77a3a122af0d2d469f769833b6116cad5f94cf9d 100644 (file)
@@ -37,6 +37,7 @@ libb10_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
 libb10_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
 libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
 libb10_dhcpsrv_la_SOURCES += dhcp_config_parser.h
+libb10_dhcpsrv_la_SOURCES += dhcp_parsers.cc dhcp_parsers.h 
 libb10_dhcpsrv_la_SOURCES += key_from_key.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
@@ -57,6 +58,7 @@ libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libb10_dhcpsrv_la_LIBADD   = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 libb10_dhcpsrv_la_LIBADD  += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
 libb10_dhcpsrv_la_LIBADD  += $(top_builddir)/src/lib/util/libb10-util.la
+libb10_dhcpsrv_la_LIBADD  += $(top_builddir)/src/lib/cc/libb10-cc.la
 libb10_dhcpsrv_la_LDFLAGS  = -no-undefined -version-info 3:0:0
 if HAVE_MYSQL
 libb10_dhcpsrv_la_LDFLAGS += $(MYSQL_LIBS)
diff --git a/src/lib/dhcpsrv/dhcp_parsers.cc b/src/lib/dhcpsrv/dhcp_parsers.cc
new file mode 100644 (file)
index 0000000..940cf06
--- /dev/null
@@ -0,0 +1,633 @@
+// Copyright (C) 2013 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.
+
+#include <dhcpsrv/dhcp_parsers.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <util/encode/hex.h>
+#include <util/strutil.h>
+
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+// Pointers to various parser objects.
+typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
+typedef boost::shared_ptr<StringParser> StringParserPtr;
+typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
+
+// **************************** DebugParser *************************
+
+DebugParser::DebugParser(const std::string& param_name)
+    :param_name_(param_name) {
+}
+
+void DebugParser::build(ConstElementPtr new_config) {
+    std::cout << "Build for token: [" << param_name_ << "] = ["
+        << value_->str() << "]" << std::endl; 
+    value_ = new_config;
+}
+
+void DebugParser::commit() {
+    // Debug message. The whole DebugParser class is used only for parser
+    // debugging, and is not used in production code. It is very convenient
+    // to keep it around. Please do not turn this cout into logger calls.
+    std::cout << "Commit for token: [" << param_name_ << "] = ["
+                  << value_->str() << "]" << std::endl;
+}
+
+// **************************** BooleanParser  *************************
+BooleanParser::BooleanParser(const std::string& param_name, BooleanStorage *storage)
+    : storage_(storage), param_name_(param_name), value_(false) {
+    // Empty parameter name is invalid.
+    if (param_name_.empty()) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+        << "empty parameter name provided");
+    }
+
+    // NUll storage is invalid.
+    if (!storage_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+            << "storage may not be NULL");
+    }
+}
+
+void BooleanParser::build(ConstElementPtr value) {
+    // The Config Manager checks if user specified a
+    // valid value for a boolean parameter: True or False.
+    // It is then ok to assume that if str() does not return
+    // 'true' the value is 'false'.
+    value_ = (value->str() == "true") ? true : false;
+}
+
+void BooleanParser::commit() {
+    // If a given parameter already exists in the storage we override
+    // its value. If it doesn't we insert a new element.
+    storage_->setParam(param_name_, value_);
+}
+
+// **************************** Uin32Parser  *************************
+
+Uint32Parser::Uint32Parser(const std::string& param_name, Uint32Storage *storage)
+    : storage_(storage), param_name_(param_name) {
+    // Empty parameter name is invalid.
+    if (param_name_.empty()) {
+        isc_throw(DhcpConfigError, "parser logic error:"
+            << "empty parameter name provided");
+    }
+
+    // NULL storage is invalid.
+    if (!storage_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+            << "storage may not be NULL");
+    }
+}
+
+void Uint32Parser::build(ConstElementPtr value) {
+    int64_t check;
+    string x = value->str();
+    try {
+        check = boost::lexical_cast<int64_t>(x);
+    } catch (const boost::bad_lexical_cast &) {
+        isc_throw(BadValue, "Failed to parse value " << value->str()
+                  << " as unsigned 32-bit integer.");
+    }
+    if (check > std::numeric_limits<uint32_t>::max()) {
+        isc_throw(BadValue, "Value " << value->str() << "is too large"
+                  << " for unsigned 32-bit integer.");
+    }
+    if (check < 0) {
+        isc_throw(BadValue, "Value " << value->str() << "is negative."
+                  << " Only 0 or larger are allowed for unsigned 32-bit integer.");
+    }
+
+    // value is small enough to fit
+    value_ = static_cast<uint32_t>(check);
+}
+
+void Uint32Parser::commit() {
+    // If a given parameter already exists in the storage we override
+    // its value. If it doesn't we insert a new element.
+    storage_->setParam(param_name_, value_);
+}
+
+// **************************** StringParser  *************************
+
+StringParser::StringParser(const std::string& param_name, StringStorage *storage)
+    :storage_(storage), param_name_(param_name) {
+    // Empty parameter name is invalid.
+    if (param_name_.empty()) {
+        isc_throw(DhcpConfigError, "parser logic error:"
+                  << "empty parameter name provided");
+    }
+
+    // NULL storage is invalid.
+    if (!storage_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+            << "storage may not be NULL");
+    }
+}
+
+void StringParser::build(ConstElementPtr value) {
+    value_ = value->str();
+    boost::erase_all(value_, "\"");
+}
+
+void StringParser::commit() {
+    // If a given parameter already exists in the storage we override
+    // its value. If it doesn't we insert a new element.
+    storage_->setParam(param_name_, value_);
+}
+
+// **************************** InterfaceListConfigParser *************************
+
+InterfaceListConfigParser::InterfaceListConfigParser(const std::string& param_name) {
+    if (param_name != "interface") {
+        isc_throw(BadValue, "Internal error. Interface configuration "
+            "parser called for the wrong parameter: " << param_name);
+    }
+}
+
+void InterfaceListConfigParser::build(ConstElementPtr value) {
+    BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
+        interfaces_.push_back(iface->str());
+    }
+}
+
+void InterfaceListConfigParser::commit() {
+    /// @todo: Implement per interface listening. Currently always listening
+    /// on all interfaces.
+}
+
+// **************************** OptionDataParser *************************
+
+OptionDataParser::OptionDataParser(const std::string&, OptionStorage *options,
+    OptionDefStorage *option_defs, Option::Universe universe)
+        : options_(options),
+          // initialize option to NULL ptr
+          option_descriptor_(false), global_option_defs_(option_defs),
+          universe_(universe) {
+    if (!options_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+             << "options storage may not be NULL");
+    }
+}
+
+void OptionDataParser::build(ConstElementPtr option_data_entries) {
+    BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
+        ParserPtr parser;
+        if (param.first == "name" || param.first == "data" ||
+            param.first == "space") {
+            StringParserPtr name_parser(new StringParser(param.first, &string_values_)); 
+            parser = name_parser;
+        } else if (param.first == "code") {
+            Uint32ParserPtr code_parser(new Uint32Parser(param.first, &uint32_values_)); 
+            parser = code_parser;
+        } else if (param.first == "csv-format") {
+            BooleanParserPtr value_parser(new BooleanParser(param.first, &boolean_values_)); 
+            parser = value_parser;
+        } else {
+            isc_throw(DhcpConfigError,
+                      "Parser error: option-data parameter not supported: "
+                      << param.first);
+        }
+
+        parser->build(param.second);
+        // Before we can create an option we need to get the data from
+        // the child parsers. The only way to do it is to invoke commit
+        // on them so as they store the values in appropriate storages
+        // that this class provided to them. Note that this will not
+        // modify values stored in the global storages so the configuration
+        // will remain consistent even parsing fails somewhere further on.
+        parser->commit();
+    }
+
+    // Try to create the option instance.
+    createOption();
+}
+
+void OptionDataParser::commit() {
+    if (!option_descriptor_.option) {
+        // Before we can commit the new option should be configured. If it is not
+        // than somebody must have called commit() before build().
+        isc_throw(isc::InvalidOperation, 
+            "parser logic error: no option has been configured and"
+            " thus there is nothing to commit. Has build() been called?");
+    }
+
+    uint16_t opt_type = option_descriptor_.option->getType();
+    Subnet::OptionContainerPtr options = options_->getItems(option_space_);
+    // The getItems() should never return NULL pointer. If there are no
+    // options configured for the particular option space a pointer
+    // to an empty container should be returned.
+    assert(options);
+    Subnet::OptionContainerTypeIndex& idx = options->get<1>();
+    // Try to find options with the particular option code in the main
+    // storage. If found, remove these options because they will be
+    // replaced with new one.
+    Subnet::OptionContainerTypeRange range = idx.equal_range(opt_type);
+    if (std::distance(range.first, range.second) > 0) {
+        idx.erase(range.first, range.second);
+    }
+
+    // Append new option to the main storage.
+    options_->addItem(option_descriptor_, option_space_);
+}
+
+void OptionDataParser::createOption() {
+    // Option code is held in the uint32_t storage but is supposed to
+    // be uint16_t value. We need to check that value in the configuration
+    // does not exceed range of uint8_t and is not zero.
+    uint32_t option_code = uint32_values_.getParam("code");
+    if (option_code == 0) {
+        isc_throw(DhcpConfigError, "option code must not be zero."
+                << " Option code '0' is reserved in DHCPv4.");
+    } else if (option_code > std::numeric_limits<uint8_t>::max()) {
+        isc_throw(DhcpConfigError, "invalid option code '" << option_code
+                << "', it must not exceed '"
+                << std::numeric_limits<uint8_t>::max() << "'");
+    }
+
+    // Check that the option name has been specified, is non-empty and does not
+    // contain spaces
+    std::string option_name = string_values_.getParam("name"); 
+    if (option_name.empty()) {
+        isc_throw(DhcpConfigError, "name of the option with code '"
+                << option_code << "' is empty");
+    } else if (option_name.find(" ") != std::string::npos) {
+        isc_throw(DhcpConfigError, "invalid option name '" << option_name
+                << "', space character is not allowed");
+    }
+
+    std::string option_space = string_values_.getParam("space"); 
+    if (!OptionSpace::validateName(option_space)) {
+        isc_throw(DhcpConfigError, "invalid option space name '"
+                << option_space << "' specified for option '"
+                << option_name << "' (code '" << option_code
+                << "')");
+    }
+
+    // Find the Option Definition for the option by its option code.
+    // findOptionDefinition will throw if not found, no need to test.
+    OptionDefinitionPtr def;
+    if (!(def = findServerSpaceOptionDefinition(option_space, option_code))) {
+        // If we are not dealing with a standard option then we
+        // need to search for its definition among user-configured
+        // options. They are expected to be in the global storage
+        // already.
+        OptionDefContainerPtr defs = global_option_defs_->getItems(option_space);
+
+        // The getItems() should never return the NULL pointer. If there are
+        // no option definitions for the particular option space a pointer
+        // to an empty container should be returned.
+        assert(defs);
+        const OptionDefContainerTypeIndex& idx = defs->get<1>();
+        OptionDefContainerTypeRange range = idx.equal_range(option_code);
+        if (std::distance(range.first, range.second) > 0) {
+            def = *range.first;
+        }
+        if (!def) {
+            isc_throw(DhcpConfigError, "definition for the option '"
+                      << option_space << "." << option_name
+                      << "' having code '" <<  option_code
+                      << "' does not exist");
+        }
+    }
+
+    // Get option data from the configuration database ('data' field).
+    const std::string option_data = string_values_.getParam("data");
+    const bool csv_format = boolean_values_.getParam("csv-format");
+
+    // Transform string of hexadecimal digits into binary format.
+    std::vector<uint8_t> binary;
+    std::vector<std::string> data_tokens;
+
+    if (csv_format) {
+        // If the option data is specified as a string of comma
+        // separated values then we need to split this string into
+        // individual values - each value will be used to initialize
+        // one data field of an option.
+        data_tokens = isc::util::str::tokens(option_data, ",");
+    } else {
+        // Otherwise, the option data is specified as a string of
+        // hexadecimal digits that we have to turn into binary format.
+        try {
+            util::encode::decodeHex(option_data, binary);
+        } catch (...) {
+            isc_throw(DhcpConfigError, "option data is not a valid"
+                      << " string of hexadecimal digits: " << option_data);
+        }
+    }
+
+    OptionPtr option;
+    if (!def) {
+        if (csv_format) {
+            isc_throw(DhcpConfigError, "the CSV option data format can be"
+                      " used to specify values for an option that has a"
+                      " definition. The option with code " << option_code
+                      << " does not have a definition.");
+        }
+
+        // @todo We have a limited set of option definitions intiialized at the moment.
+        // In the future we want to initialize option definitions for all options.
+        // Consequently an error will be issued if an option definition does not exist
+        // for a particular option code. For now it is ok to create generic option
+        // if definition does not exist.
+        OptionPtr option(new Option(universe_, static_cast<uint16_t>(option_code),
+                                        binary));
+        // The created option is stored in option_descriptor_ class member until the
+        // commit stage when it is inserted into the main storage. If an option with the
+        // same code exists in main storage already the old option is replaced.
+        option_descriptor_.option = option;
+        option_descriptor_.persistent = false;
+    } else {
+
+        // Option name should match the definition. The option name
+        // may seem to be redundant but in the future we may want
+        // to reference options and definitions using their names
+        // and/or option codes so keeping the option name in the
+        // definition of option value makes sense.
+        if (def->getName() != option_name) {
+            isc_throw(DhcpConfigError, "specified option name '"
+                      << option_name << "' does not match the "
+                      << "option definition: '" << option_space
+                      << "." << def->getName() << "'");
+        }
+
+        // Option definition has been found so let's use it to create
+        // an instance of our option.
+        try {
+            OptionPtr option = csv_format ?
+                def->optionFactory(universe_, option_code, data_tokens) :
+                def->optionFactory(universe_, option_code, binary);
+            Subnet::OptionDescriptor desc(option, false);
+            option_descriptor_.option = option;
+            option_descriptor_.persistent = false;
+        } catch (const isc::Exception& ex) {
+            isc_throw(DhcpConfigError, "option data does not match"
+                      << " option definition (space: " << option_space
+                      << ", code: " << option_code << "): "
+                      << ex.what());
+        }
+    }
+
+    // All went good, so we can set the option space name.
+    option_space_ = option_space;
+}
+
+// **************************** OptionDataListParser *************************
+
+OptionDataListParser::OptionDataListParser(const std::string&, 
+    OptionStorage *storage, OptionDefStorage *global_option_defs,
+    OptionDataParserFactory *optionDataParserFactory)
+    : options_(storage), local_options_(), 
+    global_option_defs_(global_option_defs),
+    optionDataParserFactory_(optionDataParserFactory) {
+    if (!options_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+             << "options storage may not be NULL");
+    }
+
+    if (!optionDataParserFactory_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+             << "option data parser factory may not be NULL");
+    }
+}
+
+
+void OptionDataListParser::build(ConstElementPtr option_data_list) {
+    BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
+        boost::shared_ptr<OptionDataParser> 
+            parser((*optionDataParserFactory_)("option-data", &local_options_, global_option_defs_));
+
+        // options_ member will hold instances of all options thus
+        // each OptionDataParser takes it as a storage.
+        // Build the instance of a single option.
+        parser->build(option_value);
+        // Store a parser as it will be used to commit.
+        parsers_.push_back(parser);
+    }
+}
+
+void OptionDataListParser::commit() {
+    BOOST_FOREACH(ParserPtr parser, parsers_) {
+        parser->commit();
+    }
+
+    // Parsing was successful and we have all configured
+    // options in local storage. We can now replace old values
+    // with new values.
+    std::swap(local_options_, *options_);
+}
+
+// ******************************** OptionDefParser ****************************
+
+OptionDefParser::OptionDefParser(const std::string&, OptionDefStorage *storage)
+    : storage_(storage) {
+    if (!storage_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+             << "options storage may not be NULL");
+    }
+}
+
+void OptionDefParser::build(ConstElementPtr option_def) {
+    // Parse the elements that make up the option definition.
+     BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
+        std::string entry(param.first);
+        ParserPtr parser;
+        if (entry == "name" || entry == "type" || entry == "record-types" 
+            || entry == "space" || entry == "encapsulate") {
+            StringParserPtr str_parser(new StringParser(entry, &string_values_));
+            parser = str_parser;
+        } else if (entry == "code") {
+            Uint32ParserPtr code_parser(new Uint32Parser(entry, &uint32_values_));
+            parser = code_parser;
+        } else if (entry == "array") {
+            BooleanParserPtr array_parser(new BooleanParser(entry, &boolean_values_));
+            parser = array_parser;
+        } else {
+            isc_throw(DhcpConfigError, "invalid parameter: " << entry);
+        }
+
+        parser->build(param.second);
+        parser->commit();
+    }
+
+    // Create an instance of option definition.
+    createOptionDef();
+
+    // Get all items we collected so far for the particular option space.
+    OptionDefContainerPtr defs = storage_->getItems(option_space_name_);
+
+    // Check if there are any items with option code the same as the
+    // one specified for the definition we are now creating.
+    const OptionDefContainerTypeIndex& idx = defs->get<1>();
+    const OptionDefContainerTypeRange& range =
+            idx.equal_range(option_definition_->getCode());
+
+    // If there are any items with this option code already we need
+    // to issue an error because we don't allow duplicates for
+    // option definitions within an option space.
+    if (std::distance(range.first, range.second) > 0) {
+        isc_throw(DhcpConfigError, "duplicated option definition for"
+                << " code '" << option_definition_->getCode() << "'");
+    }
+}
+
+void OptionDefParser::commit() {
+    if (storage_ && option_definition_ &&
+        OptionSpace::validateName(option_space_name_)) {
+            storage_->addItem(option_definition_, option_space_name_);
+    }
+}
+
+void OptionDefParser::createOptionDef() {
+    // Get the option space name and validate it.
+    std::string space = string_values_.getParam("space");
+    if (!OptionSpace::validateName(space)) {
+        isc_throw(DhcpConfigError, "invalid option space name '"
+                  << space << "'");
+    }
+
+    // Get other parameters that are needed to create the
+    // option definition.
+    std::string name = string_values_.getParam("name");
+    uint32_t code = uint32_values_.getParam("code");
+    std::string type = string_values_.getParam("type");
+    bool array_type = boolean_values_.getParam("array");
+    std::string encapsulates = string_values_.getParam("encapsulate");
+
+    // Create option definition.
+    OptionDefinitionPtr def;
+    // We need to check if user has set encapsulated option space
+    // name. If so, different constructor will be used.
+    if (!encapsulates.empty()) {
+        // Arrays can't be used together with sub-options.
+        if (array_type) {
+            isc_throw(DhcpConfigError, "option '" << space << "."
+                      << "name" << "', comprising an array of data"
+                      << " fields may not encapsulate any option space");
+
+        } else if (encapsulates == space) {
+            isc_throw(DhcpConfigError, "option must not encapsulate"
+                      << " an option space it belongs to: '"
+                      << space << "." << name << "' is set to"
+                      << " encapsulate '" << space << "'");
+
+        } else {
+            def.reset(new OptionDefinition(name, code, type,
+                        encapsulates.c_str()));
+        }
+
+    } else {
+        def.reset(new OptionDefinition(name, code, type, array_type));
+
+    }
+
+    // The record-types field may carry a list of comma separated names
+    // of data types that form a record.
+    std::string record_types = string_values_.getParam("record-types");
+
+    // Split the list of record types into tokens.
+    std::vector<std::string> record_tokens =
+    isc::util::str::tokens(record_types, ",");
+    // Iterate over each token and add a record type into
+    // option definition.
+    BOOST_FOREACH(std::string record_type, record_tokens) {
+        try {
+            boost::trim(record_type);
+            if (!record_type.empty()) {
+                    def->addRecordField(record_type);
+            }
+        } catch (const Exception& ex) {
+            isc_throw(DhcpConfigError, "invalid record type values"
+                      << " specified for the option definition: "
+                      << ex.what());
+        }
+    }
+
+    // Check the option definition parameters are valid.
+    try {
+        def->validate();
+    } catch (const isc::Exception& ex) {
+        isc_throw(DhcpConfigError, "invalid option definition"
+                  << " parameters: " << ex.what());
+    }
+
+    // Option definition has been created successfully.
+    option_space_name_ = space;
+    option_definition_ = def;
+}
+
+// ******************************** OptionDefListParser ************************
+
+OptionDefListParser::OptionDefListParser(const std::string&, 
+    OptionDefStorage *storage) :storage_(storage) {
+    if (!storage_) {
+        isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
+             << "storage may not be NULL");
+    }
+}
+
+void OptionDefListParser::build(ConstElementPtr option_def_list) {
+    // Clear existing items in the global storage.
+    // We are going to replace all of them.
+    storage_->clearItems();
+
+    if (!option_def_list) {
+        isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
+                  << " option definitions is NULL");
+    }
+
+    BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
+        boost::shared_ptr<OptionDefParser>
+                parser(new OptionDefParser("single-option-def", storage_));
+        parser->build(option_def);
+        parser->commit();
+    }
+}
+
+void OptionDefListParser::commit() {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+    cfg_mgr.deleteOptionDefs();
+
+    // We need to move option definitions from the temporary
+    // storage to the global storage.
+    std::list<std::string> space_names =
+    storage_->getOptionSpaceNames();
+
+    BOOST_FOREACH(std::string space_name, space_names) {
+        BOOST_FOREACH(OptionDefinitionPtr def,
+                    *(storage_->getItems(space_name))) {
+            // All option definitions should be initialized to non-NULL
+            // values. The validation is expected to be made by the
+            // OptionDefParser when creating an option definition.
+            assert(def);
+            cfg_mgr.addOptionDef(def, space_name);
+        }
+    }
+}
+
+};  // namespace dhcp
+};  // namespace isc
diff --git a/src/lib/dhcpsrv/dhcp_parsers.h b/src/lib/dhcpsrv/dhcp_parsers.h
new file mode 100644 (file)
index 0000000..76c6719
--- /dev/null
@@ -0,0 +1,504 @@
+// Copyright (C) 2013 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.
+
+#ifndef DHCP_PARSERS_H
+#define DHCP_PARSERS_H
+
+#include <cc/data.h>
+#include <dhcp/option_definition.h>
+#include <dhcpsrv/dhcp_config_parser.h>
+#include <dhcpsrv/option_space_container.h>
+#include <dhcpsrv/subnet.h>
+#include <exceptions/exceptions.h>
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Storage for option definitions.
+typedef OptionSpaceContainer<OptionDefContainer,
+                             OptionDefinitionPtr> OptionDefStorage;
+
+/// Collection of containers holding option spaces. Each container within
+/// a particular option space holds so-called option descriptors.
+typedef OptionSpaceContainer<Subnet::OptionContainer,
+                             Subnet::OptionDescriptor> OptionStorage;
+
+/// @brief a dummy configuration parser
+///
+/// It is a debugging parser. It does not configure anything,
+/// will accept any configuration and will just print it out
+/// on commit. Useful for debugging existing configurations and
+/// adding new ones.
+class DebugParser : public DhcpConfigParser {
+public:
+
+    /// @brief Constructor
+    ///
+    /// See @ref DhcpConfigParser class for details.
+    ///
+    /// @param param_name name of the parsed parameter
+    DebugParser(const std::string& param_name);
+
+    /// @brief builds parameter value
+    ///
+    /// See @ref DhcpConfigParser class for details.
+    ///
+    /// @param new_config pointer to the new configuration
+    virtual void build(isc::data::ConstElementPtr new_config);
+
+    /// @brief pretends to apply the configuration
+    ///
+    /// This is a method required by base class. It pretends to apply the
+    /// configuration, but in fact it only prints the parameter out.
+    ///
+    /// See @ref DhcpConfigParser class for details.
+    virtual void commit();
+
+private:
+    /// name of the parsed parameter
+    std::string param_name_;
+
+    /// pointer to the actual value of the parameter
+    isc::data::ConstElementPtr value_;
+
+};
+
+/// @brief A boolean value parser.
+///
+/// This parser handles configuration values of the boolean type.
+/// Parsed values are stored in a provided storage. If no storage
+/// is provided then the build function throws an exception.
+class BooleanParser : public DhcpConfigParser {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param param_name name of the parameter.
+    BooleanParser(const std::string& param_name, BooleanStorage *storage);
+
+    /// @brief Parse a boolean value.
+    ///
+    /// @param value a value to be parsed.
+    ///
+    /// @throw isc::InvalidOperation if a storage has not been set
+    ///        prior to calling this function
+    /// @throw isc::dhcp::DhcpConfigError if a provided parameter's
+    ///        name is empty.
+    virtual void build(isc::data::ConstElementPtr value);
+
+    /// @brief Put a parsed value to the storage.
+    virtual void commit();
+
+private:
+    /// Pointer to the storage where parsed value is stored.
+    BooleanStorage* storage_;
+    /// Name of the parameter which value is parsed with this parser.
+    std::string param_name_;
+    /// Parsed value.
+    bool value_;
+
+    /// Default constructor is private for safety.
+    BooleanParser(){};
+};
+
+/// @brief Configuration parser for uint32 parameters
+///
+/// This class is a generic parser that is able to handle any uint32 integer
+/// type. By default it stores the value in external global container
+/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, @ref DhcpConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// @ref dhcpv4ConfigInherit page.
+class Uint32Parser : public DhcpConfigParser {
+public:
+
+    /// @brief constructor for Uint32Parser
+    /// @param param_name name of the configuration parameter being parsed
+    Uint32Parser(const std::string& param_name, Uint32Storage *storage);
+
+    /// @brief Parses configuration configuration parameter as uint32_t.
+    ///
+    /// @param value pointer to the content of parsed values
+    /// @throw BadValue if supplied value could not be base to uint32_t
+    ///        or the parameter name is empty.
+    virtual void build(isc::data::ConstElementPtr value);
+
+    /// @brief Stores the parsed uint32_t value in a storage.
+    virtual void commit();
+
+private:
+    /// pointer to the storage, where parsed value will be stored
+    Uint32Storage* storage_;
+
+    /// name of the parameter to be parsed
+    std::string param_name_;
+
+    /// the actual parsed value
+    uint32_t value_;
+
+    /// Default constructor is private for safety.
+    Uint32Parser(){};
+};
+
+/// @brief Configuration parser for string parameters
+///
+/// This class is a generic parser that is able to handle any string
+/// parameter. By default it stores the value in external global container
+/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, @ref DhcpConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// @ref dhcpv4ConfigInherit page.
+class StringParser : public DhcpConfigParser {
+public:
+    /// @brief constructor for StringParser
+    /// @param param_name name of the configuration parameter being parsed
+    StringParser(const std::string& param_name, StringStorage *storage);
+
+    /// @brief parses parameter value
+    ///
+    /// Parses configuration entry and stores it in storage. See
+    /// @ref setStorage() for details.
+    ///
+    /// @param value pointer to the content of parsed values
+    virtual void build(isc::data::ConstElementPtr value);
+
+    /// @brief Stores the parsed value in a storage.
+    virtual void commit();
+
+private:
+    /// pointer to the storage, where parsed value will be stored
+    StringStorage* storage_;
+
+    /// name of the parameter to be parsed
+    std::string param_name_;
+
+    /// the actual parsed value
+    std::string value_;
+
+    /// Default constructor is private for safety.
+    StringParser(){};
+};
+
+/// @brief parser for interface list definition
+///
+/// This parser handles Dhcp4/interface entry.
+/// It contains a list of network interfaces that the server listens on.
+/// In particular, it can contain an entry called "all" or "any" that
+/// designates all interfaces.
+///
+/// It is useful for parsing Dhcp4/interface parameter.
+class InterfaceListConfigParser : public DhcpConfigParser {
+public:
+
+    /// @brief constructor
+    ///
+    /// As this is a dedicated parser, it must be used to parse
+    /// "interface" parameter only. All other types will throw exception.
+    ///
+    /// @param param_name name of the configuration parameter being parsed
+    /// @throw BadValue if supplied parameter name is not "interface"
+    InterfaceListConfigParser(const std::string& param_name);
+
+    /// @brief parses parameters value
+    ///
+    /// Parses configuration entry (list of parameters) and adds each element
+    /// to the interfaces list.
+    ///
+    /// @param value pointer to the content of parsed values
+    virtual void build(isc::data::ConstElementPtr value);
+
+    /// @brief commits interfaces list configuration
+    virtual void commit();
+
+private:
+    /// contains list of network interfaces
+    std::vector<std::string> interfaces_;
+
+    /// Default constructor is private for safety.
+    InterfaceListConfigParser(){};
+};
+
+
+/// @brief Parser for option data value.
+///
+/// This parser parses configuration entries that specify value of
+/// a single option. These entries include option name, option code
+/// and data carried by the option. The option data can be specified
+/// in one of the two available formats: binary value represented as
+/// a string of hexadecimal digits or a list of comma separated values.
+/// The format being used is controlled by csv-format configuration
+/// parameter. When setting this value to True, the latter format is
+/// used. The subsequent values in the CSV format apply to relevant
+/// option data fields in the configured option. For example the
+/// configuration: "data" : "192.168.2.0, 56, hello world" can be
+/// used to set values for the option comprising IPv4 address,
+/// integer and string data field. Note that order matters. If the
+/// order of values does not match the order of data fields within
+/// an option the configuration will not be accepted. If parsing
+/// is successful then an instance of an option is created and
+/// added to the storage provided by the calling class.
+class OptionDataParser : public DhcpConfigParser {
+public:
+    /// @brief Constructor.
+    ///
+    /// Class constructor.
+    OptionDataParser(const std::string&, OptionStorage *options, 
+        OptionDefStorage *option_defs, Option::Universe universe);
+
+    /// @brief Parses the single option data.
+    ///
+    /// This method parses the data of a single option from the configuration.
+    /// The option data includes option name, option code and data being
+    /// carried by this option. Eventually it creates the instance of the
+    /// option.
+    ///
+    /// @warning setStorage must be called with valid storage pointer prior
+    /// to calling this method.
+    ///
+    /// @param option_data_entries collection of entries that define value
+    /// for a particular option.
+    /// @throw DhcpConfigError if invalid parameter specified in
+    /// the configuration.
+    /// @throw isc::InvalidOperation if failed to set storage prior to
+    /// calling build.
+    virtual void build(isc::data::ConstElementPtr option_data_entries);
+
+    /// @brief Commits option value.
+    ///
+    /// This function adds a new option to the storage or replaces an existing option
+    /// with the same code.
+    ///
+    /// @throw isc::InvalidOperation if failed to set pointer to storage or failed
+    /// to call build() prior to commit. If that happens data in the storage
+    /// remain un-modified.
+    virtual void commit();
+
+    /// @brief virtual destructor to ensure orderly destruction of derivations. 
+    virtual ~OptionDataParser(){};
+
+protected:
+    /// @brief Finds an option definition within the server's option space
+    /// 
+    /// Given an option space and an option code, find the correpsonding 
+    /// option defintion within the server's option defintion storage. This
+    /// method is pure virtual requiring derivations to manage which option
+    /// space(s) is valid for search.
+    ///
+    /// @param option_space name of the parameter option space 
+    /// @param option_code numeric value of the parameter to find 
+    /// @return OptionDefintionPtr of the option defintion or an 
+    /// empty OptionDefinitionPtr if not found.
+    /// @throw DhcpConfigError if the option space requested is not valid 
+    /// for this server.
+    virtual OptionDefinitionPtr findServerSpaceOptionDefinition (
+            std::string& option_space, uint32_t option_code) = 0;
+
+private:
+
+    /// @brief Create option instance.
+    ///
+    /// Creates an instance of an option and adds it to the provided
+    /// options storage. If the option data parsed by \ref build function
+    /// are invalid or insufficient this function emits an exception.
+    ///
+    /// @warning this function does not check if options_ storage pointer
+    /// is intitialized but this check is not needed here because it is done
+    /// in the \ref build function.
+    ///
+    /// @throw DhcpConfigError if parameters provided in the configuration
+    /// are invalid.
+    void createOption();
+
+    /// Storage for uint32 values (e.g. option code).
+    Uint32Storage uint32_values_;
+    /// Storage for string values (e.g. option name or data).
+    StringStorage string_values_;
+    /// Storage for boolean values.
+    BooleanStorage boolean_values_;
+    /// Pointer to options storage. This storage is provided by
+    /// the calling class and is shared by all OptionDataParser objects.
+    OptionStorage* options_;
+    /// Option descriptor holds newly configured option.
+    Subnet::OptionDescriptor option_descriptor_;
+    /// Option space name where the option belongs to.
+    std::string option_space_;
+
+    /// Option definition storage
+    OptionDefStorage *global_option_defs_;
+
+    /// Option::Universe for this parser's option
+    Option::Universe universe_;
+
+    /// Default constructor is private for safety.
+    OptionDataParser():option_descriptor_(false){};
+};
+
+///@brief Function pointer for OptionDataParser factory methods
+typedef OptionDataParser *OptionDataParserFactory(const std::string&, OptionStorage *options, 
+        OptionDefStorage *option_defs);
+
+/// @brief Parser for option data values within a subnet.
+///
+/// This parser iterates over all entries that define options
+/// data for a particular subnet and creates a collection of options.
+/// If parsing is successful, all these options are added to the Subnet
+/// object.
+class OptionDataListParser : public DhcpConfigParser {
+public:
+    /// @brief Constructor.
+    ///
+    /// @param string& nominally would be param name, this is always ignored.
+    /// @param storage parsed option storage for options in this list
+    /// @param global_option_defs global set of option definitions to reference
+    /// @param optionDataParserFactory factory method for creating individual option
+    /// parsers 
+    OptionDataListParser(const std::string&, OptionStorage *storage, 
+        OptionDefStorage *global_option_defs,
+        OptionDataParserFactory *optionDataParserFactory);
+
+    /// @brief Parses entries that define options' data for a subnet.
+    ///
+    /// This method iterates over all entries that define option data
+    /// for options within a single subnet and creates options' instances.
+    ///
+    /// @param option_data_list pointer to a list of options' data sets.
+    /// @throw DhcpConfigError if option parsing failed.
+    void build(isc::data::ConstElementPtr option_data_list);
+
+    /// @brief Commit all option values.
+    ///
+    /// This function invokes commit for all option values.
+    void commit();
+
+private:
+    /// Pointer to options instances storage.
+    OptionStorage* options_;
+    /// Intermediate option storage. This storage is used by
+    /// lower level parsers to add new options.  Values held
+    /// in this storage are assigned to main storage (options_)
+    /// if overall parsing was successful.
+    OptionStorage local_options_;
+    /// Collection of parsers;
+    ParserCollection parsers_;
+
+    /// Global option definitions
+    OptionDefStorage *global_option_defs_;
+
+    /// Factory to create server-specific option data parsers
+    OptionDataParserFactory *optionDataParserFactory_;
+
+    /// Default constructor is private for safety.
+    OptionDataListParser(){};
+};
+
+
+/// @brief Parser for a single option definition.
+///
+/// This parser creates an instance of a single option definition.
+class OptionDefParser : public DhcpConfigParser {
+public:
+    /// @brief Constructor.
+    ///
+    /// This constructor sets the pointer to the option definitions
+    /// storage to NULL. It must be set to point to the actual storage
+    /// before \ref build is called.
+    OptionDefParser(const std::string&, OptionDefStorage *storage);
+
+    /// @brief Parses an entry that describes single option definition.
+    ///
+    /// @param option_def a configuration entry to be parsed.
+    ///
+    /// @throw DhcpConfigError if parsing was unsuccessful.
+    void build(isc::data::ConstElementPtr option_def);
+
+    /// @brief Stores the parsed option definition in a storage.
+    void commit();
+
+private:
+
+    /// @brief Create option definition from the parsed parameters.
+    void createOptionDef();
+
+    /// Instance of option definition being created by this parser.
+    OptionDefinitionPtr option_definition_;
+    /// Name of the space the option definition belongs to.
+    std::string option_space_name_;
+
+    /// Pointer to a storage where the option definition will be
+    /// added when \ref commit is called.
+    OptionDefStorage* storage_;
+
+    /// Storage for boolean values.
+    BooleanStorage boolean_values_;
+    /// Storage for string values.
+    StringStorage string_values_;
+    /// Storage for uint32 values.
+    Uint32Storage uint32_values_;
+
+    // Default constructor is private for safety.
+    OptionDefParser(){};
+};
+
+/// @brief Parser for a list of option definitions.
+///
+/// This parser iterates over all configuration entries that define
+/// option definitions and creates instances of these definitions.
+/// If the parsing is successful, the collection of created definitions
+/// is put into the provided storage.
+class OptionDefListParser : public DhcpConfigParser {
+public:
+    /// @brief Constructor.
+    ///
+    /// This constructor initializes the pointer to option definitions
+    /// storage to NULL value. This pointer has to be set to point to
+    /// the actual storage before the \ref build function is called.
+    OptionDefListParser(const std::string&, OptionDefStorage *storage);
+
+    /// @brief Parse configuration entries.
+    ///
+    /// This function parses configuration entries and creates instances
+    /// of option definitions.
+    ///
+    /// @param option_def_list pointer to an element that holds entries
+    /// that define option definitions.
+    /// @throw DhcpConfigError if configuration parsing fails.
+    void build(isc::data::ConstElementPtr option_def_list);
+
+    /// @brief Stores option definitions in the CfgMgr.
+    void commit();
+
+private:
+    /// @brief storage for option definitions.
+    OptionDefStorage *storage_; 
+
+    // Default constructor is private for safety.
+    OptionDefListParser(){};
+
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // DHCP_PARSERS_H
+