<module>yang-common</module>
<module>yang-data-api</module>
<module>yang-data-util</module>
+ <module>yang-data-impl</module>
<module>yang-model-api</module>
<module>yang-model-util</module>
<module>yang-binding</module>
+++ /dev/null
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.yang.data.api;\r
-\r
-import org.opendaylight.controller.yang.common.QName;\r
-\r
-/**\r
- * For the use cases of changing the state data, the node modifications are\r
- * modeled as part of additional metadata in data tree. The modification types\r
- * are based on Netconf edit-config RPCs. In order to modify the configuration\r
- * or state data tree the user must create a tree representing the modification\r
- * of the data and apply that modification to the target tree.\r
- * \r
- * \r
- * @see <a href="http://tools.ietf.org/html/rfc6241">Network Configuration\r
- * Protocol (NETCONF)</a>\r
- * \r
- */\r
-public interface CompositeNodeModification extends CompositeNode {\r
-\r
- ModifyAction getModificationAction();\r
-\r
- // Container Modification\r
-\r
- /**\r
- * The data identified by the node containing this modification is merged\r
- * with the data at the corresponding level in the data tree\r
- * \r
- * @param node\r
- * in data tree\r
- */\r
- void mergeChild(CompositeNode node);\r
-\r
- /**\r
- * The data identified by the node containing this modification replaces any\r
- * related data in the target data tree If no such data exists in the target\r
- * data tree, the child node is created.\r
- * \r
- * @param node\r
- * composite node\r
- */\r
- void replaceChild(CompositeNode node);\r
-\r
- /**\r
- * Adds new composite node into data tree\r
- * \r
- * @param node\r
- * composite node\r
- */\r
- void addChild(CompositeNode node);\r
-\r
- /**\r
- * The data identified by the node containing this modification is deleted\r
- * from the target data tree if and only if the data currently exists in the\r
- * target data tree. If the data does not exist, an error is returned with\r
- * an error value of "data-missing".\r
- * \r
- * @param node\r
- */\r
- void deleteChild(CompositeNode node);\r
-\r
- /**\r
- * The data identified by the node containing this attribute is deleted from\r
- * the target data tree if the data currently exists in the target data\r
- * tree. If the data does not exist, the modification is silently ignored.\r
- * \r
- * @param node\r
- * composite node\r
- */\r
- void removeChild(CompositeNode node);\r
-\r
- // Leaf Modifications\r
-\r
- /**\r
- * The data identified by the node containing this modification replaces any\r
- * related data in the target data tree If no such data exists in the target\r
- * data tree, it is created.\r
- * \r
- * @param leaf\r
- */\r
- void replaceSimpleNode(SimpleNode<?> leaf);\r
-\r
- /**\r
- * The data identified by the node containing this modification is deleted\r
- * from the target data tree if and only if the data currently exists in the\r
- * target data tree. If the data does not exist, an error is returned with\r
- * an error value of "data-missing".\r
- * \r
- * @param leaf\r
- */\r
- void deleteSimpleNode(SimpleNode<?> leaf);\r
-\r
- /**\r
- * The data identified by the node containing this attribute is deleted from\r
- * the target data tree if the data currently exists in the target data\r
- * tree. If the data does not exist, the modification is silently ignored.\r
- * \r
- * @param leaf\r
- */\r
- void removeSimpleNode(SimpleNode<?> leaf);\r
-\r
- void removeLeaf(SimpleNode<?> leaf);\r
-\r
- void removeLeaf(QName leaf);\r
-}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.api;\r
+\r
+import java.util.List;\r
+\r
+\r
+/**\r
+ * @author michal.rehak\r
+ *\r
+ */\r
+public interface MutableCompositeNode extends MutableNode<List<Node<?>>>, CompositeNode {\r
+ \r
+ /**\r
+ * update internal map\r
+ */\r
+ public void init();\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.api;\r
+\r
+\r
+/**\r
+ * Base representation of node in the data tree, defines basic parameters of\r
+ * node such as a QName.\r
+ * \r
+ * \r
+ * @param <T>\r
+ */\r
+public interface MutableNode<T> extends Node<T> {\r
+\r
+ /**\r
+ * @param parent value to set\r
+ */\r
+ void setParent(CompositeNode parent);\r
+ \r
+ /**\r
+ * @param value value to set (children list or leaf value)\r
+ */\r
+ void setValue(T value);\r
+ \r
+ /**\r
+ * @param action value to set\r
+ */\r
+ void setModifyAction(ModifyAction action);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.api;\r
+\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * @param <T> node value type\r
+ *\r
+ */\r
+public interface MutableSimpleNode<T> extends MutableNode<T>, SimpleNode<T> {\r
+ \r
+ // nothing\r
+ \r
+}\r
/**\r
* Returns the name of the Node\r
* \r
- * @return\r
+ * @return qName of node\r
*/\r
QName getNodeType();\r
\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.api;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public interface NodeModification {\r
+\r
+ /**\r
+ * @return modify action\r
+ */\r
+ ModifyAction getModificationAction();\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.api;\r
+\r
+\r
+/**\r
+ * @author michal.rehak\r
+ *\r
+ */\r
+public interface NodeModificationBuilder {\r
+\r
+ public abstract Node<?> getMutableEquivalent(Node<?> originalNode);\r
+\r
+ public abstract CompositeNode buildDiffTree();\r
+\r
+ public abstract void mergeNode(MutableCompositeNode alteredNode);\r
+\r
+ public abstract void removeNode(MutableCompositeNode deadNode);\r
+\r
+ public abstract void removeNode(MutableSimpleNode<?> deadNode);\r
+\r
+ public abstract void deleteNode(MutableSimpleNode<?> deadNode);\r
+\r
+ public abstract void deleteNode(MutableCompositeNode deadNode);\r
+\r
+ public abstract void replaceNode(MutableCompositeNode replacementNode);\r
+\r
+ public abstract void replaceNode(MutableSimpleNode<?> replacementNode);\r
+\r
+ public abstract void addNode(MutableCompositeNode newNode);\r
+\r
+ public abstract void addNode(MutableSimpleNode<?> newNode);\r
+\r
+}\r
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0"\r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+ <modelVersion>4.0.0</modelVersion>\r
+ <parent>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>yang</artifactId>\r
+ <version>0.5.3-SNAPSHOT</version>\r
+ </parent>\r
+ <artifactId>yang-data-impl</artifactId>\r
+\r
+ <properties>\r
+ <groovy.version>2.1.5</groovy.version>\r
+ </properties>\r
+\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-surefire-plugin</artifactId>\r
+ <configuration>\r
+ <argLine>-Dlog4j.configuration=log4j-test.xml</argLine>\r
+ <redirectTestOutputToFile>true</redirectTestOutputToFile>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+\r
+\r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>yang-common</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>yang-data-api</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>yang-model-parser-impl</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>com.google.guava</groupId>\r
+ <artifactId>guava</artifactId>\r
+ <version>14.0.1</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>junit</groupId>\r
+ <artifactId>junit</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.slf4j</groupId>\r
+ <artifactId>slf4j-log4j12</artifactId>\r
+ <version>${slf4j.version}</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.codehaus.groovy</groupId>\r
+ <artifactId>groovy</artifactId>\r
+ <version>${groovy.version}</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.codehaus.groovy</groupId>\r
+ <artifactId>groovy-xml</artifactId>\r
+ <version>${groovy.version}</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ </dependencies>\r
+</project>
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * @param <T>\r
+ * type of node value\r
+ * \r
+ */\r
+public abstract class AbstractNodeTO<T> implements Node<T> {\r
+\r
+ private QName qName;\r
+ private CompositeNode parent;\r
+ private T value;\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent\r
+ * @param value\r
+ */\r
+ public AbstractNodeTO(QName qname, CompositeNode parent, T value) {\r
+ this.qName = qname;\r
+ this.parent = parent;\r
+ this.value = value;\r
+ }\r
+\r
+ @Override\r
+ public QName getNodeType() {\r
+ return qName;\r
+ }\r
+\r
+ /**\r
+ * @return the qName\r
+ */\r
+ protected QName getQName() {\r
+ return qName;\r
+ }\r
+\r
+ @Override\r
+ public CompositeNode getParent() {\r
+ return parent;\r
+ }\r
+ \r
+ /**\r
+ * @param parent the parent to set\r
+ */\r
+ public void setParent(CompositeNode parent) {\r
+ this.parent = parent;\r
+ }\r
+ \r
+ /**\r
+ * @param value the value to set\r
+ */\r
+ protected void setValue(T value) {\r
+ this.value = value;\r
+ }\r
+\r
+ @Override\r
+ public T getValue() {\r
+ return value;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * \r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.NodeModification;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public class CompositeNodeModificationTOImpl extends CompositeNodeTOImpl\r
+ implements NodeModification {\r
+\r
+ private ModifyAction modifyAction;\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent\r
+ * @param value\r
+ * @param modifyAction\r
+ */\r
+ public CompositeNodeModificationTOImpl(QName qname, CompositeNode parent,\r
+ List<Node<?>> value, ModifyAction modifyAction) {\r
+ super(qname, parent, value);\r
+ this.modifyAction = modifyAction;\r
+ }\r
+\r
+ /**\r
+ * @return modification action\r
+ * @see org.opendaylight.controller.yang.data.impl.NodeModificationSupport#getModificationAction()\r
+ */\r
+ @Override\r
+ public ModifyAction getModificationAction() {\r
+ return modifyAction;\r
+ }\r
+\r
+ /**\r
+ * @param modifyAction\r
+ * the modifyAction to set\r
+ */\r
+ protected void setModificationAction(ModifyAction modifyAction) {\r
+ this.modifyAction = modifyAction;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.SimpleNode;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public class CompositeNodeTOImpl extends AbstractNodeTO<List<Node<?>>>\r
+ implements CompositeNode {\r
+\r
+ private Map<QName, List<Node<?>>> nodeMap;\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent use null to create top composite node (without parent)\r
+ * @param value\r
+ */\r
+ public CompositeNodeTOImpl(QName qname, CompositeNode parent,\r
+ List<Node<?>> value) {\r
+ super(qname, parent, value);\r
+ if (value != null) {\r
+ nodeMap = NodeUtils.buildNodeMap(getValue());\r
+ }\r
+ }\r
+ \r
+\r
+ /**\r
+ * @return the nodeMap\r
+ */\r
+ protected Map<QName, List<Node<?>>> getNodeMap() {\r
+ return nodeMap;\r
+ }\r
+ \r
+ @Override\r
+ public List<Node<?>> getChildren() {\r
+ return getValue();\r
+ }\r
+\r
+ @Override\r
+ public SimpleNode<?> getFirstSimpleByName(QName leafQName) {\r
+ List<SimpleNode<?>> list = getSimpleNodesByName(leafQName);\r
+ if (list.isEmpty())\r
+ return null;\r
+ return list.get(0);\r
+ }\r
+\r
+ @Override\r
+ public List<CompositeNode> getCompositesByName(QName children) {\r
+ List<Node<?>> toFilter = getNodeMap().get(children);\r
+ List<CompositeNode> list = new ArrayList<CompositeNode>();\r
+ for (Node<?> node : toFilter) {\r
+ if (node instanceof CompositeNode)\r
+ list.add((CompositeNode) node);\r
+ }\r
+ return list;\r
+ }\r
+\r
+ @Override\r
+ public List<SimpleNode<?>> getSimpleNodesByName(QName children) {\r
+ List<Node<?>> toFilter = getNodeMap().get(children);\r
+ List<SimpleNode<?>> list = new ArrayList<SimpleNode<?>>();\r
+\r
+ for (Node<?> node : toFilter) {\r
+ if (node instanceof SimpleNode<?>)\r
+ list.add((SimpleNode<?>) node);\r
+ }\r
+ return list;\r
+ }\r
+\r
+ @Override\r
+ public CompositeNode getFirstCompositeByName(QName container) {\r
+ List<CompositeNode> list = getCompositesByName(container);\r
+ if (list.isEmpty()) {\r
+ return null;\r
+ }\r
+ return list.get(0);\r
+ }\r
+\r
+ /**\r
+ * @param leaf\r
+ * @return TODO:: do we need this method?\r
+ */\r
+ public SimpleNode<?> getFirstLeafByName(QName leaf) {\r
+ List<SimpleNode<?>> list = getSimpleNodesByName(leaf);\r
+ if (list.isEmpty()) {\r
+ return null;\r
+ }\r
+ return list.get(0);\r
+ }\r
+\r
+ @Override\r
+ public List<CompositeNode> getCompositesByName(String children) {\r
+ return getCompositesByName(localQName(children));\r
+ }\r
+ \r
+ @Override\r
+ public List<SimpleNode<?>> getSimpleNodesByName(String children) {\r
+ return getSimpleNodesByName(localQName(children));\r
+ }\r
+\r
+ private QName localQName(String str) {\r
+ return new QName(getNodeType(), str);\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.MutableCompositeNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public class MutableCompositeNodeTOImpl extends CompositeNodeModificationTOImpl\r
+ implements MutableCompositeNode {\r
+\r
+ private Map<QName, List<Node<?>>> nodeMap;\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent\r
+ * @param value\r
+ * @param modifyAction\r
+ */\r
+ public MutableCompositeNodeTOImpl(QName qname, CompositeNode parent,\r
+ List<Node<?>> value, ModifyAction modifyAction) {\r
+ super(qname, parent, value, modifyAction);\r
+ }\r
+ \r
+ /**\r
+ * update nodeMap\r
+ */\r
+ @Override\r
+ public void init() {\r
+ nodeMap = NodeUtils.buildNodeMap(getChildren());\r
+ }\r
+\r
+ @Override\r
+ public void setValue(List<Node<?>> value) {\r
+ super.setValue(value);\r
+ }\r
+ \r
+ @Override\r
+ public void setModifyAction(ModifyAction action) {\r
+ super.setModificationAction(action);\r
+ }\r
+ \r
+ @Override\r
+ protected Map<QName, List<Node<?>>> getNodeMap() {\r
+ return nodeMap;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.MutableSimpleNode;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * @param <T> type of simple node value\r
+ * \r
+ */\r
+public class MutableSimpleNodeTOImpl<T> extends SimpleNodeModificationTOImpl<T> \r
+ implements MutableSimpleNode<T> {\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent\r
+ * @param value\r
+ * @param modifyAction\r
+ */\r
+ public MutableSimpleNodeTOImpl(QName qname, CompositeNode parent, T value,\r
+ ModifyAction modifyAction) {\r
+ super(qname, parent, value, modifyAction);\r
+ }\r
+\r
+ @Override\r
+ public void setValue(T value) {\r
+ super.setValue(value);\r
+ }\r
+ \r
+ @Override\r
+ public void setModifyAction(ModifyAction action) {\r
+ super.setModificationAction(action);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.util.AbstractMap.SimpleEntry;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Stack;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.MutableCompositeNode;\r
+import org.opendaylight.controller.yang.data.api.MutableSimpleNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.SimpleNode;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public abstract class NodeFactory {\r
+\r
+ /**\r
+ * @param qName\r
+ * @param parent\r
+ * @param value\r
+ * @return simple node modification, based on given qname, value and parent\r
+ */\r
+ public static <T> SimpleNode<T> createSimpleNode(QName qName,\r
+ CompositeNode parent, T value) {\r
+ SimpleNodeTOImpl<T> simpleNodeTOImpl = new SimpleNodeTOImpl<T>(qName, parent, value);\r
+ return simpleNodeTOImpl;\r
+ }\r
+ \r
+ /**\r
+ * @param qName\r
+ * @param parent\r
+ * @param value\r
+ * @return simple node modification, based on given qname, value and parent\r
+ */\r
+ public static <T> MutableSimpleNode<T> createMutableSimpleNode(QName qName,\r
+ CompositeNode parent, T value) {\r
+ MutableSimpleNodeTOImpl<T> simpleNodeTOImpl = \r
+ new MutableSimpleNodeTOImpl<T>(qName, parent, value, null);\r
+ return simpleNodeTOImpl;\r
+ }\r
+\r
+ /**\r
+ * @param qName\r
+ * @param parent\r
+ * @param value\r
+ * @return composite node modification, based on given qname, value (children), parent and modifyAction\r
+ */\r
+ public static CompositeNode createCompositeNode(QName qName,\r
+ CompositeNode parent, List<Node<?>> value) {\r
+ CompositeNode compositeNodeTOImpl = new CompositeNodeTOImpl(qName, parent, value);\r
+ return compositeNodeTOImpl;\r
+ }\r
+ \r
+ /**\r
+ * @param qName\r
+ * @param parent\r
+ * @param value\r
+ * @return composite node modification, based on given qname, value (children), parent and modifyAction\r
+ */\r
+ public static MutableCompositeNode createMutableCompositeNode(QName qName,\r
+ CompositeNode parent, List<Node<?>> value) {\r
+ MutableCompositeNodeTOImpl compositeNodeTOImpl = \r
+ new MutableCompositeNodeTOImpl(qName, parent, value, null);\r
+ return compositeNodeTOImpl;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * @param qName\r
+ * @param parent\r
+ * @param value\r
+ * @param modifyAction\r
+ * @return simple node modification, based on given qname, value, parent and modifyAction\r
+ */\r
+ public static <T> SimpleNodeModificationTOImpl<T> createSimpleNodeModification(QName qName,\r
+ CompositeNode parent, T value, ModifyAction modifyAction) {\r
+ SimpleNodeModificationTOImpl<T> simpleNodeModTOImpl = \r
+ new SimpleNodeModificationTOImpl<T>(qName, parent, value, modifyAction);\r
+ return simpleNodeModTOImpl;\r
+ }\r
+\r
+ /**\r
+ * @param qName\r
+ * @param parent\r
+ * @param value\r
+ * @param modifyAction \r
+ * @return composite node modification, based on given qname, value (children), parent and modifyAction\r
+ */\r
+ public static CompositeNodeModificationTOImpl createCompositeNodeModification(QName qName,\r
+ CompositeNode parent, List<Node<?>> value, ModifyAction modifyAction) {\r
+ CompositeNodeModificationTOImpl compositeNodeModTOImpl = \r
+ new CompositeNodeModificationTOImpl(qName, parent, value, modifyAction);\r
+ return compositeNodeModTOImpl;\r
+ }\r
+\r
+ /**\r
+ * @param node\r
+ * @return copy of given node, parent and value are the same, but parent \r
+ * has no reference to this copy \r
+ */\r
+ public static <T> SimpleNode<T> copyNode(SimpleNode<T> node) {\r
+ SimpleNode<T> twinNode = createSimpleNode(\r
+ node.getNodeType(), node.getParent(), node.getValue());\r
+ return twinNode;\r
+ }\r
+ \r
+ /**\r
+ * @param node\r
+ * @return copy of given node, parent and value are the same, but parent \r
+ * has no reference to this copy \r
+ */\r
+ public static <T> SimpleNode<T> copyNodeAsMutable(SimpleNode<T> node) {\r
+ SimpleNode<T> twinNode = createMutableSimpleNode(\r
+ node.getNodeType(), node.getParent(), node.getValue());\r
+ return twinNode;\r
+ }\r
+\r
+ /**\r
+ * @param node\r
+ * @param children \r
+ * @return copy of given node, parent and children are the same, but parent and children \r
+ * have no reference to this copy\r
+ */\r
+ public static CompositeNode copyNode(CompositeNode node, Node<?>... children) {\r
+ CompositeNode twinNode = createCompositeNode(\r
+ node.getNodeType(), node.getParent(), Arrays.asList(children));\r
+ return twinNode;\r
+ }\r
+ \r
+ /**\r
+ * @param node\r
+ * @return copy of given node, parent and children are the same, but parent and children \r
+ * have no reference to this copy\r
+ */\r
+ public static CompositeNode copyNode(CompositeNode node) {\r
+ return copyNode(node, node.getChildren().toArray(new Node<?>[0]));\r
+ }\r
+ \r
+ /**\r
+ * @param node root of original tree\r
+ * @param originalToMutable (optional) empty map, where binding between original and copy \r
+ * will be stored\r
+ * @return copy of given node, parent and children are the same, but parent and children \r
+ * have no reference to this copy\r
+ */\r
+ public static MutableCompositeNode copyDeepNode(CompositeNode node, \r
+ Map<Node<?>, Node<?>> originalToMutable) {\r
+ \r
+ MutableCompositeNode mutableRoot = \r
+ createMutableCompositeNode(node.getNodeType(), null, null);\r
+ Stack<SimpleEntry<CompositeNode, MutableCompositeNode>> jobQueue = new Stack<>();\r
+ jobQueue.push(new SimpleEntry<CompositeNode, MutableCompositeNode>(node, mutableRoot));\r
+ if (originalToMutable != null) {\r
+ originalToMutable.put(node, mutableRoot);\r
+ }\r
+ \r
+ while (!jobQueue.isEmpty()) {\r
+ SimpleEntry<CompositeNode, MutableCompositeNode> job = jobQueue.pop();\r
+ CompositeNode originalNode = job.getKey();\r
+ MutableCompositeNode mutableNode = job.getValue();\r
+ mutableNode.setValue(new ArrayList<Node<?>>());\r
+ \r
+ for (Node<?> child : originalNode.getChildren()) {\r
+ Node<?> mutableAscendant = null;\r
+ if (child instanceof CompositeNode) {\r
+ MutableCompositeNode newMutable = \r
+ createMutableCompositeNode(child.getNodeType(), mutableNode, null);\r
+ jobQueue.push(new SimpleEntry<CompositeNode, MutableCompositeNode>(\r
+ (CompositeNode) child, newMutable));\r
+ mutableAscendant = newMutable;\r
+ } else if (child instanceof SimpleNode<?>) {\r
+ mutableAscendant = \r
+ createMutableSimpleNode(child.getNodeType(), mutableNode, child.getValue());\r
+ } else {\r
+ throw new IllegalStateException("Node class deep copy not supported: "\r
+ +child.getClass().getName());\r
+ }\r
+ \r
+ mutableNode.getChildren().add(mutableAscendant);\r
+ if (originalToMutable != null) {\r
+ originalToMutable.put(child, mutableAscendant);\r
+ }\r
+ }\r
+ mutableNode.init();\r
+ }\r
+ \r
+ return mutableRoot;\r
+ }\r
+ \r
+}\r
--- /dev/null
+/**\r
+ * \r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.MutableCompositeNode;\r
+import org.opendaylight.controller.yang.data.api.MutableNode;\r
+import org.opendaylight.controller.yang.data.api.MutableSimpleNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.NodeModificationBuilder;\r
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ *\r
+ */\r
+public class NodeModificationBuilderImpl implements NodeModificationBuilder {\r
+ \r
+ private SchemaContext context;\r
+ \r
+ private Set<MutableNode<?>> changeLog;\r
+ private Map<Node<?>, Node<?>> originalToMutable;\r
+\r
+ private MutableCompositeNode mutableRoot;\r
+\r
+ /**\r
+ * @param originalTreeRootNode \r
+ * @param context\r
+ */\r
+ public NodeModificationBuilderImpl(CompositeNode originalTreeRootNode, SchemaContext context) {\r
+ this.context = context;\r
+ originalToMutable = new HashMap<>();\r
+ mutableRoot = NodeFactory.copyDeepNode(originalTreeRootNode, originalToMutable);\r
+ changeLog = new HashSet<>();\r
+ }\r
+\r
+ /**\r
+ * add given node to it's parent's list of children\r
+ * @param newNode\r
+ */\r
+ private static void fixParentRelation(Node<?> newNode) {\r
+ if (newNode.getParent() != null) {\r
+ List<Node<?>> siblings = newNode.getParent().getChildren();\r
+ if (!siblings.contains(newNode)) {\r
+ siblings.add(newNode);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param modNode\r
+ * @param action \r
+ */\r
+ private void addModificationToLog(MutableNode<?> modNode, ModifyAction action) {\r
+ modNode.setModifyAction(action);\r
+ changeLog.add(modNode);\r
+ }\r
+\r
+ @Override\r
+ public void addNode(MutableSimpleNode<?> newNode) {\r
+ fixParentRelation(newNode);\r
+ addModificationToLog(newNode, ModifyAction.CREATE);\r
+ }\r
+ \r
+ @Override\r
+ public void addNode(MutableCompositeNode newNode) {\r
+ fixParentRelation(newNode);\r
+ addModificationToLog(newNode, ModifyAction.CREATE);\r
+ }\r
+ \r
+ @Override\r
+ public void replaceNode(MutableSimpleNode<?> replacementNode) {\r
+ addModificationToLog(replacementNode, ModifyAction.REPLACE);\r
+ }\r
+ \r
+ @Override\r
+ public void replaceNode(MutableCompositeNode replacementNode) {\r
+ addModificationToLog(replacementNode, ModifyAction.REPLACE);\r
+ }\r
+\r
+ @Override\r
+ public void deleteNode(MutableCompositeNode deadNode) {\r
+ addModificationToLog(deadNode, ModifyAction.DELETE);\r
+ }\r
+ \r
+ @Override\r
+ public void deleteNode(MutableSimpleNode<?> deadNode) {\r
+ addModificationToLog(deadNode, ModifyAction.DELETE);\r
+ }\r
+\r
+ @Override\r
+ public void removeNode(MutableSimpleNode<?> deadNode) {\r
+ addModificationToLog(deadNode, ModifyAction.REMOVE);\r
+ }\r
+ \r
+ @Override\r
+ public void removeNode(MutableCompositeNode deadNode) {\r
+ addModificationToLog(deadNode, ModifyAction.REMOVE);\r
+ }\r
+ \r
+ @Override\r
+ public void mergeNode(MutableCompositeNode alteredNode) {\r
+ addModificationToLog(alteredNode, ModifyAction.MERGE);\r
+ }\r
+\r
+ /**\r
+ * @return minimalistic tree containing diffs only\r
+ */\r
+ @Override\r
+ public CompositeNode buildDiffTree() {\r
+ Set<Node<?>> wanted = new HashSet<>();\r
+ \r
+ // walk changeLog, collect all required nodes\r
+ for (MutableNode<?> mutant : changeLog) {\r
+ wanted.addAll(collectSelfAndAllParents(mutant));\r
+ }\r
+ \r
+ // TODO:: walk wanted and add relevant keys\r
+ Map<String, ListSchemaNode> mapOfLists = NodeUtils.buildMapOfListNodes(context);\r
+ Set<Node<?>> wantedKeys = new HashSet<>();\r
+ for (Node<?> outlaw : wanted) {\r
+ if (outlaw instanceof CompositeNode) {\r
+ String path = NodeUtils.buildPath(outlaw);\r
+ if (mapOfLists.containsKey(path)) {\r
+ ListSchemaNode listSchema = mapOfLists.get(path);\r
+ if (listSchema.getQName().equals(outlaw.getNodeType())) {\r
+ // try to add key subnode to wanted list\r
+ List<QName> supportedKeys = listSchema.getKeyDefinition();\r
+ for (Node<?> outlawChildren : ((CompositeNode) outlaw).getChildren()) {\r
+ if (supportedKeys.contains(outlawChildren.getNodeType())) {\r
+ wantedKeys.add(outlawChildren);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ wanted.addAll(wantedKeys);\r
+ \r
+ // remove all unwanted nodes from tree\r
+ removeUnrelevantNodes(mutableRoot, wanted);\r
+ \r
+ return mutableRoot;\r
+ }\r
+\r
+ /**\r
+ * @param mutableRoot2\r
+ * @param wanted\r
+ */\r
+ private static void removeUnrelevantNodes(MutableCompositeNode mutRoot,\r
+ Set<Node<?>> wanted) {\r
+ Stack<MutableNode<?>> jobQueue = new Stack<>();\r
+ jobQueue.push(mutRoot);\r
+ while (!jobQueue.isEmpty()) {\r
+ MutableNode<?> mutNode = jobQueue.pop();\r
+ if (!wanted.contains(mutNode)) {\r
+ if (mutNode.getParent() != null) {\r
+ mutNode.getParent().getChildren().remove(mutNode);\r
+ }\r
+ } else {\r
+ if (mutNode instanceof MutableCompositeNode) {\r
+ for (Node<?> mutChild : ((MutableCompositeNode) mutNode).getChildren()) {\r
+ jobQueue.push((MutableNode<?>) mutChild);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param focusedAncestor\r
+ * @return set of parents and focusedAncestor itself\r
+ */\r
+ private static Set<Node<?>> collectSelfAndAllParents(Node<?> focusedAncestor) {\r
+ Set<Node<?>> family = new HashSet<>();\r
+ Node<?> tmpNode = focusedAncestor;\r
+ while (tmpNode != null) {\r
+ family.add(tmpNode);\r
+ tmpNode = tmpNode.getParent();\r
+ }\r
+ return family;\r
+ }\r
+\r
+ /**\r
+ * @param originalNode\r
+ * @return mutable version of given node\r
+ */\r
+ @Override\r
+ public Node<?> getMutableEquivalent(Node<?> originalNode) {\r
+ return originalToMutable.get(originalNode);\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.util.AbstractMap.SimpleEntry;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Stack;\r
+import java.util.Vector;\r
+\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
+import javax.xml.parsers.ParserConfigurationException;\r
+import javax.xml.xpath.XPath;\r
+import javax.xml.xpath.XPathConstants;\r
+import javax.xml.xpath.XPathExpression;\r
+import javax.xml.xpath.XPathExpressionException;\r
+import javax.xml.xpath.XPathFactory;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.NodeModification;\r
+import org.opendaylight.controller.yang.data.api.SimpleNode;\r
+import org.opendaylight.controller.yang.model.api.DataNodeContainer;\r
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+\r
+import com.google.common.base.Joiner;\r
+\r
+\r
+/**\r
+ * @author michal.rehak\r
+ *\r
+ */\r
+public abstract class NodeUtils {\r
+ \r
+ /**\r
+ * \r
+ */\r
+ private static final String USER_KEY_NODE = "node";\r
+ private static final Logger LOG = LoggerFactory.getLogger(NodeUtils.class);\r
+ \r
+ /**\r
+ * @param node\r
+ * @return node path up till root node\r
+ */\r
+ public static String buildPath(Node<?> node) {\r
+ Vector<String> breadCrumbs = new Vector<>();\r
+ Node<?> tmpNode = node;\r
+ while (tmpNode != null) {\r
+ breadCrumbs.insertElementAt(tmpNode.getNodeType().getLocalName(), 0);\r
+ tmpNode = tmpNode.getParent();\r
+ }\r
+ \r
+ return Joiner.on(".").join(breadCrumbs);\r
+ }\r
+\r
+ \r
+ /**\r
+ * @param treeRootNode\r
+ * @return dom tree, containing same node structure, yang nodes are associated \r
+ * to dom nodes as user data\r
+ */\r
+ public static Document buildShadowDomTree(CompositeNode treeRootNode) {\r
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
+ Document doc = null;\r
+ try {\r
+ DocumentBuilder bob = dbf.newDocumentBuilder();\r
+ doc = bob.newDocument();\r
+ } catch (ParserConfigurationException e) {\r
+ LOG.error("documentBuilder problem", e);\r
+ return null;\r
+ }\r
+ \r
+ Stack<SimpleEntry<org.w3c.dom.Node, Node<?>>> jobQueue = new Stack<>();\r
+ jobQueue.push(new SimpleEntry<org.w3c.dom.Node, Node<?>>(doc, treeRootNode));\r
+ \r
+ while (!jobQueue.isEmpty()) {\r
+ SimpleEntry<org.w3c.dom.Node, Node<?>> job = jobQueue.pop();\r
+ org.w3c.dom.Node jointPlace = job.getKey();\r
+ Node<?> item = job.getValue();\r
+ Element itemEl = doc.createElement(item.getNodeType().getLocalName());\r
+ itemEl.setUserData(USER_KEY_NODE, item, null);\r
+ if (item instanceof SimpleNode<?>) {\r
+ Object value = ((SimpleNode<?>) item).getValue();\r
+ itemEl.setTextContent(String.valueOf(value));\r
+ itemEl.setAttribute("type", value.getClass().getSimpleName());\r
+ }\r
+ if (item instanceof NodeModification) {\r
+ ModifyAction modificationAction = ((NodeModification) item).getModificationAction();\r
+ if (modificationAction != null) {\r
+ itemEl.setAttribute("modifyAction", modificationAction.toString());\r
+ }\r
+ }\r
+ \r
+ jointPlace.appendChild(itemEl);\r
+ \r
+ if (item instanceof CompositeNode) {\r
+ for (Node<?> child : ((CompositeNode) item).getChildren()) {\r
+ jobQueue.push(new SimpleEntry<org.w3c.dom.Node, Node<?>>(itemEl, child));\r
+ }\r
+ }\r
+ }\r
+ \r
+ return doc;\r
+ }\r
+ \r
+ /**\r
+ * @param doc\r
+ * @param xpathEx\r
+ * @return user data value on found node\r
+ * @throws XPathExpressionException\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+ public static <T> T findNodeByXpath(Document doc, String xpathEx) \r
+ throws XPathExpressionException {\r
+ T userNode = null;\r
+ XPathFactory xPathfactory = XPathFactory.newInstance();\r
+ XPath xpath = xPathfactory.newXPath();\r
+ XPathExpression expr = xpath.compile(xpathEx);\r
+ \r
+ org.w3c.dom.Node result = (org.w3c.dom.Node) expr.evaluate(doc, XPathConstants.NODE);\r
+ if (result != null) {\r
+ userNode = (T) result.getUserData(USER_KEY_NODE);\r
+ } \r
+ \r
+ return userNode;\r
+ }\r
+\r
+\r
+ /**\r
+ * build NodeMap, where key = qName; value = node\r
+ * \r
+ * @param value\r
+ * @return map of children, where key = qName and value is list of children groupped by qName \r
+ */\r
+ public static Map<QName, List<Node<?>>> buildNodeMap(List<Node<?>> value) {\r
+ Map<QName, List<Node<?>>> nodeMapTmp = new HashMap<>();\r
+ if (value == null || value.isEmpty()) {\r
+ throw new IllegalStateException(\r
+ "nodeList should not be null or empty");\r
+ }\r
+ for (Node<?> node : value) {\r
+ List<Node<?>> qList = nodeMapTmp.get(node.getNodeType());\r
+ if (qList == null) {\r
+ qList = new ArrayList<>();\r
+ nodeMapTmp.put(node.getNodeType(), qList);\r
+ }\r
+ qList.add(node);\r
+ }\r
+ return nodeMapTmp;\r
+ }\r
+\r
+\r
+ /**\r
+ * @param context\r
+ * @return map of lists, where key = path; value = {@link DataSchemaNode}\r
+ */\r
+ public static Map<String, ListSchemaNode> buildMapOfListNodes(\r
+ SchemaContext context) {\r
+ Map<String, ListSchemaNode> mapOfLists = new HashMap<>();\r
+ \r
+ Stack<DataSchemaNode> jobQueue = new Stack<>();\r
+ jobQueue.addAll(context.getDataDefinitions());\r
+ \r
+ while (!jobQueue.isEmpty()) {\r
+ DataSchemaNode dataSchema = jobQueue.pop();\r
+ if (dataSchema instanceof ListSchemaNode) {\r
+ mapOfLists.put(schemaPathToPath(dataSchema.getPath().getPath()), (ListSchemaNode) dataSchema);\r
+ }\r
+ \r
+ if (dataSchema instanceof DataNodeContainer) {\r
+ jobQueue.addAll(((DataNodeContainer) dataSchema).getChildNodes());\r
+ }\r
+ }\r
+ \r
+ return mapOfLists;\r
+ }\r
+\r
+\r
+ /**\r
+ * @param path\r
+ * @return\r
+ */\r
+ private static String schemaPathToPath(List<QName> qNamesPath) {\r
+ List<String> pathSeed = new ArrayList<>();\r
+ for (QName qNameItem : qNamesPath) {\r
+ pathSeed.add(qNameItem.getLocalName());\r
+ }\r
+ return Joiner.on(".").join(pathSeed);\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * \r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.NodeModification;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * @param <T> type of node value\r
+ * \r
+ */\r
+public class SimpleNodeModificationTOImpl<T> extends SimpleNodeTOImpl<T>\r
+ implements NodeModification {\r
+\r
+ private ModifyAction modifyAction;\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent\r
+ * @param value\r
+ * @param modifyAction \r
+ */\r
+ public SimpleNodeModificationTOImpl(QName qname, CompositeNode parent,\r
+ T value, ModifyAction modifyAction) {\r
+ super(qname, parent, value);\r
+ this.modifyAction = modifyAction;\r
+ }\r
+\r
+ /**\r
+ * @return modification action\r
+ * @see org.opendaylight.controller.yang.data.impl.NodeModificationSupport#getModificationAction()\r
+ */\r
+ @Override\r
+ public ModifyAction getModificationAction() {\r
+ return modifyAction;\r
+ }\r
+\r
+ /**\r
+ * @param modifyAction\r
+ * the modifyAction to set\r
+ */\r
+ protected void setModificationAction(ModifyAction modifyAction) {\r
+ this.modifyAction = modifyAction;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.SimpleNode;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * @param <T> type of simple node value\r
+ * \r
+ */\r
+public class SimpleNodeTOImpl<T> extends AbstractNodeTO<T> implements\r
+ SimpleNode<T> {\r
+\r
+ /**\r
+ * @param qname\r
+ * @param parent\r
+ * @param value\r
+ */\r
+ public SimpleNodeTOImpl(QName qname, CompositeNode parent, T value) {\r
+ super(qname, parent, value);\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.PrintStream;\r
+import java.net.URI;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.ModifyAction;\r
+import org.opendaylight.controller.yang.data.api.MutableCompositeNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.NodeModification;\r
+import org.w3c.dom.Document;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public class NodeFactoryTest {\r
+\r
+ /**\r
+ * Test method for methods creating immutable nodes in\r
+ * {@link org.opendaylight.controller.yang.data.impl.NodeFactory}.\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testImmutableNodes() throws Exception {\r
+ QName qName = new QName(\r
+ new URI("urn:opendaylight:controller:network"), \r
+ new Date(42), "yang-data-impl-immutableTest_", null);\r
+ \r
+ CompositeNode network = NodeHelper.buildTestConfigTree(qName);\r
+ \r
+ \r
+ Assert.assertEquals(1, network.getChildren().size());\r
+ Document domTree = NodeUtils.buildShadowDomTree(network);\r
+ NodeHelper.dumpDoc(domTree, System.out);\r
+ \r
+ CompositeNode tpList = NodeUtils.findNodeByXpath(domTree, \r
+ "//node[node-id/text()='nodeId_19']/termination-points");\r
+ \r
+ \r
+ Assert.assertEquals(2, tpList.getCompositesByName("termination-point").size());\r
+// Assert.assertEquals(1, topologies.getCompositesByName("topology").size());\r
+// Assert.assertEquals(2, destination.getChildren().size());\r
+ }\r
+\r
+ /**\r
+ * Test method for methods creating immutable nodes in\r
+ * {@link org.opendaylight.controller.yang.data.impl.NodeFactory}.\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testMutableNodes() throws Exception {\r
+ // <config>\r
+ // <top xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\r
+ // <interface xc:operation="delete">\r
+ // <name>Ethernet0/0</name>\r
+ // <mtu>1500</mtu>\r
+ // </interface>\r
+ // <interface>\r
+ // <name>Ethernet0/1</name>\r
+ // <mtu>1501</mtu>\r
+ // </interface>\r
+ // </top>\r
+ // </config>\r
+ \r
+ QName qName = new QName(\r
+ new URI("urn:ietf:params:xml:ns:netconf:base:1.0"), \r
+ new Date(42), "yang-data-impl-mutableTest");\r
+ \r
+ List<Node<?>> value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "name"), null, "Ethernet0/0"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "mtu"), null, 1500));\r
+ \r
+ CompositeNodeModificationTOImpl ifNode = NodeFactory.createCompositeNodeModification(\r
+ new QName(qName, "interface"), null, value, ModifyAction.DELETE);\r
+ NodeHelper.assignParentToChildren(ifNode);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "name"), null, "Ethernet1/0"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "mtu"), null, 1501));\r
+ \r
+ CompositeNode ifNode2 = NodeFactory.createCompositeNode(new QName(qName, "interface"), null, value);\r
+ NodeHelper.assignParentToChildren(ifNode2);\r
+\r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(ifNode);\r
+ value.add(ifNode2);\r
+ \r
+ CompositeNode topNode = NodeFactory.createCompositeNode(new QName(qName, "top"), null, value);\r
+ NodeHelper.assignParentToChildren(topNode);\r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(topNode);\r
+ \r
+ CompositeNode root = NodeFactory.createCompositeNode(new QName(qName, "config"), null, value);\r
+ \r
+ \r
+ Assert.assertEquals(1, root.getChildren().size());\r
+ Assert.assertEquals(1, ifNode.getSimpleNodesByName("name").size());\r
+ Assert.assertEquals(1, ifNode.getSimpleNodesByName("mtu").size());\r
+ Assert.assertEquals(2, topNode.getCompositesByName("interface").size());\r
+ NodeModification interfaceMod = (NodeModification) \r
+ topNode.getCompositesByName("interface").get(0);\r
+ Assert.assertEquals(ModifyAction.DELETE, interfaceMod.getModificationAction());\r
+ }\r
+\r
+ /**\r
+ * test modifications builder\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testCopyDeepNode() throws Exception {\r
+ QName qName = new QName(\r
+ new URI("urn:opendaylight:controller:network"), \r
+ new Date(42), "yang-data-impl-immutableTest_", null);\r
+ \r
+ CompositeNode network = NodeHelper.buildTestConfigTree(qName);\r
+ Map<Node<?>, Node<?>> mutableToOrig = new HashMap<>();\r
+ MutableCompositeNode mutableNetwork = NodeFactory.copyDeepNode(network, mutableToOrig );\r
+\r
+ Document networkShadow = NodeUtils.buildShadowDomTree(network);\r
+ ByteArrayOutputStream expected = new ByteArrayOutputStream();\r
+ NodeHelper.dumpDoc(networkShadow, new PrintStream(expected));\r
+ \r
+ Document mutableNetworkShadow = NodeUtils.buildShadowDomTree(mutableNetwork);\r
+ ByteArrayOutputStream actual = new ByteArrayOutputStream();\r
+ NodeHelper.dumpDoc(mutableNetworkShadow, new PrintStream(actual));\r
+ \r
+ Assert.assertEquals(new String(expected.toByteArray()), new String(actual.toByteArray()));\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+import java.io.StringWriter;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import javax.xml.transform.OutputKeys;\r
+import javax.xml.transform.Transformer;\r
+import javax.xml.transform.TransformerFactory;\r
+import javax.xml.transform.dom.DOMSource;\r
+import javax.xml.transform.stream.StreamResult;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.model.api.Module;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+import org.opendaylight.controller.yang.model.parser.api.YangModelParser;\r
+import org.opendaylight.controller.yang.parser.impl.YangParserImpl;\r
+import org.w3c.dom.Document;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ *\r
+ */\r
+public abstract class NodeHelper {\r
+ \r
+ /** xml source of example network configuration */\r
+ public static final String NETWORK_XML = \r
+ "<network xmlns=\"urn:opendaylight:controller:network\">\n" +\r
+ //"<network>\n" +\r
+ " <topologies>\n" +\r
+ " <topology>\n" +\r
+ " <topology-id>topId_01</topology-id>\n" +\r
+ " <nodes>\n" +\r
+ " <node>\n" +\r
+ " <node-id>nodeId_02</node-id>\n" +\r
+ " <supporting-ne>networkId_02</supporting-ne>\n" +\r
+ " <termination-points>\n" +\r
+ " <termination-point>\n" +\r
+ " <tp-id>tpId_03</tp-id>\n" +\r
+ " </termination-point>\n" +\r
+ " </termination-points>\n" +\r
+ " </node>\n" +\r
+ " <node>\n" +\r
+ " <node-id>nodeId_16</node-id>\n" +\r
+ " <supporting-ne>networkId_17</supporting-ne>\n" +\r
+ " <termination-points>\n" +\r
+ " <termination-point>\n" +\r
+ " <tp-id>tpId_18</tp-id>\n" +\r
+ " </termination-point>\n" +\r
+ " </termination-points>\n" +\r
+ " </node>\n" +\r
+ " <node>\n" +\r
+ " <node-id>nodeId_19</node-id>\n" +\r
+ " <supporting-ne>networkId_20</supporting-ne>\n" +\r
+ " <termination-points>\n" +\r
+ " <termination-point>\n" +\r
+ " <tp-id>tpId_18</tp-id>\n" +\r
+ " </termination-point>\n" +\r
+ " <termination-point>\n" +\r
+ " <tp-id>tpId_19</tp-id>\n" +\r
+ " </termination-point>\n" +\r
+ " </termination-points>\n" +\r
+ " </node>\n" +\r
+ " </nodes>\n" +\r
+ " <links>\n" +\r
+ " <link>\n" +\r
+ " <link-id>linkId_04</link-id>\n" +\r
+ " <source>\n" +\r
+ " <source-node>nodeId_05</source-node>\n" +\r
+ " <source-tp>tpId_06</source-tp>\n" +\r
+ " </source>\n" +\r
+ " <destination>\n" +\r
+ " <dest-node>nodeId_07</dest-node>\n" +\r
+ " <dest-tp>tpId_08</dest-tp>\n" +\r
+ " </destination>\n" +\r
+ " </link>\n" +\r
+ " <link>\n" +\r
+ " <link-id>linkId_11</link-id>\n" +\r
+ " <source>\n" +\r
+ " <source-node>nodeId_12</source-node>\n" +\r
+ " <source-tp>tpId_13</source-tp>\n" +\r
+ " </source>\n" +\r
+ " <destination>\n" +\r
+ " <dest-node>nodeId_14</dest-node>\n" +\r
+ " <dest-tp>tpId_15</dest-tp>\n" +\r
+ " </destination>\n" +\r
+ " </link>\n" +\r
+ " </links>\n" +\r
+ " </topology>\n" +\r
+ " </topologies>\n" +\r
+ " <network-elements>\n" +\r
+ " <network-element>\n" +\r
+ " <element-id>ntElementId_09</element-id>\n" +\r
+ " </network-element>\n" +\r
+ " <network-element>\n" +\r
+ " <element-id>ntElementId_10</element-id>\n" +\r
+ " </network-element>\n" +\r
+ " </network-elements>\n" +\r
+ "</network>";\r
+\r
+ /**\r
+ * @param domTree\r
+ * @param out\r
+ * @throws Exception \r
+ */\r
+ public static void dumpDoc(Document domTree, PrintStream out) throws Exception {\r
+ TransformerFactory transformerFact = TransformerFactory.newInstance();\r
+ transformerFact.setAttribute("indent-number", 4);\r
+ Transformer transformer = transformerFact.newTransformer();\r
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
+ //initialize StreamResult with File object to save to file\r
+ StreamResult result = new StreamResult(new StringWriter());\r
+ DOMSource source = new DOMSource(domTree);\r
+ transformer.transform(source, result);\r
+ String xmlString = result.getWriter().toString();\r
+ out.println(xmlString);\r
+ }\r
+\r
+ /**\r
+ * @param qName\r
+ * @return example tree, see {@link #NETWORK_XML}\r
+ */\r
+ public static CompositeNode buildTestConfigTree(QName qName) {\r
+ List<Node<?>> value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "element-id"), null, "ntElementId_09"));\r
+ CompositeNode ntElementNode1 = NodeFactory.createCompositeNode(new QName(qName, "network-element"), null, value);\r
+ assignParentToChildren(ntElementNode1);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "element-id"), null, "ntElementId_10"));\r
+ CompositeNode ntElementNode2 = NodeFactory.createCompositeNode(new QName(qName, "network-element"), null, value);\r
+ assignParentToChildren(ntElementNode2);\r
+ \r
+ value = new ArrayList<Node<?>>();\r
+ value.add(ntElementNode1);\r
+ value.add(ntElementNode2);\r
+ CompositeNode ntElementsNode = NodeFactory.createCompositeNode(\r
+ new QName(qName, "network-elements"), null, value);\r
+ assignParentToChildren(ntElementsNode);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "dest-node"), null, "nodeId_07"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "dest-tp"), null, "tpId_08"));\r
+ CompositeNode destination = NodeFactory.createCompositeNode(\r
+ new QName(qName, "destination"), null, value);\r
+ assignParentToChildren(destination);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "source-node"), null, "nodeId_05"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "source-tp"), null, "tpId_06"));\r
+ CompositeNode source = NodeFactory.createCompositeNode(\r
+ new QName(qName, "source"), null, value);\r
+ assignParentToChildren(source);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "link-id"), null, "linkId_04"));\r
+ value.add(source);\r
+ value.add(destination);\r
+ CompositeNode link1 = NodeFactory.createCompositeNode(\r
+ new QName(qName, "link"), null, value);\r
+ assignParentToChildren(link1);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "dest-node"), null, "nodeId_14"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "dest-tp"), null, "tpId_15"));\r
+ destination = NodeFactory.createCompositeNode(\r
+ new QName(qName, "destination"), null, value);\r
+ assignParentToChildren(destination);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "source-node"), null, "nodeId_12"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "source-tp"), null, "tpId_13"));\r
+ source = NodeFactory.createCompositeNode(\r
+ new QName(qName, "source"), null, value);\r
+ assignParentToChildren(source);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "link-id"), null, "linkId_11"));\r
+ value.add(source);\r
+ value.add(destination);\r
+ CompositeNode link2 = NodeFactory.createCompositeNode(\r
+ new QName(qName, "link"), null, value);\r
+ assignParentToChildren(link2);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(link1);\r
+ value.add(link2);\r
+ CompositeNode links = NodeFactory.createCompositeNode(\r
+ new QName(qName, "links"), null, value);\r
+ assignParentToChildren(links);\r
+ \r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "tp-id"), null, "tpId_03"));\r
+ CompositeNode terminationPointNode1 = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-point"), null, value);\r
+ assignParentToChildren(terminationPointNode1);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(terminationPointNode1);\r
+ CompositeNode terminationPointsNode = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-points"), null, value);\r
+ assignParentToChildren(terminationPointsNode);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "node-id"), null, "nodeId_02"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "supporting-ne"), null, "networkId_02"));\r
+ value.add(terminationPointsNode);\r
+ CompositeNode node1Node = NodeFactory.createCompositeNode(\r
+ new QName(qName, "node"), null, value);\r
+ assignParentToChildren(node1Node);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "tp-id"), null, "tpId_18"));\r
+ terminationPointNode1 = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-point"), null, value);\r
+ assignParentToChildren(terminationPointNode1);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(terminationPointNode1);\r
+ terminationPointsNode = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-points"), null, value);\r
+ assignParentToChildren(terminationPointsNode);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "node-id"), null, "nodeId_16"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "supporting-ne"), null, "networkId_17"));\r
+ value.add(terminationPointsNode);\r
+ CompositeNode node2Node = NodeFactory.createCompositeNode(\r
+ new QName(qName, "node"), null, value);\r
+ assignParentToChildren(node2Node);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "tp-id"), null, "tpId_18"));\r
+ terminationPointNode1 = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-point"), null, value);\r
+ assignParentToChildren(terminationPointNode1);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "tp-id"), null, "tpId_19"));\r
+ CompositeNode terminationPointNode2 = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-point"), null, value);\r
+ assignParentToChildren(terminationPointNode2);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(terminationPointNode1);\r
+ value.add(terminationPointNode2);\r
+ terminationPointsNode = NodeFactory.createCompositeNode(\r
+ new QName(qName, "termination-points"), null, value);\r
+ assignParentToChildren(terminationPointsNode);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "node-id"), null, "nodeId_19"));\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "supporting-ne"), null, "networkId_20"));\r
+ value.add(terminationPointsNode);\r
+ CompositeNode node3Node = NodeFactory.createCompositeNode(\r
+ new QName(qName, "node"), null, value);\r
+ assignParentToChildren(node3Node);\r
+ \r
+ value = new ArrayList<Node<?>>(); \r
+ value.add(node1Node);\r
+ value.add(node2Node);\r
+ value.add(node3Node);\r
+ CompositeNode nodesNode = NodeFactory.createCompositeNode(\r
+ new QName(qName, "nodes"), null, value);\r
+ assignParentToChildren(nodesNode);\r
+ \r
+ value = new ArrayList<Node<?>>();\r
+ value.add(links);\r
+ value.add(nodesNode);\r
+ value.add(NodeFactory.createSimpleNode(new QName(qName, "topology-id"), null, "topId_01"));\r
+ CompositeNode topology = NodeFactory.createCompositeNode(\r
+ new QName(qName, "topology"), null, value);\r
+ assignParentToChildren(topology);\r
+ \r
+ value = new ArrayList<Node<?>>();\r
+ value.add(topology);\r
+ CompositeNode topologies = NodeFactory.createCompositeNode(\r
+ new QName(qName, "topologies"), null, value);\r
+ assignParentToChildren(topologies);\r
+ \r
+ value = new ArrayList<Node<?>>();\r
+ value.add(topologies);\r
+ CompositeNode network = NodeFactory.createCompositeNode(\r
+ new QName(qName, "network"), null, value);\r
+ assignParentToChildren(network);\r
+ \r
+ return network;\r
+ }\r
+\r
+ /**\r
+ * @param parentNode\r
+ */\r
+ public static void assignParentToChildren(CompositeNode parentNode) {\r
+ for (Node<?> child : parentNode.getChildren()) {\r
+ ((AbstractNodeTO<?>) child).setParent(parentNode);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @return schema context of controller-network.yang\r
+ */\r
+ public static SchemaContext loadSchemaContext() {\r
+ YangModelParser yParser = new YangParserImpl();\r
+ List<InputStream> yangInputStreams = new ArrayList<>();\r
+ yangInputStreams.add(NodeHelper.class.getResourceAsStream(\r
+ "/controller-network.yang"));\r
+ yangInputStreams.add(NodeHelper.class.getResourceAsStream(\r
+ "/ietf-inet-types@2010-09-24.yang"));\r
+ Set<Module> modules = yParser\r
+ .parseYangModelsFromStreams(yangInputStreams);\r
+ return yParser.resolveSchemaContext(modules);\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.net.URI;\r
+import java.util.Date;\r
+\r
+import junit.framework.Assert;\r
+\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.MutableCompositeNode;\r
+import org.opendaylight.controller.yang.data.api.MutableSimpleNode;\r
+import org.opendaylight.controller.yang.data.api.SimpleNode;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+import org.w3c.dom.Document;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ * \r
+ */\r
+public class NodeModificationBuilderImplTest {\r
+\r
+ private SchemaContext schemaCtx;\r
+ private QName qName;\r
+ private CompositeNode network;\r
+ private NodeModificationBuilderImpl nodeModificationBuilder;\r
+\r
+ /**\r
+ * prepare schemaContext\r
+ * @throws Exception \r
+ */\r
+ @Before\r
+ public void setUp() throws Exception {\r
+ schemaCtx = NodeHelper.loadSchemaContext();\r
+\r
+ qName = new QName(\r
+ new URI("urn:opendaylight:controller:network"), \r
+ new Date(1369000800000L), "topos");\r
+ network = NodeHelper.buildTestConfigTree(qName);\r
+ \r
+ nodeModificationBuilder = new NodeModificationBuilderImpl(network, schemaCtx);\r
+ }\r
+\r
+ /**\r
+ * Test method for\r
+ * {@link org.opendaylight.controller.yang.data.impl.NodeModificationBuilderImpl#buildDiffTree()}\r
+ * .\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testBuildDiffTree() throws Exception {\r
+ Document networkShadow = NodeUtils.buildShadowDomTree(network);\r
+ SimpleNode<String> needle = NodeUtils.findNodeByXpath(networkShadow, \r
+ "//node[node-id='nodeId_19']//termination-point[2]/tp-id");\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ MutableSimpleNode<String> mutableNeedle = (MutableSimpleNode<String>) \r
+ nodeModificationBuilder.getMutableEquivalent(needle);\r
+ \r
+ mutableNeedle.setValue("tpId_18x");\r
+ nodeModificationBuilder.replaceNode(mutableNeedle);\r
+ CompositeNode diffTree = nodeModificationBuilder.buildDiffTree();\r
+ \r
+ Document diffShadow = NodeUtils.buildShadowDomTree(diffTree);\r
+ NodeHelper.dumpDoc(diffShadow, System.out);\r
+ }\r
+\r
+ /**\r
+ * Test method for\r
+ * {@link org.opendaylight.controller.yang.data.impl.NodeModificationBuilderImpl#getMutableEquivalent(org.opendaylight.controller.yang.data.api.Node)}\r
+ * .\r
+ */\r
+ @Test\r
+ public void testGetMutableEquivalent() {\r
+ MutableCompositeNode rootMutable = (MutableCompositeNode) \r
+ nodeModificationBuilder.getMutableEquivalent(network);\r
+ \r
+ CompositeNode topologies = network.getCompositesByName("topologies").iterator().next();\r
+ CompositeNode topologiesMutable = rootMutable.getCompositesByName("topologies").iterator().next();\r
+ \r
+ Assert.assertSame(topologiesMutable, nodeModificationBuilder.getMutableEquivalent(topologies));\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.data.impl;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.PrintStream;\r
+import java.net.URI;\r
+import java.util.Date;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
+import org.opendaylight.controller.yang.data.api.Node;\r
+import org.opendaylight.controller.yang.data.api.SimpleNode;\r
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+import org.w3c.dom.Document;\r
+\r
+/**\r
+ * @author michal.rehak\r
+ *\r
+ */\r
+public class NodeUtilsTest {\r
+ \r
+ private QName qName;\r
+ private CompositeNode network;\r
+\r
+ /**\r
+ * @throws Exception\r
+ */\r
+ @Before\r
+ public void setUp() throws Exception {\r
+ qName = new QName(\r
+ new URI("urn:ietf:params:xml:ns:netconf:base:1.0"), \r
+ new Date(42), "yang-data-impl-mutableTest");\r
+ network = NodeHelper.buildTestConfigTree(qName);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link org.opendaylight.controller.yang.data.impl.NodeUtils#buildPath(org.opendaylight.controller.yang.data.api.Node)}.\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testBuildPath() throws Exception {\r
+ SimpleNode<?> needle = network.getCompositesByName("topologies").iterator().next()\r
+ .getCompositesByName("topology").iterator().next()\r
+ .getSimpleNodesByName("topology-id").iterator().next();\r
+ String breadCrumbs = NodeUtils.buildPath(needle);\r
+ \r
+ Assert.assertEquals("network.topologies.topology.topology-id", breadCrumbs);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link org.opendaylight.controller.yang.data.impl.NodeUtils#buildShadowDomTree(org.opendaylight.controller.yang.data.api.CompositeNode)}.\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testBuildShadowDomTree() throws Exception {\r
+ Document networkShadow = NodeUtils.buildShadowDomTree(network);\r
+ ByteArrayOutputStream actual = new ByteArrayOutputStream();\r
+ NodeHelper.dumpDoc(networkShadow, new PrintStream(actual));\r
+ \r
+ Assert.assertEquals(2760, new String(actual.toByteArray()).length());\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link org.opendaylight.controller.yang.data.impl.NodeUtils#findNodeByXpath(org.w3c.dom.Document, java.lang.String)}.\r
+ * @throws Exception \r
+ */\r
+ @Test\r
+ public void testFindNodeByXpath() throws Exception {\r
+ Document networkShadow = NodeUtils.buildShadowDomTree(network);\r
+ SimpleNode<String> needle = NodeUtils.findNodeByXpath(networkShadow, \r
+ "//node[node-id='nodeId_19']//termination-point[2]/tp-id");\r
+ Assert.assertNotNull(needle);\r
+ Assert.assertEquals("tpId_18", needle.getValue());\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link org.opendaylight.controller.yang.data.impl.NodeUtils#buildNodeMap(java.util.List)}.\r
+ */\r
+ @Test\r
+ public void testBuildNodeMap() {\r
+ CompositeNode topology = network.getCompositesByName("topologies").iterator().next()\r
+ .getCompositesByName("topology").iterator().next();\r
+ \r
+ Map<QName, List<Node<?>>> nodeMap = NodeUtils.buildNodeMap(topology.getChildren());\r
+ Assert.assertEquals(3, nodeMap.size());\r
+ }\r
+ \r
+ /**\r
+ * Test method for {@link org.opendaylight.controller.yang.data.impl.NodeUtils#buildMapOfListNodes(org.opendaylight.controller.yang.model.api.SchemaContext)}.\r
+ */\r
+ @Test\r
+ public void testBuildMapOfListNodes() {\r
+ SchemaContext schemaCtx = NodeHelper.loadSchemaContext();\r
+ Map<String, ListSchemaNode> mapOfLists = NodeUtils.buildMapOfListNodes(schemaCtx);\r
+ Assert.assertEquals(5, mapOfLists.size());\r
+ }\r
+\r
+}\r
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>\r
+<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\r
+ <edit-config>\r
+ <target>\r
+ <running />\r
+ </target>\r
+ <config>\r
+ <top xmlns="http://example.com/schema/1.2/config">\r
+ <interface>\r
+ <name>Ethernet0/0</name>\r
+ <mtu>1500</mtu>\r
+ </interface>\r
+ </top>\r
+ </config>\r
+ </edit-config>\r
+</rpc>\r
+
\ No newline at end of file
--- /dev/null
+xmlDoc.network(xmlns: 'urn:opendaylight:controller:network') {\r
+ topologies {\r
+ topology {\r
+ 'topology-id'('topId_'+cnt.get())\r
+ \r
+ types()\r
+ nodes {\r
+ node {\r
+ 'node-id'('nodeId_'+cnt.get())\r
+ 'supporting-ne'('networkId_'+cnt.get())\r
+ 'termination-points' {\r
+ 'termination-point' {\r
+ 'tp-id'('tpId_'+cnt.get())\r
+ }\r
+ }\r
+ }\r
+ node {\r
+ 'node-id'('nodeId_'+cnt.get())\r
+ 'supporting-ne'('networkId_'+cnt.get())\r
+ 'termination-points' {\r
+ 'termination-point' {\r
+ 'tp-id'('tpId_'+cnt.get())\r
+ }\r
+ }\r
+ }\r
+ node {\r
+ 'node-id'('nodeId_'+cnt.get())\r
+ 'supporting-ne'('networkId_'+cnt.get())\r
+ 'termination-points' {\r
+ 'termination-point' {\r
+ 'tp-id'('tpId_'+cnt.get())\r
+ }\r
+ 'termination-point' {\r
+ 'tp-id'('tpId_'+cnt.get())\r
+ }\r
+ }\r
+ }\r
+ }\r
+ links {\r
+ link {\r
+ 'link-id'('linkId_'+cnt.get())\r
+ source {\r
+ 'source-node'('nodeId_'+cnt.get())\r
+ 'source-tp'('tpId_'+cnt.get(false))\r
+ }\r
+ destination {\r
+ 'dest-node'('nodeId_'+cnt.get())\r
+ 'dest-tp'('tpId_'+cnt.get(false))\r
+ }\r
+ }\r
+ link {\r
+ 'link-id'('linkId_'+cnt.get())\r
+ source {\r
+ 'source-node'('nodeId_'+cnt.get())\r
+ 'source-tp'('tpId_'+cnt.get(false))\r
+ }\r
+ destination {\r
+ 'dest-node'('nodeId_'+cnt.get())\r
+ 'dest-tp'('tpId_'+cnt.get(false))\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ 'network-elements' {\r
+ 'network-element' {\r
+ 'element-id'('ntElementId_'+cnt.get())\r
+ }\r
+ 'network-element' {\r
+ 'element-id'('ntElementId_'+cnt.get())\r
+ }\r
+ }\r
+ }
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<network xmlns="urn:opendaylight:controller:network">\r
+ <topologies>\r
+ <topology>\r
+ <topology-id>topId_01</topology-id>\r
+ <types></types>\r
+ <nodes>\r
+ <node>\r
+ <node-id>nodeId_02</node-id>\r
+ <supporting-ne>networkId_02</supporting-ne>\r
+ <termination-points>\r
+ <termination-point>\r
+ <tp-id>tpId_03</tp-id>\r
+ </termination-point>\r
+ </termination-points>\r
+ </node>\r
+ <node>\r
+ <node-id>nodeId_16</node-id>\r
+ <supporting-ne>networkId_17</supporting-ne>\r
+ <termination-points>\r
+ <termination-point>\r
+ <tp-id>tpId_18</tp-id>\r
+ </termination-point>\r
+ </termination-points>\r
+ </node>\r
+ <node>\r
+ <node-id>nodeId_19</node-id>\r
+ <supporting-ne>networkId_20</supporting-ne>\r
+ <termination-points>\r
+ <termination-point>\r
+ <tp-id>tpId_18</tp-id>\r
+ </termination-point>\r
+ <termination-point>\r
+ <tp-id>tpId_19</tp-id>\r
+ </termination-point>\r
+ </termination-points>\r
+ </node>\r
+ </nodes>\r
+ <links>\r
+ <link>\r
+ <link-id>linkId_04</link-id>\r
+ <source>\r
+ <source-node>nodeId_05</source-node>\r
+ <source-tp>tpId_06</source-tp>\r
+ </source>\r
+ <destination>\r
+ <dest-node>nodeId_07</dest-node>\r
+ <dest-tp>tpId_08</dest-tp>\r
+ </destination>\r
+ </link>\r
+ <link>\r
+ <link-id>linkId_11</link-id>\r
+ <source>\r
+ <source-node>nodeId_12</source-node>\r
+ <source-tp>tpId_13</source-tp>\r
+ </source>\r
+ <destination>\r
+ <dest-node>nodeId_14</dest-node>\r
+ <dest-tp>tpId_15</dest-tp>\r
+ </destination>\r
+ </link>\r
+ </links>\r
+ </topology>\r
+ </topologies>\r
+ <network-elements>\r
+ <network-element>\r
+ <element-id>ntElementId_09</element-id>\r
+ </network-element>\r
+ <network-element>\r
+ <element-id>ntElementId_10</element-id>\r
+ </network-element>\r
+ </network-elements>\r
+</network>\r
+\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<network xmlns="urn:opendaylight:controller:network">
+ <topologies>
+ <topology>
+ <topology-id>topId_01</topology-id>
+ <types />
+ <nodes>
+ <node>
+ <node-id>nodeId_02</node-id>
+ <supporting-ne>networkId_03</supporting-ne>
+ <termination-points>
+ <termination-point>
+ <tp-id>tpId_04</tp-id>
+ </termination-point>
+ </termination-points>
+ </node>
+ <node>
+ <node-id>nodeId_05</node-id>
+ <supporting-ne>networkId_06</supporting-ne>
+ <termination-points>
+ <termination-point>
+ <tp-id>tpId_07</tp-id>
+ </termination-point>
+ </termination-points>
+ </node>
+ <node>
+ <node-id>nodeId_08</node-id>
+ <supporting-ne>networkId_09</supporting-ne>
+ <termination-points>
+ <termination-point>
+ <tp-id>tpId_10</tp-id>
+ </termination-point>
+ <termination-point>
+ <tp-id>tpId_11</tp-id>
+ </termination-point>
+ </termination-points>
+ </node>
+ </nodes>
+ <links>
+ <link>
+ <link-id>linkId_12</link-id>
+ <source>
+ <source-node>nodeId_13</source-node>
+ <source-tp>tpId_13</source-tp>
+ </source>
+ <destination>
+ <dest-node>nodeId_14</dest-node>
+ <dest-tp>tpId_14</dest-tp>
+ </destination>
+ </link>
+ <link>
+ <link-id>linkId_15</link-id>
+ <source>
+ <source-node>nodeId_16</source-node>
+ <source-tp>tpId_16</source-tp>
+ </source>
+ <destination>
+ <dest-node>nodeId_17</dest-node>
+ <dest-tp>tpId_17</dest-tp>
+ </destination>
+ </link>
+ </links>
+ </topology>
+ </topologies>
+ <network-elements>
+ <network-element>
+ <element-id>ntElementId_18</element-id>
+ </network-element>
+ <network-element>
+ <element-id>ntElementId_19</element-id>
+ </network-element>
+ </network-elements>
+</network>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:yin="urn:ietf:params:xml:schema:yang:yin:1"
+ targetNamespace="urn:opendaylight:controller:network"
+ xmlns="urn:opendaylight:controller:network"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="2013-05-20"
+ xml:lang="en"
+ xmlns:topos="urn:opendaylight:controller:network"
+ xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types">
+
+ <xs:import namespace="urn:ietf:params:xml:ns:yang:ietf-inet-types"
+ schemaLocation="ietf-inet-types@2010-09-24.xsd"/>
+
+ <xs:annotation>
+ <xs:documentation>
+ This schema was generated from the YANG module controller-network
+ by pyang version 1.2.
+
+ The schema describes an instance document consisting
+ of the entire configuration data store, operational
+ data, rpc operations, and notifications.
+ This schema can thus NOT be used as-is to
+ validate NETCONF PDUs.
+ </xs:documentation>
+ </xs:annotation>
+
+
+ <!-- YANG typedefs -->
+ <xs:simpleType name="topology-id">
+ <xs:restriction base="xs:string">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="node-id">
+ <xs:restriction base="xs:string">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="link-id">
+ <xs:restriction base="xs:string">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="tp-id">
+ <xs:annotation>
+ <xs:documentation>
+ identifier for termination points on a port
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="tp-ref">
+ <xs:restriction base="tp-id">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="topology-ref">
+ <xs:annotation>
+ <xs:documentation>
+ This type is used for leafs that reference topology identifier instance.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="topology-id">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="node-ref">
+ <xs:annotation>
+ <xs:documentation>
+ This type is used for leafs that reference a node instance.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="node-id">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="link-ref">
+ <xs:annotation>
+ <xs:documentation>
+ This type is used for leafs that reference a link instance.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="link-id">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="network-element-ref">
+ <xs:restriction base="element-id">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="element-id">
+ <xs:restriction base="xs:string">
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="network">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="topologies" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="topology" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+
+ This is the model of abstract topology which contains only Network
+ Nodes and Network Links. Each topology MUST be identified by
+ unique topology-id for reason that the store could contain many
+ topologies.
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="topology-id" type="topology-id">
+ <xs:annotation>
+ <xs:documentation>
+
+ It is presumed that datastore will contain many topologies. To
+ distinguish between topologies it is vital to have UNIQUE
+ topology identifier.
+
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="types" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+
+ The container for definition of topology types.
+ The augmenting modules should add empty optional leaf
+ to this container to signalize topology type.
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="nodes" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="node" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+ The list of network nodes defined for topology.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="node-id" type="node-id">
+ <xs:annotation>
+ <xs:documentation>
+ The Topology identifier of network-node.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="supporting-ne" minOccurs="0" type="network-element-ref">
+ </xs:element>
+ <xs:element name="termination-points" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="termination-point" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="tp-id" type="tp-id">
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:key name="key_termination-points_node_nodes_topology_topologies_network_termination-point">
+ <xs:selector xpath="topos:termination-point"/>
+ <xs:field xpath="topos:tp-id"/>
+ </xs:key>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:key name="key_nodes_topology_topologies_network_node">
+ <xs:selector xpath="topos:node"/>
+ <xs:field xpath="topos:node-id"/>
+ </xs:key>
+ </xs:element>
+ <xs:element name="links" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="link" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+
+ The Network Link which is defined by Local (Source) and
+ Remote (Destination) Network Nodes. Every link MUST be
+ defined either by identifier and his local and remote
+ Network Nodes (in real applications it is common that many
+ links are originated from one node and end up in same
+ remote node). To ensure that we would always know to
+ distinguish between links, every link SHOULD have
+ identifier.
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="link-id" type="link-id">
+ </xs:element>
+ <xs:element name="source" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="source-node" minOccurs="0" type="node-ref">
+ <xs:annotation>
+ <xs:documentation>
+ Source node identifier.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="source-tp" minOccurs="0" type="tp-ref">
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="destination" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="dest-node" minOccurs="0" type="node-ref">
+ <xs:annotation>
+ <xs:documentation>
+ Destination node identifier.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="dest-tp" minOccurs="0" type="tp-ref">
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:key name="key_links_topology_topologies_network_link">
+ <xs:selector xpath="topos:link"/>
+ <xs:field xpath="topos:link-id"/>
+ </xs:key>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:key name="key_topologies_network_topology">
+ <xs:selector xpath="topos:topology"/>
+ <xs:field xpath="topos:topology-id"/>
+ </xs:key>
+ </xs:element>
+ <xs:element name="network-elements" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="network-element" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="element-id" type="element-id">
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:key name="key_network-elements_network_network-element">
+ <xs:selector xpath="topos:network-element"/>
+ <xs:field xpath="topos:element-id"/>
+ </xs:key>
+ </xs:element>
+ <xs:any minOccurs="0" maxOccurs="unbounded"
+ namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+</xs:schema>
--- /dev/null
+module controller-network {
+ yang-version 1;
+ namespace "urn:opendaylight:controller:network";
+ prefix "topos";
+
+ import ietf-inet-types { prefix "inet"; }
+
+ revision 2013-05-20 {
+ description "Initial demo";
+ }
+
+
+
+
+ typedef topology-id {
+ type string;
+ }
+
+ typedef node-id {
+ type string;
+ }
+
+ typedef link-id {
+ type string;
+ }
+
+ typedef tp-id {
+ type string;
+ description "identifier for termination points on a port";
+ }
+
+ typedef tp-ref {
+ type leafref {
+ path "/network/topologies/topology/nodes/node/termination-points/termination-point/tp-id";
+ }
+ }
+ typedef topology-ref {
+ type leafref {
+ path "/network/topologies/topology/topology-id";
+ }
+ description "This type is used for leafs that reference topology identifier instance.";
+ // currently not used
+ }
+
+ typedef node-ref {
+ type leafref {
+ path "/network/topologies/topology/nodes/node/node-id";
+ }
+ description "This type is used for leafs that reference a node instance.";
+ }
+
+ typedef link-ref {
+ type leafref {
+ path "/network/topologies/topology/links/link/link-id";
+ }
+ description "This type is used for leafs that reference a link instance.";
+ // currently not used
+ }
+
+ typedef network-element-ref {
+ type leafref {
+ path "/network/network-elements/network-element/element-id";
+ }
+ }
+
+
+ typedef element-id {
+ type string;
+ }
+
+ container network {
+ container topologies {
+ list topology {
+ description "
+ This is the model of abstract topology which contains only Network
+ Nodes and Network Links. Each topology MUST be identified by
+ unique topology-id for reason that the store could contain many
+ topologies.
+ ";
+ key "topology-id";
+ leaf topology-id {
+ type topology-id;
+ description "
+ It is presumed that datastore will contain many topologies. To
+ distinguish between topologies it is vital to have UNIQUE
+ topology identifier.
+ ";
+ }
+
+ container types {
+ description "
+ The container for definition of topology types.
+ The augmenting modules should add empty optional leaf
+ to this container to signalize topology type.
+ ";
+ }
+
+ container nodes {
+ list node {
+ description "The list of network nodes defined for topology.";
+
+ key "node-id";
+ leaf node-id {
+ type node-id;
+ description "The Topology identifier of network-node.";
+ }
+
+ leaf supporting-ne {
+ type network-element-ref;
+ }
+
+ container termination-points {
+ list termination-point {
+ key "tp-id";
+ leaf tp-id {
+ type tp-id;
+ }
+ }
+ }
+ }
+ }
+
+ container links {
+ list link {
+ description "
+ The Network Link which is defined by Local (Source) and
+ Remote (Destination) Network Nodes. Every link MUST be
+ defined either by identifier and his local and remote
+ Network Nodes (in real applications it is common that many
+ links are originated from one node and end up in same
+ remote node). To ensure that we would always know to
+ distinguish between links, every link SHOULD have
+ identifier.
+ ";
+ key "link-id";
+
+ leaf link-id {
+ type link-id;
+ }
+ container source {
+ leaf source-node {
+ type node-ref;
+ description "Source node identifier.";
+ }
+ leaf source-tp {
+ type tp-ref;
+ }
+ }
+ container destination {
+ leaf dest-node {
+ type node-ref;
+ description "Destination node identifier.";
+ }
+ leaf dest-tp {
+ type tp-ref;
+ }
+ }
+ }
+ }
+ }
+ }
+ container network-elements {
+ config true;
+ list network-element {
+ key "element-id";
+ leaf element-id {
+ type element-id;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+//import groovy.xml.StreamingMarkupBuilder
+import groovy.xml.MarkupBuilder
+import groovy.xml.XmlUtil
+
+class Counter {
+ def counter = 0
+ def get() {
+ return get(true)
+ }
+ def get(isInc) {
+ if (isInc) {
+ counter++
+ }
+ return String.format('%02d', counter)
+ }
+}
+
+
+cnt = new Counter()
+def writer = new StringWriter()
+xmlDoc = new MarkupBuilder(writer)
+xmlDoc.setDoubleQuotes(true)
+xmlDoc.getMkp().xmlDeclaration(version:'1.0', encoding: 'UTF-8')
+
+//def data = {
+// mkp.xmlDeclaration()
+// network(xmlns: 'urn:opendaylight:controller:network') {
+dataFile = new File(args[0])
+evaluate(dataFile)
+// xmlDoc.network(xmlns: 'urn:opendaylight:controller:network') {
+ // topologies {
+ // topology {
+ // 'topology-id'('topId_'+cnt.get())
+ // types()
+ // nodes {
+ // node {
+ // 'node-id'('nodeId_'+cnt.get())
+ // 'supporting-ne'('networkId_'+cnt.get())
+ // 'termination-points' {
+ // 'termination-point' {
+ // 'tp-id'('tpId_'+cnt.get())
+ // }
+ // }
+ // }
+ // node {
+ // 'node-id'('nodeId_'+cnt.get())
+ // 'supporting-ne'('networkId_'+cnt.get())
+ // 'termination-points' {
+ // 'termination-point' {
+ // 'tp-id'('tpId_'+cnt.get())
+ // }
+ // }
+ // }
+ // node {
+ // 'node-id'('nodeId_'+cnt.get())
+ // 'supporting-ne'('networkId_'+cnt.get())
+ // 'termination-points' {
+ // 'termination-point' {
+ // 'tp-id'('tpId_'+cnt.get())
+ // }
+ // 'termination-point' {
+ // 'tp-id'('tpId_'+cnt.get())
+ // }
+ // }
+ // }
+ // }
+ // links {
+ // link {
+ // 'link-id'('linkId_'+cnt.get())
+ // source {
+ // 'source-node'('nodeId_'+cnt.get())
+ // 'source-tp'('tpId_'+cnt.get(false))
+ // }
+ // destination {
+ // 'dest-node'('nodeId_'+cnt.get())
+ // 'dest-tp'('tpId_'+cnt.get(false))
+ // }
+ // }
+ // link {
+ // 'link-id'('linkId_'+cnt.get())
+ // source {
+ // 'source-node'('nodeId_'+cnt.get())
+ // 'source-tp'('tpId_'+cnt.get(false))
+ // }
+ // destination {
+ // 'dest-node'('nodeId_'+cnt.get())
+ // 'dest-tp'('tpId_'+cnt.get(false))
+ // }
+ // }
+ // }
+ // }
+ // }
+ // 'network-elements' {
+ // 'network-element' {
+ // 'element-id'('ntElementId_'+cnt.get())
+ // }
+ // 'network-element' {
+ // 'element-id'('ntElementId_'+cnt.get())
+ // }
+ // }
+ // }
+
+//}
+
+
+// def xmlDoc = new StreamingMarkupBuilder()
+// xmlDoc.encoding = 'UTF'
+//println XmlUtil.serialize(xmlDoc.bind(data))
+
+println writer
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:yin="urn:ietf:params:xml:schema:yang:yin:1"
+ targetNamespace="urn:ietf:params:xml:ns:yang:ietf-inet-types"
+ xmlns="urn:ietf:params:xml:ns:yang:ietf-inet-types"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="2010-09-24"
+ xml:lang="en"
+ xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types">
+
+ <xs:annotation>
+ <xs:documentation>
+ This schema was generated from the YANG module ietf-inet-types
+ by pyang version 1.2.
+
+ The schema describes an instance document consisting
+ of the entire configuration data store, operational
+ data, rpc operations, and notifications.
+ This schema can thus NOT be used as-is to
+ validate NETCONF PDUs.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>
+ This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.
+ </xs:documentation>
+ </xs:annotation>
+
+ <!-- YANG typedefs -->
+ <xs:simpleType name="ip-version">
+ <xs:annotation>
+ <xs:documentation>
+ This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="unknown"/>
+ <xs:enumeration value="ipv4"/>
+ <xs:enumeration value="ipv6"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="dscp">
+ <xs:annotation>
+ <xs:documentation>
+ The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:unsignedByte">
+ <xs:minInclusive value="0"/>
+ <xs:maxInclusive value="63"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ipv6-flow-label">
+ <xs:annotation>
+ <xs:documentation>
+ The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:unsignedInt">
+ <xs:minInclusive value="0"/>
+ <xs:maxInclusive value="1048575"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="port-number">
+ <xs:annotation>
+ <xs:documentation>
+ The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:unsignedShort">
+ <xs:minInclusive value="0"/>
+ <xs:maxInclusive value="65535"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="as-number">
+ <xs:annotation>
+ <xs:documentation>
+ The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:unsignedInt">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ip-address">
+ <xs:annotation>
+ <xs:documentation>
+ The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="ipv4-address">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="ipv6-address">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ <xs:simpleType name="ipv4-address">
+ <xs:annotation>
+ <xs:documentation>
+ The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ <xs:pattern value="(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(%[\p{N}\p{L}]+)?"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ipv6-address">
+ <xs:annotation>
+ <xs:documentation>
+ The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ <xs:pattern value="(((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(%[\p{N}\p{L}]+)?)|((([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(%.+)?)"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ip-prefix">
+ <xs:annotation>
+ <xs:documentation>
+ The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="ipv4-prefix">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="ipv6-prefix">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ <xs:simpleType name="ipv4-prefix">
+ <xs:annotation>
+ <xs:documentation>
+ The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ <xs:pattern value="(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/(([0-9])|([1-2][0-9])|(3[0-2]))"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ipv6-prefix">
+ <xs:annotation>
+ <xs:documentation>
+ The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ <xs:pattern value="(((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8]))))|((([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(/.+))"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="domain-name">
+ <xs:annotation>
+ <xs:documentation>
+ The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="t0">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="253"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="host">
+ <xs:annotation>
+ <xs:documentation>
+ The host type represents either an IP address or a DNS
+ domain name.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="ip-address">
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="domain-name">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ <xs:simpleType name="uri">
+ <xs:annotation>
+ <xs:documentation>
+ The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:restriction base="xs:string">
+ </xs:restriction>
+ </xs:simpleType>
+
+
+ <!-- locally generated simpleType helpers -->
+
+ <xs:simpleType name="t0">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)|\."/>
+ </xs:restriction>
+ </xs:simpleType>
+
+</xs:schema>
--- /dev/null
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }