simple_parser.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef SIMPLE_PARSER_H
  7. #define SIMPLE_PARSER_H
  8. #include <cc/data.h>
  9. #include <cc/dhcp_config_error.h>
  10. #include <vector>
  11. #include <string>
  12. #include <stdint.h>
  13. #include <limits>
  14. namespace isc {
  15. namespace data {
  16. /// This array defines a single entry of default values
  17. struct SimpleDefault {
  18. SimpleDefault(const char* name, isc::data::Element::types type, const char* value)
  19. :name_(name), type_(type), value_(value) {}
  20. std::string name_;
  21. const isc::data::Element::types type_;
  22. const char* value_;
  23. };
  24. /// This specifies all default values in a given scope (e.g. a subnet)
  25. typedef std::vector<SimpleDefault> SimpleDefaults;
  26. /// This defines a list of all parameters that are derived (or inherited) between
  27. /// contexts
  28. typedef std::vector<std::string> ParamsList;
  29. /// @brief A simple parser
  30. ///
  31. /// This class is intended to be a simpler replacement for @ref
  32. /// isc::dhcp::DhcpConfigParser. This class has been initially created to
  33. /// facilitate DHCPv4 and DHCPv6 servers' configuration parsing. Thus examples
  34. /// provided herein are related to DHCP configuration. Nevertheless, this is a
  35. /// generic class to be used in other modules too.
  36. ///
  37. /// The simplification comes from several factors:
  38. /// - no build/commit nonsense. There's a single step:
  39. /// CfgStorage parse(ConstElementPtr json)
  40. /// that converts JSON configuration into an object and returns it.
  41. /// - no state kept. This greatly simplifies the parsers (no contexts, no child
  42. /// parsers list, no separate storage for uint32, strings etc. In fact,
  43. /// this base class is purely static. However, some derived classes may store
  44. /// some state. Implementors are advised to store as little state as possible.
  45. /// - no optional parameters (all are mandatory). This simplifies the parser,
  46. /// but introduces a new step before parsing where we insert the default
  47. /// values into client configuration before parsing. This is actually a good
  48. /// thing, because we now have a clear picture of the default parameters as
  49. /// they're defined in a single place (the DhcpConfigParser had the defaults
  50. /// spread out in multiple files in multiple directories).
  51. class SimpleParser {
  52. public:
  53. /// @brief Derives (inherits) parameters from parent scope to a child
  54. ///
  55. /// This method derives parameters from the parent scope to the child,
  56. /// if there are no values specified in the child scope. For example,
  57. /// this method can be used to derive timers from global scope (e.g. for
  58. /// the whole DHCPv6 server) to a subnet scope. This method checks
  59. /// if the child scope doesn't have more specific values defined. If
  60. /// it doesn't, then the value from parent scope is copied over.
  61. ///
  62. /// @param parent scope to copy from (e.g. global)
  63. /// @param child scope to copy from (e.g. subnet)
  64. /// @param params names of the parameters to copy
  65. /// @return number of parameters copied
  66. static size_t deriveParams(isc::data::ConstElementPtr parent,
  67. isc::data::ElementPtr child,
  68. const ParamsList& params);
  69. /// @brief Sets the default values
  70. ///
  71. /// This method sets the default values for parameters that are not
  72. /// defined. The list of default values is specified by default_values.
  73. /// If not present, those will be inserted into the scope. If
  74. /// a parameter is already present, the default value will not
  75. /// be inserted.
  76. ///
  77. /// @param scope default values will be inserted here
  78. /// @param default_values list of default values
  79. /// @return number of parameters inserted
  80. static size_t setDefaults(isc::data::ElementPtr scope,
  81. const SimpleDefaults& default_values);
  82. /// @brief Sets the default values for all entries in a list
  83. ///
  84. /// This is a simple utility method that iterates over all
  85. /// parameters in a list and calls setDefaults for each
  86. /// entry.
  87. ///
  88. /// @param list list to be iterated over
  89. /// @param default_values list of default values
  90. /// @return number of parameters inserted
  91. static size_t setListDefaults(isc::data::ConstElementPtr list,
  92. const SimpleDefaults& default_values);
  93. /// @brief Utility method that returns position of an element
  94. ///
  95. /// It's mostly useful for logging. If the element is missing
  96. /// the parent position is returned or ZERO_POSITION if parent
  97. /// is null.
  98. ///
  99. /// @param name position of that element will be returned
  100. /// @param parent parent element (optional)
  101. /// @return position of the element specified.
  102. static const data::Element::Position&
  103. getPosition(const std::string& name, const data::ConstElementPtr parent);
  104. protected:
  105. /// @brief Returns a string parameter from a scope
  106. ///
  107. /// Unconditionally returns a parameter.
  108. ///
  109. /// @param scope specified parameter will be extracted from this scope
  110. /// @param name name of the parameter
  111. /// @return a string value of the parameter
  112. /// @throw DhcpConfigError if the parameter is not there or is not of
  113. /// appropriate type
  114. static std::string getString(isc::data::ConstElementPtr scope,
  115. const std::string& name);
  116. /// @brief Returns an integer parameter from a scope
  117. ///
  118. /// Unconditionally returns a parameter.
  119. ///
  120. /// @param scope specified parameter will be extracted from this scope
  121. /// @param name name of the parameter
  122. /// @return an integer value of the parameter
  123. /// @throw DhcpConfigError if the parameter is not there or is not of
  124. /// appropriate type
  125. static int64_t getInteger(isc::data::ConstElementPtr scope,
  126. const std::string& name);
  127. /// @brief Returns a boolean parameter from a scope
  128. ///
  129. /// Unconditionally returns a parameter.
  130. ///
  131. /// @param scope specified parameter will be extracted from this scope
  132. /// @param name name of the parameter
  133. /// @return a boolean value of the parameter
  134. /// @throw DhcpConfigError if the parameter is not there or is not of
  135. /// appropriate type
  136. static bool getBoolean(isc::data::ConstElementPtr scope,
  137. const std::string& name);
  138. /// @brief Returns an integer value with range checking from a scope
  139. ///
  140. /// This template should be instantied in parsers when useful
  141. ///
  142. /// @tparam int_type the integer type e.g. uint32_t
  143. /// @param scope specified parameter will be extracted from this scope
  144. /// @param name name of the parameter for error report
  145. /// @return a value of int_type
  146. /// @throw DhcpConfigError if the parameter is not there, is not of
  147. /// appropriate type or is out of type value range
  148. template <typename int_type> int_type
  149. getIntType(isc::data::ConstElementPtr scope,
  150. const std::string& name) {
  151. int64_t val_int = getInteger(scope, name);
  152. if ((val_int < std::numeric_limits<int_type>::min()) ||
  153. (val_int > std::numeric_limits<int_type>::max())) {
  154. isc_throw(isc::dhcp::DhcpConfigError,
  155. "out of range value (" << val_int
  156. << ") specified for parameter '" << name
  157. << "' (" << getPosition(name, scope) << ")");
  158. }
  159. return (static_cast<int_type>(val_int));
  160. }
  161. /// @brief Returns a converted value from a scope
  162. ///
  163. /// This template should be instantied in parsers when useful
  164. ///
  165. /// @tparam target_type the type of the result
  166. /// @tparam convert the conversion function std::string -> target_type
  167. /// @param scope specified parameter will be extracted from this scope
  168. /// @param name name of the parameter for error report
  169. /// @param type_name name of target_type for error report
  170. /// @return a converted value of target_type
  171. /// @throw DhcpConfigError if the parameter is not there, is not of
  172. /// appropriate type or can not be converted
  173. template <typename target_type,
  174. target_type convert(const std::string&)> target_type
  175. getAndConvert(isc::data::ConstElementPtr scope,
  176. const std::string& name,
  177. const std::string& type_name) {
  178. std::string str = getString(scope, name);
  179. try {
  180. return (convert(str));
  181. } catch (const std::exception&) {
  182. isc_throw(isc::dhcp::DhcpConfigError,
  183. "invalid " << type_name << " (" << str
  184. << ") specified for parameter '" << name
  185. << "' (" << getPosition(name, scope) << ")");
  186. }
  187. }
  188. /// @brief Returns a value converted to uint32_t
  189. ///
  190. /// Instantiation of getIntType() to uint32_t
  191. ///
  192. /// @param scope specified parameter will be extracted from this scope
  193. /// @param name name of the parameter
  194. /// @return an uint32_t value
  195. /// @throw isc::dhcp::DhcpConfigError when it is not an uint32_t
  196. uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string& name) {
  197. return (getIntType<uint32_t>(scope, name));
  198. }
  199. /// @brief Returns a value converted to uint16_t
  200. ///
  201. /// Instantiation of getIntType() to uint16_t
  202. ///
  203. /// @param scope specified parameter will be extracted from this scope
  204. /// @param name name of the parameter
  205. /// @return an uint16_t value
  206. /// @throw isc::dhcp::DhcpConfigError when it is not an uint16_t
  207. uint16_t getUint16(isc::data::ConstElementPtr scope, const std::string& name) {
  208. return (getIntType<uint16_t>(scope, name));
  209. }
  210. /// @brief Get an uint8_t value
  211. ///
  212. /// Instantiation of getIntType() to uint8_t
  213. ///
  214. /// @param scope specified parameter will be extracted from this scope
  215. /// @param name name of the parameter
  216. /// @return uint8_t value
  217. /// @throw isc::dhcp::DhcpConfigError when it is not an uint8_t
  218. uint8_t getUint8(ConstElementPtr scope, const std::string& name) {
  219. return (getIntType<uint8_t>(scope, name));
  220. }
  221. };
  222. };
  223. };
  224. #endif