config_data.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #include "config_data.h"
  16. #include <boost/foreach.hpp>
  17. #include <string>
  18. #include <iostream>
  19. using namespace isc::data;
  20. namespace isc {
  21. namespace config {
  22. //
  23. // Return a part of a specification, as identified by the
  24. // '/'-separated identifier.
  25. // If it cannot be found, a DataNotFound error is thrown.
  26. //
  27. // Recursively goes through the Element. If it is a List,
  28. // we search it contents to have 'items' (i.e. contain item_name)
  29. // If it is a map, we search through the list contained in its
  30. // 'map_item_spec' value. This code assumes the data has been
  31. // validated and conforms to the specification.
  32. static ElementPtr
  33. find_spec_part(ElementPtr spec, const std::string& identifier)
  34. {
  35. //std::cout << "[XX] find_spec_part for " << identifier << std::endl;
  36. if (!spec) {
  37. isc_throw(DataNotFoundError, "Empty specification");
  38. }
  39. //std::cout << "in: " << std::endl << spec << std::endl;
  40. ElementPtr spec_part = spec;
  41. if (identifier == "") {
  42. isc_throw(DataNotFoundError, "Empty identifier");
  43. }
  44. std::string id = identifier;
  45. size_t sep = id.find('/');
  46. while(sep != std::string::npos) {
  47. std::string part = id.substr(0, sep);
  48. //std::cout << "[XX] id part: " << part << std::endl;
  49. if (spec_part->getType() == Element::list) {
  50. bool found = false;
  51. BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
  52. if (list_el->getType() == Element::map &&
  53. list_el->contains("item_name") &&
  54. list_el->get("item_name")->stringValue() == part) {
  55. spec_part = list_el;
  56. found = true;
  57. }
  58. }
  59. if (!found) {
  60. isc_throw(DataNotFoundError, identifier);
  61. }
  62. }
  63. id = id.substr(sep + 1);
  64. sep = id.find("/");
  65. }
  66. if (id != "" && id != "/") {
  67. if (spec_part->getType() == Element::list) {
  68. bool found = false;
  69. BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
  70. if (list_el->getType() == Element::map &&
  71. list_el->contains("item_name") &&
  72. list_el->get("item_name")->stringValue() == id) {
  73. spec_part = list_el;
  74. found = true;
  75. }
  76. }
  77. if (!found) {
  78. isc_throw(DataNotFoundError, identifier);
  79. }
  80. } else if (spec_part->getType() == Element::map) {
  81. if (spec_part->contains("map_item_spec")) {
  82. bool found = false;
  83. BOOST_FOREACH(ElementPtr list_el, spec_part->get("map_item_spec")->listValue()) {
  84. if (list_el->getType() == Element::map &&
  85. list_el->contains("item_name") &&
  86. list_el->get("item_name")->stringValue() == id) {
  87. spec_part = list_el;
  88. found = true;
  89. }
  90. }
  91. if (!found) {
  92. isc_throw(DataNotFoundError, identifier);
  93. }
  94. } else {
  95. isc_throw(DataNotFoundError, identifier);
  96. }
  97. }
  98. }
  99. //std::cout << "[XX] found spec part: " << std::endl << spec_part << std::endl;
  100. return spec_part;
  101. }
  102. //
  103. // Adds the names of the items in the given specification part.
  104. // If recurse is true, maps will also have their children added.
  105. // Result must be a ListElement
  106. //
  107. static void
  108. spec_name_list(ElementPtr result, ElementPtr spec_part, std::string prefix, bool recurse = false)
  109. {
  110. if (spec_part->getType() == Element::list) {
  111. BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
  112. if (list_el->getType() == Element::map &&
  113. list_el->contains("item_name")) {
  114. std::string new_prefix = prefix;
  115. if (prefix != "") {
  116. new_prefix += "/";
  117. }
  118. new_prefix += list_el->get("item_name")->stringValue();
  119. if (recurse && list_el->get("item_type")->stringValue() == "map") {
  120. spec_name_list(result, list_el->get("map_item_spec"), new_prefix, recurse);
  121. } else {
  122. if (list_el->get("item_type")->stringValue() == "map" ||
  123. list_el->get("item_type")->stringValue() == "list"
  124. ) {
  125. new_prefix += "/";
  126. }
  127. result->add(Element::create(new_prefix));
  128. }
  129. }
  130. }
  131. } else if (spec_part->getType() == Element::map && spec_part->contains("map_item_spec")) {
  132. spec_name_list(result, spec_part->get("map_item_spec"), prefix, recurse);
  133. }
  134. }
  135. ElementPtr
  136. ConfigData::getValue(const std::string& identifier)
  137. {
  138. // 'fake' is set, but dropped by this function and
  139. // serves no further purpose.
  140. bool fake;
  141. return getValue(fake, identifier);
  142. }
  143. ElementPtr
  144. ConfigData::getValue(bool& is_default, const std::string& identifier)
  145. {
  146. ElementPtr value = _config->find(identifier);
  147. if (value) {
  148. is_default = false;
  149. } else {
  150. ElementPtr spec_part = find_spec_part(_module_spec.getConfigSpec(), identifier);
  151. if (spec_part->contains("item_default")) {
  152. value = spec_part->get("item_default");
  153. is_default = true;
  154. } else {
  155. is_default = false;
  156. value = ElementPtr();
  157. }
  158. }
  159. return value;
  160. }
  161. /// Returns an ElementPtr pointing to a ListElement containing
  162. /// StringElements with the names of the options at the given
  163. /// identifier. If recurse is true, maps will be expanded as well
  164. ElementPtr
  165. ConfigData::getItemList(const std::string& identifier, bool recurse)
  166. {
  167. ElementPtr result = Element::createList();
  168. ElementPtr spec_part = getModuleSpec().getConfigSpec();
  169. if (identifier != "" && identifier != "/") {
  170. spec_part = find_spec_part(spec_part, identifier);
  171. }
  172. spec_name_list(result, spec_part, identifier, recurse);
  173. return result;
  174. }
  175. /// Returns an ElementPtr containing a MapElement with identifier->value
  176. /// pairs.
  177. ElementPtr
  178. ConfigData::getFullConfig()
  179. {
  180. ElementPtr result = Element::createMap();
  181. ElementPtr items = getItemList("", true);
  182. BOOST_FOREACH(ElementPtr item, items->listValue()) {
  183. result->set(item->stringValue(), getValue(item->stringValue()));
  184. }
  185. return result;
  186. }
  187. }
  188. }