LCOV - code coverage report
Current view: top level - config - config_data.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 88 92 95.7 %
Date: 2012-05-15 Functions: 10 10 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 221 408 54.2 %

           Branch data     Line data    Source code
       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                 :            : 
      15                 :            : #include <config/config_data.h>
      16                 :            : 
      17                 :            : #include <boost/foreach.hpp>
      18                 :            : 
      19                 :            : #include <string>
      20                 :            : #include <iostream>
      21                 :            : 
      22                 :            : using namespace isc::data;
      23                 :            : 
      24                 :            : namespace {
      25                 :            : 
      26                 :            : // Returns the '_spec' part of a list or map specification (recursively,
      27                 :            : // i.e. if it is a list of lists or maps, will return the spec of the
      28                 :            : // inner-most list or map).
      29                 :            : //
      30                 :            : // \param spec_part the list or map specification (part)
      31                 :            : // \return the value of spec_part's "list_item_spec" or "map_item_spec",
      32                 :            : //         or the original spec_part, if it is not a MapElement or does
      33                 :            : //         not contain "list_item_spec" or "map_item_spec"
      34                 :         23 : ConstElementPtr findListOrMapSubSpec(ConstElementPtr spec_part) {
      35 [ +  + ][ +  + ]:        179 :     while (spec_part->getType() == Element::map &&
         [ +  + ][ +  + ]
      36 [ +  - ][ +  - ]:         97 :            (spec_part->contains("list_item_spec") ||
         [ +  + ][ #  # ]
      37 [ +  - ][ +  - ]:         82 :             spec_part->contains("map_item_spec"))) {
         [ +  + ][ #  # ]
      38 [ +  - ][ +  + ]:         36 :         if (spec_part->contains("list_item_spec")) {
      39 [ +  - ][ +  - ]:         30 :             spec_part = spec_part->get("list_item_spec");
      40                 :            :         } else {
      41 [ +  - ][ +  - ]:         57 :             spec_part = spec_part->get("map_item_spec");
      42                 :            :         }
      43                 :            :     }
      44                 :         23 :     return spec_part;
      45                 :            : }
      46                 :            : 
      47                 :            : // Returns a specific Element in a given specification ListElement
      48                 :            : //
      49                 :            : // \exception DataNotFoundError if the given identifier does not
      50                 :            : // point to an existing element. Since we are dealing with the
      51                 :            : // specification here, and not the config data itself, this should
      52                 :            : // not happen, and is a code bug.
      53                 :            : //
      54                 :            : // \param spec_part ListElement to find the element in
      55                 :            : // \param id_part the name of the element to find (must match the value
      56                 :            : //                "item_name" in the list item
      57                 :            : // \param id_full the full identifier id_part is a part of, this is
      58                 :            : //                used to better report any errors
      59                 :         78 : ConstElementPtr findItemInSpecList(ConstElementPtr spec_part,
      60                 :            :                                    const std::string& id_part,
      61                 :            :                                    const std::string& id_full)
      62                 :            : {
      63                 :         78 :     bool found = false;
      64   [ +  +  +  - ]:       1706 :     BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
      65         [ +  - ]:       1628 :         if (list_el->getType() == Element::map &&
           [ +  -  +  + ]
                 [ +  + ]
      66 [ +  - ][ +  - ]:        814 :             list_el->contains("item_name") &&
         [ +  - ][ #  # ]
      67 [ +  - ][ +  - ]:       1221 :             list_el->get("item_name")->stringValue() == id_part) {
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ #  # ][ #  # ]
      68         [ +  - ]:        479 :             spec_part = list_el;
      69                 :            :             found = true;
      70                 :            :         }
      71                 :            :     }
      72         [ +  + ]:         78 :     if (!found) {
      73 [ +  - ][ +  - ]:         12 :         isc_throw(isc::config::DataNotFoundError,
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      74                 :            :                   id_part + " in " + id_full + " not found");
      75                 :            :     }
      76                 :         72 :     return (spec_part);
      77                 :            : }
      78                 :            : 
      79                 :            : } // anonymous namespace
      80                 :            : 
      81                 :            : namespace isc {
      82                 :            : namespace config {
      83                 :            : 
      84                 :            : //
      85                 :            : // Return a part of a specification, as identified by the
      86                 :            : // '/'-separated identifier.
      87                 :            : // If it cannot be found, a DataNotFound error is thrown.
      88                 :            : //
      89                 :            : // Recursively goes through the Element. If it is a List,
      90                 :            : // we search it contents to have 'items' (i.e. contain item_name)
      91                 :            : // If it is a map, we search through the list contained in its
      92                 :            : // 'map_item_spec' value. This code assumes the data has been
      93                 :            : // validated and conforms to the specification.
      94                 :            : static ConstElementPtr
      95                 :         59 : find_spec_part(ConstElementPtr spec, const std::string& identifier) {
      96         [ +  + ]:         59 :     if (!spec) {
      97 [ +  - ][ +  - ]:          2 :         isc_throw(DataNotFoundError, "Empty specification");
                 [ +  - ]
      98                 :            :     }
      99                 :            : 
     100                 :            :     ConstElementPtr spec_part = spec;
     101         [ +  + ]:         58 :     if (identifier == "") {
     102 [ +  - ][ +  - ]:          2 :         isc_throw(DataNotFoundError, "Empty identifier");
         [ +  - ][ +  - ]
     103                 :            :     }
     104         [ +  - ]:        114 :     std::string id = identifier;
     105         [ +  - ]:         57 :     size_t sep = id.find('/');
     106         [ +  + ]:         82 :     while(sep != std::string::npos) {
     107         [ +  - ]:         52 :         std::string part = id.substr(0, sep);
     108                 :            : 
     109         [ +  - ]:         26 :         if (spec_part->getType() == Element::list) {
     110 [ +  + ][ +  - ]:         26 :             spec_part = findItemInSpecList(spec_part, part, identifier);
     111                 :            :         } else {
     112 [ #  # ][ #  # ]:          0 :             isc_throw(DataNotFoundError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     113                 :            :                       "Not a list of spec items: " + spec_part->str());
     114                 :            :         }
     115         [ +  - ]:         50 :         id = id.substr(sep + 1);
     116         [ +  - ]:         25 :         sep = id.find("/");
     117                 :            : 
     118                 :            :         // As long as we are not in the 'final' element as specified
     119                 :            :         // by the identifier, we want to automatically traverse list
     120                 :            :         // and map specifications
     121 [ +  - ][ +  + ]:         25 :         if (id != "" && id != "/") {
         [ +  - ][ -  + ]
                 [ +  + ]
     122 [ +  - ][ +  - ]:         23 :             spec_part = findListOrMapSubSpec(spec_part);
     123                 :            :         }
     124                 :            :     }
     125 [ +  - ][ +  + ]:         56 :     if (id != "" && id != "/") {
         [ +  - ][ -  + ]
                 [ +  + ]
     126         [ +  + ]:         54 :         if (spec_part->getType() == Element::list) {
     127 [ +  + ][ +  - ]:         52 :             spec_part = findItemInSpecList(spec_part, id, identifier);
     128         [ +  - ]:          2 :         } else if (spec_part->getType() == Element::map) {
     129 [ +  - ][ +  - ]:          2 :             if (spec_part->contains("map_item_spec")) {
                 [ -  + ]
     130                 :            :                 spec_part = findItemInSpecList(
     131                 :          0 :                                 spec_part->get("map_item_spec"),
     132 [ #  # ][ #  # ]:          0 :                                 id, identifier);
         [ #  # ][ #  # ]
     133                 :            :             } else {
     134                 :            :                 // Either we already have the element we are looking
     135                 :            :                 // for, or we are trying to reach something that does
     136                 :            :                 // not exist (i.e. the code does not match the spec)
     137 [ +  - ][ +  - ]:          6 :                 if (!spec_part->contains("item_name") ||
           [ +  -  +  + ]
         [ +  + ][ #  # ]
     138 [ +  - ][ +  - ]:          6 :                     spec_part->get("item_name")->stringValue() != id) {
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ #  # ][ #  # ]
     139 [ +  - ][ +  - ]:          2 :                     isc_throw(DataNotFoundError, "Element above " + id +
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     140                 :            :                                                  " in " + identifier +
     141                 :            :                                                  " is not a map: " + spec_part->str());
     142                 :            :                 }
     143                 :            :             }
     144                 :            :         }
     145                 :            :     }
     146                 :         50 :     return (spec_part);
     147                 :            : }
     148                 :            : 
     149                 :            : //
     150                 :            : // Adds the names of the items in the given specification part.
     151                 :            : // If recurse is true, maps will also have their children added.
     152                 :            : // Result must be a ListElement
     153                 :            : //
     154                 :            : static void
     155                 :         11 : spec_name_list(ElementPtr result, ConstElementPtr spec_part,
     156                 :            :                const std::string& prefix, bool recurse = false)
     157                 :            : {
     158         [ +  + ]:         11 :     if (spec_part->getType() == Element::list) {
     159   [ +  +  +  - ]:        170 :         BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     160 [ +  - ][ -  + ]:        120 :             if (list_el->getType() == Element::map &&
                 [ +  - ]
     161 [ +  - ][ +  - ]:         80 :                 list_el->contains("item_name")) {
         [ +  - ][ #  # ]
     162         [ +  - ]:        120 :                 std::string new_prefix = prefix;
     163 [ +  - ][ +  + ]:         40 :                 if (prefix != "") {
     164                 :            :                     new_prefix += "/";
     165                 :            :                 }
     166 [ +  - ][ +  - ]:        120 :                 new_prefix += list_el->get("item_name")->stringValue();
                 [ +  - ]
     167 [ +  + ][ +  - ]:        104 :                 if (recurse && list_el->get("item_type")->stringValue() == "map") {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
         [ #  # ][ #  # ]
     168 [ +  - ][ +  - ]:         12 :                     spec_name_list(result, list_el->get("map_item_spec"), new_prefix, recurse);
                 [ +  - ]
     169                 :            :                 } else {
     170 [ +  - ][ +  - ]:         72 :                     result->add(Element::create(new_prefix));
     171                 :            :                 }
     172                 :            :             }
     173                 :            :         }
     174 [ +  - ][ -  + ]:          3 :     } else if (spec_part->getType() == Element::map &&
                 [ +  - ]
     175 [ +  - ][ +  - ]:          2 :                spec_part->contains("map_item_spec")) {
         [ +  - ][ #  # ]
     176                 :          2 :         spec_name_list(result, spec_part->get("map_item_spec"), prefix,
     177 [ +  - ][ +  - ]:          2 :                        recurse);
     178                 :            :     }
     179                 :         11 : }
     180                 :            : 
     181                 :            : ConstElementPtr
     182                 :         56 : ConfigData::getValue(const std::string& identifier) const {
     183                 :            :     // 'fake' is set, but dropped by this function and
     184                 :            :     // serves no further purpose.
     185                 :            :     bool fake;
     186                 :         56 :     return (getValue(fake, identifier));
     187                 :            : }
     188                 :            : 
     189                 :            : ConstElementPtr
     190                 :         67 : ConfigData::getValue(bool& is_default, const std::string& identifier) const {
     191                 :         67 :     ConstElementPtr value = _config->find(identifier);
     192         [ +  + ]:         67 :     if (value) {
     193                 :         17 :         is_default = false;
     194                 :            :     } else {
     195                 :            :         ConstElementPtr spec_part =
     196 [ +  - ][ +  + ]:         50 :             find_spec_part(_module_spec.getConfigSpec(), identifier);
     197 [ +  - ][ +  - ]:         43 :         if (spec_part->contains("item_default")) {
                 [ +  + ]
     198 [ +  - ][ +  - ]:         80 :             value = spec_part->get("item_default");
                 [ +  - ]
     199                 :         40 :             is_default = true;
     200                 :            :         } else {
     201                 :          3 :             is_default = false;
     202                 :            :             value = ElementPtr();
     203                 :            :         }
     204                 :            :     }
     205                 :         60 :     return (value);
     206                 :            : }
     207                 :            : 
     208                 :            : ConstElementPtr
     209                 :          8 : ConfigData::getDefaultValue(const std::string& identifier) const {
     210                 :            :     ConstElementPtr spec_part =
     211         [ +  + ]:          8 :         find_spec_part(_module_spec.getConfigSpec(), identifier);
     212 [ +  - ][ +  - ]:          6 :     if (spec_part->contains("item_default")) {
                 [ +  - ]
     213 [ +  - ][ +  - ]:         12 :         return spec_part->get("item_default");
     214                 :            :     } else {
     215 [ #  # ][ #  # ]:          0 :         isc_throw(DataNotFoundError, "No default for " + identifier);
         [ #  # ][ #  # ]
                 [ #  # ]
     216                 :            :     }
     217                 :            : }
     218                 :            : 
     219                 :            : /// Returns an ElementPtr pointing to a ListElement containing
     220                 :            : /// StringElements with the names of the options at the given
     221                 :            : /// identifier. If recurse is true, maps will be expanded as well
     222                 :            : ConstElementPtr
     223                 :          6 : ConfigData::getItemList(const std::string& identifier, bool recurse) const {
     224                 :          6 :     ElementPtr result = Element::createList();
     225         [ +  - ]:          6 :     ConstElementPtr spec_part = getModuleSpec().getConfigSpec();
     226 [ +  - ][ +  + ]:          6 :     if (identifier != "" && identifier != "/") {
         [ +  - ][ -  + ]
                 [ +  + ]
     227 [ +  - ][ +  - ]:          1 :         spec_part = find_spec_part(spec_part, identifier);
     228                 :            :     }
     229         [ +  - ]:          6 :     spec_name_list(result, spec_part, identifier, recurse);
     230                 :          6 :     return (result);
     231                 :            : }
     232                 :            : 
     233                 :            : /// Returns an ElementPtr containing a MapElement with identifier->value
     234                 :            : /// pairs.
     235                 :            : ConstElementPtr
     236                 :          3 : ConfigData::getFullConfig() const {
     237                 :          3 :     ElementPtr result = Element::createMap();
     238 [ +  - ][ +  - ]:          3 :     ConstElementPtr items = getItemList("", true);
     239 [ +  - ][ +  + ]:         87 :     BOOST_FOREACH(ConstElementPtr item, items->listValue()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     240 [ +  - ][ +  - ]:         21 :         result->set(item->stringValue(), getValue(item->stringValue()));
         [ +  - ][ +  - ]
     241                 :            :     }
     242                 :          3 :     return (result);
     243                 :            : }
     244                 :            : 
     245                 :            : }
     246                 :        110 : }

Generated by: LCOV version 1.9