Exemplo n.º 1
0
// ATTN: This function seriously needs re-organization, will be done
// shortly.
rw_yang_netconf_op_status_t XMLDocMerger::do_edit(XMLNode* new_node, 
                XMLNode* delta_node,
                XMLNode* update_node,
                bool* update_required)
{
  rw_yang_netconf_op_status_t status = RW_YANG_NETCONF_OP_STATUS_OK;
  YangNode* ynode = new_node->get_descend_yang_node();
  XMLEditDefaultOperation parent_op = current_operation_;

  for(XMLNodeIter it = delta_node->child_begin();
      it != delta_node->child_end(); ++it)
  {
    XMLNode* delta_child = &(*it);
    std::string child_name = delta_child->get_local_name();
    std::string child_ns = delta_child->get_name_space();

    YangNode* child_ynode = ynode->search_child(child_name.c_str(), 
                                                child_ns.c_str());
    if (child_ynode == nullptr) {
      // Incoming node is not in our model and thus is an error
      std::string const err_msg = "Cannot find child ("+child_name+") of node ("+delta_node->get_local_name()+")";
      report_error(delta_node, RW_YANG_NETCONF_OP_STATUS_INVALID_VALUE, err_msg.c_str());
      return RW_YANG_NETCONF_OP_STATUS_INVALID_VALUE;
    }

    // Set the current node operation (default=merge)
    status = set_current_operation(delta_child);
    if (status !=  RW_YANG_NETCONF_OP_STATUS_OK) {
      return status;
    }

    bool subtree_update = false;

    XMLNode* new_child = new_node->find(child_name.c_str(), child_ns.c_str());
    if (new_child == nullptr) {
      // Node not found in existing config, edit-config on new node
      status = do_edit_new(child_ynode, new_node, delta_child, 
                           update_node, &subtree_update);
    } else {
      status = do_edit_existing(child_ynode, new_node, new_child, delta_child,
                           update_node, &subtree_update);
    }

    *update_required = (*update_required || subtree_update);

    if (status !=  RW_YANG_NETCONF_OP_STATUS_OK) {
      return status;
    }
    current_operation_ = parent_op;
  }

  if (current_operation_ == XML_EDIT_OP_REPLACE) {
    // Iterate thru the config dom node and find the elements not in delta
    // Those are marked for deletion.
    do_delete_missing(new_node, delta_node);
  }

  // Add defaults
  fill_defaults(ynode, new_node, update_node, update_required);

  if (!(*update_required)) {
    // No updates on this subtree. Either it is delete/remove operation or
    // the config is not changed. So remove the update subtree. 
    XMLNode* parent = update_node->get_parent();
    if (parent) {
      parent->remove_child(update_node);
    }
  }

  if (new_node->get_first_child() == nullptr &&
      ynode->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER &&
      !ynode->is_presence()) {
    // No children for a non-presence container, they are only present to
    // maintain hierarchy. Remove it
    XMLNode* parent = new_node->get_parent();
    if (parent) {
      parent->remove_child(new_node);
    }
  }

  return status;
}
Exemplo n.º 2
0
void XMLDocMerger::fill_defaults(
          YangNode* ynode,
          XMLNode*  new_node,
          XMLNode*  update_node,
          bool*     update_required
       )
{
  YangNode* yn = nullptr;
  XMLNode*  xchild = nullptr;

  for (YangNodeIter it = ynode->child_begin();
       it != ynode->child_end(); ++it) {
    yn = &(*it);
    const char* default_val = yn->get_default_value();
    if (!default_val && !yn->has_default()) {
      // Only default values or containers with default leaf descendents
      continue;
    }

    // Default values may be within a choice/case. Check if the choice has
    // another case. If the same case is present
    YangNode* ychoice = yn->get_choice();
    YangNode* ycase = yn->get_case();
    YangNode* other_choice = nullptr;
    YangNode* other_case   = nullptr;
    bool add_default = true;
    bool subtree_update = false;
    if (ychoice && ycase && (ychoice->get_default_case() != ycase)) {
      add_default = false;
    }

    for (XMLNodeIter xit = new_node->child_begin();
         xit != new_node->child_end(); ++xit) {
      xchild = &(*xit);
      if (xchild->get_local_name() == yn->get_name() &&
          xchild->get_name_space() == yn->get_ns()) {
        if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER) {
          // The container has a default descendant node
          XMLNode* update_child = nullptr;
          bool created = false;
          if ((update_child = update_node->find(
                                yn->get_name(), yn->get_ns())) == nullptr) {
            update_child = update_node->add_child(yn);
            created = true;
          }
          fill_defaults(yn, xchild, update_child, &subtree_update);
          if (!subtree_update && created) {
            update_node->remove_child(update_child);
          }
          *update_required = (*update_required || subtree_update);
        }
        // Default node already present in the new-dom
        add_default = false;
        break;
      }
      
      if (!ychoice) {
        // Not part of a choice
        continue;
      }

      other_choice = xchild->get_yang_node()->get_choice();
      if (!other_choice || (other_choice != ychoice)) {
        // Other node is not a choice, or not the same choice, not conflicting
        continue;
      }

      other_case = xchild->get_yang_node()->get_case();
      if (other_case && (ycase != other_case)) {
        // There is a node with conflicting case. Hence no default
        add_default = false;
        break;
      }

      // Same case, in-case the case is not default, some-other node in the same
      // case is set. Then add this default, unless the same node is found in
      // the new-dom.
      add_default = true;
    }
    if (add_default) {
      XMLNode* xn = new_node->add_child(yn, default_val);
      RW_ASSERT(xn);
      XMLNode* un = update_node->add_child(yn, default_val);
      if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER) {
        // The container has a default descendant node
        fill_defaults(yn, xn, un, &subtree_update);
        if (!subtree_update) {
          new_node->remove_child(xn);
          update_node->remove_child(un);
        }
        *update_required = (*update_required || subtree_update);
      } else {
        *update_required = true;
      }
    }
  }
}
Exemplo n.º 3
0
  virtual rw_xml_next_action_t visit(XMLNode* node, XMLNode** path, int32_t level)
  {
    if  (node == nullptr) {
      return RW_XML_ACTION_TERMINATE;
    }

    YangNode *yn = node->get_yang_node();
    
    if (nullptr == yn) {
      return RW_XML_ACTION_NEXT;
    }

    if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_LIST) {
      return RW_XML_ACTION_NEXT_SIBLING;      
    }

    RW_ASSERT(to_node_);
    

    
    // This is the root node then this is the first time call
    if (level == 0) {
      RW_ASSERT(level_ == -1);

      std::string text = node->get_text_value();

      if (node->get_yang_node()->is_leafy() &&
          node->get_yang_node()->get_type()->get_leaf_type() != RW_YANG_LEAF_TYPE_EMPTY && 
          text.find_first_not_of("\t\n\v\f\r ") != std::string::npos) {
        if (text.find_first_of ("http")) {
          RW_CRASH();
        }
        
        curr_node_ = to_node_->add_child(node->get_yang_node(), node->get_text_value().c_str());
      } else {
        curr_node_ = to_node_->add_child(node->get_yang_node());
      }
      path_[++level_].first = node;
      path_[level_].second = curr_node_;
      
      return RW_XML_ACTION_NEXT;
    }
    
    XMLNode *from_parent = path[level-1];
    
    RW_ASSERT(from_parent);
    
    // Walk up our path and find the corresponding parent in teh vistor's tree
    
    while(level_ >= 0)  {
      if (path_[level_].first == from_parent) {
        // Found a common parent - break  and add the new node
        XMLNode *to_parent = static_cast<XMLNode*>(path_[level_].second);

        std::string text = node->get_text_value();

        if (text.find_first_not_of("\t\n\v\f\r ") != std::string::npos) {
          // A bit of a hack to ensure that white spaces are not inserted to the
          // XML. This is a problem for UT that read from files 
          
          curr_node_ = to_parent->add_child(node->get_yang_node(), node->get_text_value().c_str());
        } else {
          curr_node_ = to_parent->add_child(node->get_yang_node());
        }
        
        
        // Replace the node in the current path with the new node.
        path_[++level_].first = node;
        path_[level_].second  = curr_node_;
        break;
      }
      level_--;
    }
    RW_ASSERT(level_ > 0);
    
    return RW_XML_ACTION_NEXT;
  }