"Fossies" - the Fresh Open Source Software Archive

Member "kea-1.7.1/src/lib/yang/adaptor.cc" (29 Oct 2019, 9826 Bytes) of package /linux/misc/kea-1.7.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "adaptor.cc" see the Fossies "Dox" file reference documentation.

    1 // Copyright (C) 2018 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 
    7 #include <yang/adaptor.h>
    8 #include <boost/foreach.hpp>
    9 
   10 #include <iostream>
   11 
   12 using namespace std;
   13 using namespace isc::data;
   14 
   15 namespace isc {
   16 namespace yang {
   17 
   18 Adaptor::Adaptor() {
   19 }
   20 
   21 Adaptor::~Adaptor() {
   22 }
   23 
   24 ConstElementPtr
   25 Adaptor::getContext(ConstElementPtr parent)
   26 {
   27     ConstElementPtr context = parent->get("user-context");
   28     ConstElementPtr comment = parent->get("comment");
   29     if (!comment) {
   30         return (context);
   31     }
   32     ElementPtr result;
   33     if (context) {
   34         result = copy(context);
   35     } else {
   36         result = Element::createMap();
   37     }
   38     result->set("comment", comment);
   39     return (result);
   40 }
   41 
   42 void
   43 Adaptor::fromParent(const string& name, ConstElementPtr parent,
   44                     ConstElementPtr list) {
   45     ConstElementPtr param = parent->get(name);
   46     if (!param) {
   47         return;
   48     }
   49     BOOST_FOREACH(ElementPtr item, list->listValue()) {
   50         // don't override. Skip this entry if it already has the parameter.
   51         if (item->contains(name)) {
   52             continue;
   53         }
   54         item->set(name, param);
   55     }
   56 }
   57 
   58 void
   59 Adaptor::toParent(const string& name, ElementPtr parent,
   60                   ConstElementPtr list) {
   61     ConstElementPtr param;
   62     bool first = true;
   63     BOOST_FOREACH(ElementPtr item, list->listValue()) {
   64         if (first) {
   65             first = false;
   66             param = item->get(name);
   67         } else if ((!param && item->contains(name)) ||
   68                    (param && !item->contains(name)) ||
   69                    (param && item->contains(name) &&
   70                     !param->equals(*item->get(name)))) {
   71             isc_throw(BadValue,
   72                       "inconsistent value of " << name
   73                       << " in " << list->str());
   74         }
   75     }
   76     if (!first && param) {
   77         BOOST_FOREACH(ElementPtr item, list->listValue()) {
   78             if (param) {
   79                 item->remove(name);
   80             }
   81         }
   82         parent->set(name, param);
   83     }
   84 }
   85 
   86 namespace {
   87 
   88 /// @brief Apply insert.
   89 ///
   90 /// This function applies an insert action at the given scope:
   91 ///  - in a map it adds the value at the key when the key does not exist
   92 ///  - in a list it appends the value
   93 ///  - in other scope type it does nothing
   94 /// @note a copy of the value is used to avoid unwanted sharing/side effects.
   95 ///
   96 /// @param key The key of the modification.
   97 /// @param value The value of the modification.
   98 /// @param scope The place to apply the insert.
   99 void applyInsert(ConstElementPtr key, ConstElementPtr value,
  100                  ElementPtr scope) {
  101     if (scope->getType() == Element::map) {
  102         if (!key || !value || (key->getType() != Element::string)) {
  103             return;
  104         }
  105         string name = key->stringValue();
  106         if (!name.empty() && !scope->contains(name)) {
  107             scope->set(name, copy(value));
  108         }
  109     } else if (scope->getType() == Element::list) {
  110         if (value) {
  111             scope->add(copy(value));
  112         }
  113     }
  114 }
  115 
  116 /// @brief Apply replace.
  117 ///
  118 /// This function works only on map scopes and acts as insert at the
  119 /// exception the new value is set even if the key already exists.
  120 ///
  121 /// @param key The key of the modification.
  122 /// @param value The value of the modification.
  123 /// @param scope The place to apply the replace.
  124 void applyReplace(ConstElementPtr key, ConstElementPtr value,
  125                    ElementPtr scope) {
  126     if ((scope->getType() != Element::map) ||
  127         !key || !value || (key->getType() != Element::string)) {
  128             return;
  129     }
  130     string name = key->stringValue();
  131     if (!name.empty()) {
  132         scope->set(name, copy(value));
  133     }
  134 }
  135 
  136 /// @brief Apply delete.
  137 ///
  138 /// This function deletes the value designed by the key from the given scope:
  139 ///  - in a map the key is the key of the value to remove
  140 ///  - in a list the key is:
  141 ///     * when it is an integer the index of the value to remove
  142 ///     * when it is a map the key / value pair which belongs to the value
  143 ///      to remove
  144 ///  - in other scope type it does nothing
  145 ///
  146 /// @param key The key item of the path.
  147 /// @param scope The place to apply the delete.
  148 void applyDelete(ConstElementPtr key, ElementPtr scope) {
  149     if (scope->getType() == Element::map) {
  150         if (!key || (key->getType() != Element::string)) {
  151             return;
  152         }
  153         string name = key->stringValue();
  154         if (!name.empty()) {
  155             scope->remove(name);
  156         }
  157     } else if (scope->getType() == Element::list) {
  158         if (!key) {
  159             return;
  160         } else if (key->getType() == Element::integer) {
  161             int index = key->intValue();
  162             if ((index >= 0) && (index < scope->size())) {
  163                 scope->remove(index);
  164             }
  165         } else if (key->getType() == Element::map) {
  166             ConstElementPtr entry = key->get("key");
  167             ConstElementPtr value = key->get("value");
  168             if (!entry || !value || (entry->getType() != Element::string)) {
  169                 return;
  170             }
  171             string name = entry->stringValue();
  172             if (name.empty()) {
  173                 return;
  174             }
  175             for (int i = 0; i < scope->size(); ++i) {
  176                 ConstElementPtr item = scope->get(i);
  177                 if (!item || (item->getType() != Element::map)) {
  178                     continue;
  179                 }
  180                 ConstElementPtr compare = item->get(name);
  181                 if (compare && value->equals(*compare)) {
  182                     scope->remove(i);
  183                     return;
  184                 }
  185             }
  186         }
  187     }
  188 }
  189 
  190 /// @brief Apply action.
  191 ///
  192 /// This function applies one action (insert, replace or delete) using
  193 /// applyInsert, applyReplace or applyDelete.
  194 ///
  195 /// @param actions The action list.
  196 /// @param scope The current scope.
  197 /// @param next The index of the next action.
  198 void applyAction(ConstElementPtr actions, ElementPtr scope, size_t next) {
  199     if (next == actions->size()) {
  200         return;
  201     }
  202     ConstElementPtr action = actions->get(next);
  203     ++next;
  204     if (!action || (action->getType() != Element::map) ||
  205         !action->contains("action")) {
  206         applyAction(actions, scope, next);
  207         return;
  208     }
  209     string name = action->get("action")->stringValue();
  210     if (name == "insert") {
  211         applyInsert(action->get("key"), action->get("value"), scope);
  212     } else if (name == "replace") {
  213         applyReplace(action->get("key"), action->get("value"), scope);
  214     } else if (name == "delete") {
  215         applyDelete(action->get("key"), scope);
  216     }
  217     applyAction(actions, scope, next);
  218 }
  219 
  220 /// @brief Apply recursively actions following the path and going down
  221 /// in the to-be-modified structure.
  222 ///
  223 /// The recursive call when the end of the path is not reached is done:
  224 ///  - in a map on the value at the key
  225 ///  - in a list the next path item is:
  226 ///     * if it is a positive integer on the value at the index
  227 ///     * if it is -1 on all elements of the list
  228 ///     * if a map on the element where the key / value pair belongs to
  229 ///
  230 /// @param path The search list.
  231 /// @param actions The action list.
  232 /// @param scope The current scope.
  233 /// @param next The index of the next item to use in the path.
  234 void applyDown(ConstElementPtr path, ConstElementPtr actions, ElementPtr scope,
  235                size_t next) {
  236     if (!scope) {
  237         return;
  238     }
  239     if (next == path->size()) {
  240         applyAction(actions, scope, 0);
  241         return;
  242     }
  243     ConstElementPtr step = path->get(next);
  244     ++next;
  245     if (scope->getType() == Element::map) {
  246         if (!step || (step->getType() != Element::string)) {
  247             return;
  248         }
  249         string name = step->stringValue();
  250         if (name.empty() || !scope->contains(name)) {
  251             return;
  252         }
  253         ElementPtr down = boost::const_pointer_cast<Element>(scope->get(name));
  254         if (down) {
  255             applyDown(path, actions, down, next);
  256         }
  257     } else if (scope->getType() == Element::list) {
  258         if (!step) {
  259             return;
  260         }
  261         auto downs = scope->listValue();
  262         if (step->getType() == Element::map) {
  263             ConstElementPtr key = step->get("key");
  264             ConstElementPtr value = step->get("value");
  265             if (!key || !value || (key->getType() != Element::string)) {
  266                 return;
  267             }
  268             string name = key->stringValue();
  269             if (name.empty()) {
  270                 return;
  271             }
  272             for (ElementPtr down : downs) {
  273                 if (!down || (down->getType() != Element::map)) {
  274                     continue;
  275                 }
  276                 ConstElementPtr compare = down->get(name);
  277                 if (compare && value->equals(*compare)) {
  278                     applyDown(path, actions, down, next);
  279                     return;
  280                 }
  281             }
  282         } else if (step->getType() != Element::integer) {
  283             return;
  284         }
  285         int index = step->intValue();
  286         if (index == -1) {
  287             for (ElementPtr down : downs) {
  288                 applyDown(path, actions, down, next);
  289             }
  290         } else if ((index >= 0) && (index < scope->size())) {
  291             applyDown(path, actions, scope->getNonConst(index), next);
  292         }
  293     }
  294 }
  295 
  296 } // end of anonymous namespace
  297 
  298 /// Apply recursively starting at the beginning of the path.
  299 void
  300 Adaptor::modify(ConstElementPtr path, ConstElementPtr actions,
  301                 ElementPtr config) {
  302     applyDown(path, actions, config, 0);
  303 }
  304 
  305 }; // end of namespace isc::yang
  306 }; // end of namespace isc