<build>
<plugins>
+ <plugin>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <version>4.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>antlr4</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <sourceDirectory>src/main/antlr</sourceDirectory>
+ <outputDirectory>target/generated-sources/parser/org/opendaylight/yangtools/yang/data/impl/leafref</outputDirectory>
+ <visitor>true</visitor>
+ <listener>true</listener>
+ </configuration>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</configuration>
</plugin>
</plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <versionRange>[4.0,)</versionRange>
+ <goals>
+ <goal>antlr4</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
</build>
<dependencies>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-runtime</artifactId>
+ <version>4.0</version>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+lexer grammar LeafRefPathLexer;\r
+\r
+@header {\r
+package org.opendaylight.yangtools.yang.data.impl.leafref;\r
+}\r
+\r
+COLON : ':' ;\r
+SLASH : '/' ;\r
+DOTS : '..' ;\r
+EQUAL : '=' ;\r
+LEFT_SQUARE_BRACKET : '[' ;\r
+RIGHT_SQUARE_BRACKET : ']' ;\r
+LEFT_PARENTHESIS : '(' ;\r
+RIGHT_PARENTHESIS : ')' ;\r
+\r
+CURRENT_KEYWORD : 'current';\r
+\r
+SEP: [ \n\r\t]+ ;\r
+IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_\-.]*;\r
+\r
--- /dev/null
+parser grammar LeafRefPathParser;\r
+\r
+@header {\r
+package org.opendaylight.yangtools.yang.data.impl.leafref;\r
+}\r
+\r
+options{\r
+ tokenVocab = LeafRefPathLexer;\r
+}\r
+\r
+path_arg : absolute_path | relative_path;\r
+\r
+absolute_path : (SLASH node_identifier (path_predicate)*)+; \r
+\r
+relative_path : (DOTS SLASH)* descendant_path;\r
+\r
+descendant_path : node_identifier ((path_predicate)* absolute_path)?;\r
+\r
+path_predicate : LEFT_SQUARE_BRACKET SEP? path_equality_expr SEP? RIGHT_SQUARE_BRACKET;\r
+\r
+path_equality_expr : node_identifier SEP? EQUAL SEP? path_key_expr;\r
+\r
+path_key_expr : current_function_invocation SEP? SLASH SEP? rel_path_keyexpr;\r
+\r
+rel_path_keyexpr : (DOTS SEP? SLASH SEP?)* (node_identifier SEP? SLASH SEP?)* node_identifier;\r
+\r
+node_identifier : (prefix COLON)? identifier;\r
+\r
+current_function_invocation : CURRENT_KEYWORD SEP? LEFT_PARENTHESIS SEP? RIGHT_PARENTHESIS;\r
+\r
+descendant_schema_nodeid : node_identifier\r
+ absolute_schema_nodeid;\r
+\r
+absolute_schema_nodeid : (SLASH node_identifier)+;\r
+\r
+prefix : identifier;\r
+\r
+identifier: IDENTIFIER | CURRENT_KEYWORD;\r
+\r
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+final public class LeafRefContext {
+
+ private final QName currentNodeQName;
+ private final SchemaPath currentNodePath;
+ private final SchemaContext schemaContext;
+ private final Module module;
+
+ private final LeafRefPath leafRefTargetPath;
+ private final LeafRefPath absoluteLeafRefTargetPath ;
+ private final String leafRefTargetPathString;
+
+ private final boolean isReferencedBy;
+ private final boolean isReferencing;
+
+ private final Map<QName, LeafRefContext> referencingChilds;
+ private final Map<QName, LeafRefContext> referencedByChilds;
+ private final Map<QName, LeafRefContext> referencedByLeafRefCtx;
+
+ LeafRefContext(final LeafRefContextBuilder leafRefContextBuilder) {
+ this.currentNodeQName = leafRefContextBuilder.getCurrentNodeQName();
+ this.currentNodePath = leafRefContextBuilder.getCurrentNodePath();
+ this.schemaContext = leafRefContextBuilder.getSchemaContext();
+ this.leafRefTargetPath = leafRefContextBuilder.getLeafRefTargetPath();
+ this.absoluteLeafRefTargetPath = leafRefContextBuilder
+ .getAbsoluteLeafRefTargetPath();
+ this.leafRefTargetPathString = leafRefContextBuilder
+ .getLeafRefTargetPathString();
+ this.isReferencedBy = leafRefContextBuilder.isReferencedBy();
+ this.isReferencing = leafRefContextBuilder.isReferencing();
+ this.referencingChilds = ImmutableMap.copyOf(leafRefContextBuilder.getReferencingChilds());
+ this.referencedByChilds = ImmutableMap.copyOf(leafRefContextBuilder.getReferencedByChilds());
+ this.referencedByLeafRefCtx = ImmutableMap.copyOf(leafRefContextBuilder
+ .getAllReferencedByLeafRefCtxs());
+ this.module = leafRefContextBuilder.getLeafRefContextModule();
+ }
+
+ public static final LeafRefContext create(final SchemaContext ctx) {
+ try {
+ return new LeafRefContextTreeBuilder(ctx).buildLeafRefContextTree();
+ } catch (IOException | LeafRefYangSyntaxErrorException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean hasLeafRefContextChild() {
+ return hasReferencedChild() || hasReferencingChild();
+ }
+
+ public boolean hasReferencedChild() {
+ return !referencedByChilds.isEmpty();
+ }
+
+ public boolean hasReferencingChild() {
+ return !referencingChilds.isEmpty();
+ }
+
+ public boolean isReferenced() {
+ return isReferencedBy;
+ }
+
+ public boolean isReferencing() {
+ return isReferencing;
+ }
+
+ public LeafRefContext getReferencingChildByName(final QName name) {
+ return referencingChilds.get(name);
+ }
+
+ public Map<QName, LeafRefContext> getReferencingChilds() {
+ return referencingChilds;
+ }
+
+ public LeafRefContext getReferencedChildByName(final QName name) {
+ return referencedByChilds.get(name);
+ }
+
+ public Map<QName, LeafRefContext> getReferencedByChilds() {
+ return referencedByChilds;
+ }
+
+ public SchemaPath getCurrentNodePath() {
+ return currentNodePath;
+ }
+
+ public LeafRefPath getLeafRefTargetPath() {
+ return leafRefTargetPath;
+ }
+
+ public String getLeafRefTargetPathString() {
+ return leafRefTargetPathString;
+ }
+
+ public QName getNodeName() {
+ return currentNodeQName;
+ }
+
+ SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ public LeafRefPath getAbsoluteLeafRefTargetPath() {
+ return absoluteLeafRefTargetPath;
+ }
+
+ public Module getLeafRefContextModule() {
+ return module;
+ }
+
+ public LeafRefContext getReferencedByLeafRefCtxByName(final QName qname) {
+ return referencedByLeafRefCtx.get(qname);
+ }
+
+ public Map<QName, LeafRefContext> getAllReferencedByLeafRefCtxs() {
+ return referencedByLeafRefCtx;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+class LeafRefContextBuilder {
+
+ private QName currentNodeQName;
+ private SchemaPath currentNodePath;
+ private SchemaContext schemaContext;
+
+ private LeafRefPath leafRefTargetPath = null;
+ private LeafRefPath absoluteLeafRefTargetPath = null;
+ private String leafRefTargetPathString = "";
+
+ private boolean isReferencedBy = false;
+ private boolean isReferencing = false;
+
+ private Map<QName, LeafRefContext> referencingChilds = new HashMap<QName, LeafRefContext>();
+ private Map<QName, LeafRefContext> referencedByChilds = new HashMap<QName, LeafRefContext>();
+ private Map<QName, LeafRefContext> referencedByLeafRefCtx = new HashMap<QName, LeafRefContext>();
+
+ public LeafRefContextBuilder(final QName currentNodeQName,
+ final SchemaPath currentNodePath, final SchemaContext schemaContext) {
+ this.currentNodeQName = currentNodeQName;
+ this.currentNodePath = currentNodePath;
+ this.schemaContext = schemaContext;
+ }
+
+ public LeafRefContext build() {
+ final LeafRefContext leafRefContext = new LeafRefContext(this);
+
+ referencingChilds = new HashMap<QName, LeafRefContext>();
+ referencedByChilds = new HashMap<QName, LeafRefContext>();
+ referencedByLeafRefCtx = new HashMap<QName, LeafRefContext>();
+
+ return leafRefContext;
+ }
+
+ public boolean hasLeafRefContextChild() {
+ return hasReferencedByChild() || hasReferencingChild();
+ }
+
+ public boolean hasReferencedByChild() {
+ return !referencedByChilds.isEmpty();
+ }
+
+ public boolean hasReferencingChild() {
+ return !referencingChilds.isEmpty();
+ }
+
+ public boolean isReferencedBy() {
+ return isReferencedBy;
+ }
+
+ public void setReferencedBy(final boolean isReferencedBy) {
+ this.isReferencedBy = isReferencedBy;
+ }
+
+ public boolean isReferencing() {
+ return isReferencing;
+ }
+
+ public void setReferencing(final boolean isReferencing) {
+ this.isReferencing = isReferencing;
+ }
+
+ public void addReferencingChild(final LeafRefContext child, final QName childQName) {
+ referencingChilds.put(childQName, child);
+ }
+
+ public LeafRefContext getReferencingChildByName(final QName name) {
+ return referencingChilds.get(name);
+ }
+
+ public Map<QName, LeafRefContext> getReferencingChilds() {
+ return referencingChilds;
+ }
+
+ public void addReferencedByChild(final LeafRefContext child, final QName childQName) {
+ referencedByChilds.put(childQName, child);
+ }
+
+ public LeafRefContext getReferencedByChildByName(final QName name) {
+ return referencedByChilds.get(name);
+ }
+
+ public Map<QName, LeafRefContext> getReferencedByChilds() {
+ return referencedByChilds;
+ }
+
+ public SchemaPath getCurrentNodePath() {
+ return currentNodePath;
+ }
+
+ public void setCurrentNodePath(final SchemaPath currentNodePath) {
+ this.currentNodePath = currentNodePath;
+ }
+
+ public LeafRefPath getLeafRefTargetPath() {
+ return leafRefTargetPath;
+ }
+
+ public void setLeafRefTargetPath(final LeafRefPath leafRefPath) {
+ this.leafRefTargetPath = leafRefPath;
+ }
+
+ public String getLeafRefTargetPathString() {
+ return leafRefTargetPathString;
+ }
+
+ public void setLeafRefTargetPathString(final String leafRefPathString) {
+ this.leafRefTargetPathString = leafRefPathString;
+ }
+
+ public QName getCurrentNodeQName() {
+ return currentNodeQName;
+ }
+
+ public void setCurrentNodeQName(final QName currentNodeQName) {
+ this.currentNodeQName = currentNodeQName;
+ }
+
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ public void setSchemaContext(final SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ }
+
+ public LeafRefPath getAbsoluteLeafRefTargetPath() {
+
+ if (isReferencing && absoluteLeafRefTargetPath == null) {
+ if (leafRefTargetPath.isAbsolute()) {
+ absoluteLeafRefTargetPath = leafRefTargetPath;
+ } else {
+ absoluteLeafRefTargetPath = LeafRefUtils
+ .createAbsoluteLeafRefPath(leafRefTargetPath,
+ currentNodePath, getLeafRefContextModule());
+ }
+ }
+
+ return absoluteLeafRefTargetPath;
+ }
+
+ public Module getLeafRefContextModule() {
+ final QNameModule qnameModule = currentNodeQName.getModule();
+
+ return schemaContext.findModuleByNamespaceAndRevision(
+ qnameModule.getNamespace(), qnameModule.getRevision());
+ }
+
+ public void addReferencedByLeafRefCtx(final QName qname, final LeafRefContext leafRef) {
+ referencedByLeafRefCtx.put(qname, leafRef);
+ }
+
+ public LeafRefContext getReferencedByLeafRefCtxByName(final QName qname) {
+ return referencedByLeafRefCtx.get(qname);
+ }
+
+ public Map<QName, LeafRefContext> getAllReferencedByLeafRefCtxs() {
+ return referencedByLeafRefCtx;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.Leafref;
+
+class LeafRefContextTreeBuilder {
+ private final SchemaContext schemaContext;
+ private final LinkedList<LeafRefContext> leafRefs;
+
+ public LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ this.leafRefs = new LinkedList<LeafRefContext>();
+ }
+
+ public LeafRefContext buildLeafRefContextTree() throws IOException,
+ LeafRefYangSyntaxErrorException {
+ final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(
+ schemaContext.getQName(), schemaContext.getPath(),
+ schemaContext);
+
+ final Set<Module> modules = schemaContext.getModules();
+ for (final Module module : modules) {
+ final Collection<DataSchemaNode> childNodes = module.getChildNodes();
+ for (final DataSchemaNode childNode : childNodes) {
+ final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
+ childNode, module);
+
+ if (childLeafRefContext.hasReferencingChild()
+ || childLeafRefContext.isReferencing()) {
+ rootBuilder.addReferencingChild(childLeafRefContext,
+ childLeafRefContext.getNodeName());
+ }
+ }
+ }
+
+ for (final Module module : modules) {
+ final Collection<DataSchemaNode> childNodes = module.getChildNodes();
+ for (final DataSchemaNode childNode : childNodes) {
+ final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
+ childNode, module);
+
+ if (childLeafRefContext.hasReferencedChild()
+ || childLeafRefContext.isReferenced()) {
+ rootBuilder.addReferencedByChild(childLeafRefContext,
+ childLeafRefContext.getNodeName());
+ }
+ }
+ }
+
+ // FIXME: it might be useful to merge these subtrees (i.e. referencing
+ // and referencedBy subtree)
+
+ return rootBuilder.build();
+ }
+
+ private LeafRefContext buildLeafRefContextReferencingTree(
+ final DataSchemaNode node, final Module currentModule) throws IOException,
+ LeafRefYangSyntaxErrorException {
+
+ final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
+ node.getQName(), node.getPath(), schemaContext);
+
+ if (node instanceof DataNodeContainer) {
+ final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
+ final Collection<DataSchemaNode> childNodes = dataNodeContainer
+ .getChildNodes();
+
+ for (final DataSchemaNode childNode : childNodes) {
+ final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
+ childNode, currentModule);
+
+ if (childLeafRefContext.hasReferencingChild()
+ || childLeafRefContext.isReferencing()) {
+ currentLeafRefContextBuilder.addReferencingChild(
+ childLeafRefContext,
+ childLeafRefContext.getNodeName());
+ }
+ }
+ } else if (node instanceof ChoiceSchemaNode) {
+
+ final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
+ final Set<ChoiceCaseNode> cases = choice.getCases();
+ // :FIXME choice without case
+
+ for (final ChoiceCaseNode caseNode : cases) {
+ final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
+ caseNode, currentModule);
+
+ if (childLeafRefContext.hasReferencingChild()
+ || childLeafRefContext.isReferencing()) {
+ currentLeafRefContextBuilder.addReferencingChild(
+ childLeafRefContext,
+ childLeafRefContext.getNodeName());
+ }
+ }
+
+ } else if (node instanceof LeafSchemaNode
+ || node instanceof LeafListSchemaNode) {
+
+ TypeDefinition<?> type = null;
+
+ if (node instanceof LeafSchemaNode) {
+ type = ((LeafSchemaNode) node).getType();
+ } else {
+ type = ((LeafListSchemaNode) node).getType();
+ }
+
+ // FIXME: fix case when type is e.g. typdef -> typedef -> leafref
+ if (type instanceof Leafref) {
+ final Leafref leafrefType = (Leafref) type;
+ final String leafRefPathString = leafrefType.getPathStatement()
+ .toString();
+
+ currentLeafRefContextBuilder
+ .setLeafRefTargetPathString(leafRefPathString);
+ currentLeafRefContextBuilder.setReferencing(true);
+
+ final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(
+ schemaContext, currentModule, node);
+
+ final ByteArrayInputStream leafRefPathInputStream = new ByteArrayInputStream(
+ leafRefPathString.getBytes(Charset.forName("UTF-8")));
+ final LeafRefPath leafRefPath = leafRefPathParser
+ .parseLeafRefPathSourceToSchemaPath(leafRefPathInputStream);
+
+ currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
+
+ final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder
+ .build();
+ leafRefs.add(currentLeafRefContext);
+ return currentLeafRefContext;
+ }
+ }
+
+ return currentLeafRefContextBuilder.build();
+ }
+
+ private LeafRefContext buildLeafRefContextReferencedByTree(
+ final DataSchemaNode node, final Module currentModule) throws IOException,
+ LeafRefYangSyntaxErrorException {
+
+ final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
+ node.getQName(), node.getPath(), schemaContext);
+
+ if (node instanceof DataNodeContainer) {
+ final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
+ final Collection<DataSchemaNode> childNodes = dataNodeContainer
+ .getChildNodes();
+
+ for (final DataSchemaNode childNode : childNodes) {
+ final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
+ childNode, currentModule);
+
+ if (childLeafRefContext.hasReferencedChild()
+ || childLeafRefContext.isReferenced()) {
+ currentLeafRefContextBuilder.addReferencedByChild(
+ childLeafRefContext,
+ childLeafRefContext.getNodeName());
+ }
+ }
+ } else if (node instanceof ChoiceSchemaNode) {
+
+ final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
+ final Set<ChoiceCaseNode> cases = choice.getCases();
+
+ for (final ChoiceCaseNode caseNode : cases) {
+ final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
+ caseNode, currentModule);
+
+ if (childLeafRefContext.hasReferencedChild()
+ || childLeafRefContext.isReferenced()) {
+ currentLeafRefContextBuilder.addReferencedByChild(
+ childLeafRefContext,
+ childLeafRefContext.getNodeName());
+ }
+ }
+
+ } else if (node instanceof LeafSchemaNode
+ || node instanceof LeafListSchemaNode) {
+
+ final LinkedList<LeafRefContext> foundLeafRefs = getLeafRefsFor(node,
+ currentModule);
+ if (!foundLeafRefs.isEmpty()) {
+ currentLeafRefContextBuilder.setReferencedBy(true);
+ for (final LeafRefContext leafRef : foundLeafRefs) {
+ currentLeafRefContextBuilder.addReferencedByLeafRefCtx(
+ leafRef.getNodeName(), leafRef);
+ }
+ }
+ }
+
+ return currentLeafRefContextBuilder.build();
+ }
+
+ private LinkedList<LeafRefContext> getLeafRefsFor(final DataSchemaNode node,
+ final Module module) {
+ final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(
+ node.getPath(), module);
+
+ final LinkedList<LeafRefContext> foundLeafRefs = new LinkedList<LeafRefContext>();
+
+ for (final LeafRefContext leafref : leafRefs) {
+ final LeafRefPath leafRefTargetPath = leafref
+ .getAbsoluteLeafRefTargetPath();
+ if (leafRefTargetPath.equals(nodeXPath)) {
+ foundLeafRefs.add(leafref);
+ }
+ }
+
+ return foundLeafRefs;
+ }
+
+ // private LeafRefContext buildLeafRefContextTreeFor(LeafRefContext parent,
+ // Module module) {
+ //
+ // Collection<DataSchemaNode> childNodes = module.getChildNodes();
+ // for (DataSchemaNode childNode : childNodes) {
+ // LeafRefContext childLeafRefContext = buildLeafRefContextTreeFor(parent,
+ // childNode);
+ //
+ // if(childLeafRefContext.hasReferencedByChild() ||
+ // childLeafRefContext.isReferencedBy()) {
+ // parent.addReferencedByChild(childLeafRefContext,
+ // childLeafRefContext.getCurrentNodeQName());
+ // }
+ // if(childLeafRefContext.hasReferencingChild() ||
+ // childLeafRefContext.isReferencing()) {
+ // parent.addReferencingChild(childLeafRefContext,
+ // childLeafRefContext.getCurrentNodeQName());
+ // }
+ // }
+ //
+ // return node;
+ // }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public final class LeafRefContextUtils {
+
+ private LeafRefContextUtils() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static LeafRefContext getLeafRefReferencingContext(final SchemaNode node,
+ final LeafRefContext root) {
+ final SchemaPath schemaPath = node.getPath();
+ return getLeafRefReferencingContext(schemaPath, root);
+ }
+
+ public static LeafRefContext getLeafRefReferencingContext(
+ final SchemaPath schemaPath, final LeafRefContext root) {
+ final Iterable<QName> pathFromRoot = schemaPath.getPathFromRoot();
+ return getLeafRefReferencingContext(pathFromRoot, root);
+ }
+
+ public static LeafRefContext getLeafRefReferencingContext(
+ final Iterable<QName> pathFromRoot, LeafRefContext root) {
+
+ LeafRefContext leafRefCtx = null;
+ final Iterator<QName> iterator = pathFromRoot.iterator();
+ while (iterator.hasNext() && root != null) {
+ final QName qname = iterator.next();
+ leafRefCtx = root.getReferencingChildByName(qname);
+ if (iterator.hasNext()) {
+ root = leafRefCtx;
+ }
+ }
+
+ return leafRefCtx;
+ }
+
+ public static LeafRefContext getLeafRefReferencedByContext(final SchemaNode node,
+ final LeafRefContext root) {
+ final SchemaPath schemaPath = node.getPath();
+ return getLeafRefReferencedByContext(schemaPath, root);
+ }
+
+ public static LeafRefContext getLeafRefReferencedByContext(
+ final SchemaPath schemaPath, final LeafRefContext root) {
+ final Iterable<QName> pathFromRoot = schemaPath.getPathFromRoot();
+ return getLeafRefReferencedByContext(pathFromRoot, root);
+ }
+
+ public static LeafRefContext getLeafRefReferencedByContext(
+ final Iterable<QName> pathFromRoot, LeafRefContext root) {
+
+ LeafRefContext leafRefCtx = null;
+ final Iterator<QName> iterator = pathFromRoot.iterator();
+ while (iterator.hasNext() && root != null) {
+ final QName qname = iterator.next();
+ leafRefCtx = root.getReferencedChildByName(qname);
+ if (iterator.hasNext()) {
+ root = leafRefCtx;
+ }
+ }
+
+ return leafRefCtx;
+ }
+
+ public static boolean isLeafRef(final SchemaNode node, final LeafRefContext root) {
+
+ if ((node == null) || (root == null))
+ return false;
+
+ final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(
+ node, root);
+ if (leafRefReferencingContext == null)
+ return false;
+
+ return leafRefReferencingContext.isReferencing();
+ }
+
+ public static boolean hasLeafRefChild(final SchemaNode node, final LeafRefContext root) {
+
+ if ((node == null) || (root == null))
+ return false;
+
+ final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(
+ node, root);
+ if (leafRefReferencingContext == null)
+ return false;
+
+ return leafRefReferencingContext.hasReferencingChild();
+ }
+
+ public static boolean isReferencedByLeafRef(final SchemaNode node,
+ final LeafRefContext root) {
+
+ if ((node == null) || (root == null))
+ return false;
+
+ final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+ node, root);
+ if (leafRefReferencedByContext == null)
+ return false;
+
+ return leafRefReferencedByContext.isReferenced();
+ }
+
+ public static boolean hasChildReferencedByLeafRef(final SchemaNode node,
+ final LeafRefContext root) {
+
+ if ((node == null) || (root == null))
+ return false;
+
+ final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+ node, root);
+ if (leafRefReferencedByContext == null)
+ return false;
+
+ return leafRefReferencedByContext.hasReferencedChild();
+ }
+
+ public static List<LeafRefContext> findAllLeafRefChilds(final SchemaNode node,
+ final LeafRefContext root) {
+
+ return findAllLeafRefChilds(node.getPath(), root);
+ }
+
+ public static List<LeafRefContext> findAllLeafRefChilds(
+ final SchemaPath schemaPath, final LeafRefContext root) {
+
+ return findAllLeafRefChilds(schemaPath.getPathFromRoot(), root);
+ }
+
+ public static List<LeafRefContext> findAllLeafRefChilds(
+ final Iterable<QName> pathFromRoot, final LeafRefContext root) {
+
+ final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(
+ pathFromRoot, root);
+ final List<LeafRefContext> allLeafRefsChilds = findAllLeafRefChilds(leafRefReferencingContext);
+
+ return allLeafRefsChilds;
+ }
+
+ public static List<LeafRefContext> findAllLeafRefChilds(
+ final LeafRefContext parent) {
+
+ final LinkedList<LeafRefContext> leafRefChilds = new LinkedList<LeafRefContext>();
+
+ if (parent == null) {
+ return leafRefChilds;
+ }
+
+ if (parent.isReferencing()) {
+ leafRefChilds.add(parent);
+ return leafRefChilds;
+ } else {
+ final Set<Entry<QName, LeafRefContext>> childs = parent
+ .getReferencingChilds().entrySet();
+ for (final Entry<QName, LeafRefContext> child : childs) {
+ leafRefChilds.addAll(findAllLeafRefChilds(child.getValue()));
+ }
+ }
+ return leafRefChilds;
+ }
+
+ public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+ final SchemaNode node, final LeafRefContext root) {
+
+ return findAllChildsReferencedByLeafRef(node.getPath(), root);
+ }
+
+ public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+ final SchemaPath schemaPath, final LeafRefContext root) {
+
+ return findAllChildsReferencedByLeafRef(schemaPath.getPathFromRoot(),
+ root);
+ }
+
+ public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+ final Iterable<QName> pathFromRoot, final LeafRefContext root) {
+
+ final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+ pathFromRoot, root);
+ final List<LeafRefContext> allChildsReferencedByLeafRef = findAllChildsReferencedByLeafRef(leafRefReferencedByContext);
+
+ return allChildsReferencedByLeafRef;
+ }
+
+ public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+ final LeafRefContext parent) {
+
+ final LinkedList<LeafRefContext> childsReferencedByLeafRef = new LinkedList<LeafRefContext>();
+
+ if (parent == null) {
+ return childsReferencedByLeafRef;
+ }
+
+ if (parent.isReferenced()) {
+ childsReferencedByLeafRef.add(parent);
+ return childsReferencedByLeafRef;
+ } else {
+ final Set<Entry<QName, LeafRefContext>> childs = parent
+ .getReferencedByChilds().entrySet();
+ for (final Entry<QName, LeafRefContext> child : childs) {
+ childsReferencedByLeafRef
+ .addAll(findAllChildsReferencedByLeafRef(child
+ .getValue()));
+ }
+ }
+ return childsReferencedByLeafRef;
+ }
+
+ public static Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(
+ final SchemaNode node, final LeafRefContext root) {
+ return getAllLeafRefsReferencingThisNode(node.getPath(), root);
+ }
+
+ public static Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(
+ final SchemaPath path, final LeafRefContext root) {
+ return getAllLeafRefsReferencingThisNode(path.getPathFromRoot(), root);
+ }
+
+ public static Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(
+ final Iterable<QName> pathFromRoot, final LeafRefContext root) {
+
+ final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+ pathFromRoot, root);
+
+ if (leafRefReferencedByContext == null)
+ return new HashMap<QName, LeafRefContext>();
+
+ return leafRefReferencedByContext.getAllReferencedByLeafRefCtxs();
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+public class LeafRefDataValidationFailedException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ private int errorsCount = 1;
+
+ public LeafRefDataValidationFailedException(String message) {
+ super(message);
+ }
+
+ public LeafRefDataValidationFailedException(String message, int errorsCount) {
+ super(message);
+ this.errorsCount = errorsCount;
+ }
+
+ public LeafRefDataValidationFailedException(String message,
+ final Throwable cause) {
+ super(message, cause);
+ }
+
+ public int getValidationsErrorsCount() {
+ return errorsCount;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+public abstract class LeafRefPath implements Immutable {
+
+ /**
+ * An absolute LeafRefPath.
+ */
+ private static final class AbsoluteLeafRefPath extends LeafRefPath {
+ private AbsoluteLeafRefPath(final LeafRefPath parent,
+ final QNameWithPredicate qname) {
+ super(parent, qname);
+ }
+
+ @Override
+ public boolean isAbsolute() {
+ return true;
+ }
+
+ @Override
+ protected LeafRefPath createInstance(final LeafRefPath parent,
+ final QNameWithPredicate qname) {
+ return new AbsoluteLeafRefPath(parent, qname);
+ }
+ }
+
+ /**
+ * A relative LeafRefPath.
+ */
+ private static final class RelativeLeafRefPath extends LeafRefPath {
+ private RelativeLeafRefPath(final LeafRefPath parent,
+ final QNameWithPredicate qname) {
+ super(parent, qname);
+ }
+
+ @Override
+ public boolean isAbsolute() {
+ return false;
+ }
+
+ @Override
+ protected LeafRefPath createInstance(final LeafRefPath parent,
+ final QNameWithPredicate qname) {
+ return new RelativeLeafRefPath(parent, qname);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static final AtomicReferenceFieldUpdater<LeafRefPath, ImmutableList> LEGACYPATH_UPDATER = AtomicReferenceFieldUpdater
+ .newUpdater(LeafRefPath.class, ImmutableList.class, "legacyPath");
+
+ /**
+ * Shared instance of the conceptual root schema node.
+ */
+ public static final LeafRefPath ROOT = new AbsoluteLeafRefPath(null, null);
+
+ /**
+ * Shared instance of the "same" relative schema node.
+ */
+ public static final LeafRefPath SAME = new RelativeLeafRefPath(null, null);
+
+ /**
+ * Parent path.
+ */
+ private final LeafRefPath parent;
+
+ /**
+ * This component.
+ */
+ private final QNameWithPredicate qname;
+
+ /**
+ * Cached hash code. We can use this since we are immutable.
+ */
+ private final int hash;
+
+ /**
+ * Cached legacy path, filled-in when {@link #getPath()} or
+ * {@link #getPathTowardsRoot()} is invoked.
+ */
+ private volatile ImmutableList<QNameWithPredicate> legacyPath;
+
+ private ImmutableList<QNameWithPredicate> getLegacyPath() {
+ ImmutableList<QNameWithPredicate> ret = legacyPath;
+ if (ret == null) {
+ ret = ImmutableList.copyOf(getPathTowardsRoot()).reverse();
+ LEGACYPATH_UPDATER.lazySet(this, ret);
+ }
+
+ return ret;
+ }
+
+ /**
+ * Returns the complete path to schema node.
+ *
+ * @return list of <code>QNameWithPredicate</code> instances which
+ * represents complete path to schema node
+ *
+ * @deprecated Use {@link #getPathFromRoot()} instead.
+ */
+ @Deprecated
+ public List<QNameWithPredicate> getPath() {
+ return getLegacyPath();
+ }
+
+ protected LeafRefPath(final LeafRefPath parent,
+ final QNameWithPredicate qname) {
+ this.parent = parent;
+ this.qname = qname;
+
+ int h = parent == null ? 0 : parent.hashCode();
+ if (qname != null) {
+ h = h * 31 + qname.hashCode();
+ }
+
+ hash = h;
+ }
+
+ /**
+ * Constructs new instance of this class with the concrete path.
+ *
+ * @param path
+ * list of QNameWithPredicate instances which specifies exact
+ * path to the module node
+ * @param absolute
+ * boolean value which specifies if the path is absolute or
+ * relative
+ *
+ * @return A LeafRefPath instance.
+ */
+ public static LeafRefPath create(final Iterable<QNameWithPredicate> path,
+ final boolean absolute) {
+ final LeafRefPath parent = absolute ? ROOT : SAME;
+ return parent.createChild(path);
+ }
+
+ /**
+ * Constructs new instance of this class with the concrete path.
+ *
+ * @param absolute
+ * boolean value which specifies if the path is absolute or
+ * relative
+ * @param path
+ * one or more QNameWithPredicate instances which specifies exact
+ * path to the module node
+ *
+ * @return A LeafRefPath instance.
+ */
+ public static LeafRefPath create(final boolean absolute,
+ final QNameWithPredicate... path) {
+ return create(Arrays.asList(path), absolute);
+ }
+
+ /**
+ * Create a new instance.
+ *
+ * @param parent
+ * Parent LeafRefPath
+ * @param qname
+ * next path element
+ * @return A new LeafRefPath instance
+ */
+ protected abstract LeafRefPath createInstance(LeafRefPath parent,
+ QNameWithPredicate qname);
+
+ /**
+ * Create a child path based on concatenation of this path and a relative
+ * path.
+ *
+ * @param relative
+ * Relative path
+ * @return A new child path
+ */
+ public LeafRefPath createChild(final Iterable<QNameWithPredicate> relative) {
+ if (Iterables.isEmpty(relative)) {
+ return this;
+ }
+
+ LeafRefPath parent = this;
+ for (QNameWithPredicate qname : relative) {
+ parent = parent.createInstance(parent, qname);
+ }
+
+ return parent;
+ }
+
+ /**
+ * Create a child path based on concatenation of this path and a relative
+ * path.
+ *
+ * @param relative
+ * Relative LeafRefPath
+ * @return A new child path
+ */
+ public LeafRefPath createChild(final LeafRefPath relative) {
+ Preconditions.checkArgument(!relative.isAbsolute(),
+ "Child creation requires relative path");
+
+ LeafRefPath parent = this;
+ for (QNameWithPredicate qname : relative.getPathFromRoot()) {
+ parent = parent.createInstance(parent, qname);
+ }
+
+ return parent;
+ }
+
+ /**
+ * Create a child path based on concatenation of this path and additional
+ * path elements.
+ *
+ * @param elements
+ * Relative LeafRefPath elements
+ * @return A new child path
+ */
+ public LeafRefPath createChild(final QNameWithPredicate... elements) {
+ return createChild(Arrays.asList(elements));
+ }
+
+ /**
+ * Returns the list of nodes which need to be traversed to get from the
+ * starting point (root for absolute LeafRefPaths) to the node represented
+ * by this object.
+ *
+ * @return list of <code>qname</code> instances which represents path from
+ * the root to the schema node.
+ */
+ public Iterable<QNameWithPredicate> getPathFromRoot() {
+ return getLegacyPath();
+ }
+
+ /**
+ * Returns the list of nodes which need to be traversed to get from this
+ * node to the starting point (root for absolute LeafRefPaths).
+ *
+ * @return list of <code>qname</code> instances which represents path from
+ * the schema node towards the root.
+ */
+ public Iterable<QNameWithPredicate> getPathTowardsRoot() {
+ return new Iterable<QNameWithPredicate>() {
+ @Override
+ public Iterator<QNameWithPredicate> iterator() {
+ return new Iterator<QNameWithPredicate>() {
+ private LeafRefPath current = LeafRefPath.this;
+
+ @Override
+ public boolean hasNext() {
+ return current.parent != null;
+ }
+
+ @Override
+ public QNameWithPredicate next() {
+ if (current.parent != null) {
+ final QNameWithPredicate ret = current.qname;
+ current = current.parent;
+ return ret;
+ } else {
+ throw new NoSuchElementException(
+ "No more elements available");
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException(
+ "Component removal not supported");
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Returns the immediate parent LeafRefPath.
+ *
+ * @return Parent path, null if this LeafRefPath is already toplevel.
+ */
+ public LeafRefPath getParent() {
+ return parent;
+ }
+
+ /**
+ * Get the last component of this path.
+ *
+ * @return The last component of this path.
+ */
+ public final QNameWithPredicate getLastComponent() {
+ return qname;
+ }
+
+ /**
+ * Describes whether schema path is|isn't absolute.
+ *
+ * @return boolean value which is <code>true</code> if schema path is
+ * absolute.
+ */
+ public abstract boolean isAbsolute();
+
+ @Override
+ public final int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final LeafRefPath other = (LeafRefPath) obj;
+
+ if (qname != null) {
+ if (!qname.equals(other.qname)) {
+ return false;
+ }
+ } else {
+ if (other.qname != null) {
+ return false;
+ }
+ }
+
+ if (parent == null) {
+ return other.parent == null;
+ }
+ return parent.equals(other.parent);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ Iterable<QNameWithPredicate> pathFromRoot = this.getPathFromRoot();
+
+ sb.append(isAbsolute() ? "Absolute path:" : "Relative path:");
+
+ for (QNameWithPredicate qName : pathFromRoot) {
+ sb.append("/" + qName);
+ }
+
+ return sb.toString();
+
+ }
+
+ // @Override
+ // public final String toString() {
+ // return addToStringAttributes(Objects.toStringHelper(this)).toString();
+ // }
+ //
+ // protected ToStringHelper addToStringAttributes(final ToStringHelper
+ // toStringHelper) {
+ // return toStringHelper.add("path", getPathFromRoot());
+ // }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class LeafRefPathErrorListener extends BaseErrorListener {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(LeafRefPathErrorListener.class);
+ private final List<LeafRefPathSyntaxErrorException> exceptions = new ArrayList<>();
+ private final Module module;
+
+ public LeafRefPathErrorListener(final Module module) {
+ this.module = module;
+ }
+
+ @Override
+ public void syntaxError(final Recognizer<?, ?> recognizer,
+ final Object offendingSymbol, final int line,
+ final int charPositionInLine, final String msg,
+ final RecognitionException e) {
+ LOG.debug("Syntax error in module {} at {}:{}: {}", module.getName(), line, charPositionInLine, msg, e);
+
+ exceptions.add(new LeafRefPathSyntaxErrorException(module.getName(), line,
+ charPositionInLine, msg, e));
+ }
+
+ public void validate() throws LeafRefPathSyntaxErrorException {
+ if (exceptions.isEmpty()) {
+ return;
+ }
+
+ // Single exception: just throw it
+ if (exceptions.size() == 1) {
+ throw exceptions.get(0);
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ String module = null;
+ boolean first = true;
+ for (final LeafRefPathSyntaxErrorException e : exceptions) {
+ if (module == null) {
+ module = e.getModule();
+ }
+ if (first) {
+ first = false;
+ } else {
+ sb.append('\n');
+ }
+
+ sb.append(e.getFormattedMessage());
+ }
+
+ throw new LeafRefPathSyntaxErrorException(module, 0, 0, sb.toString());
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+class LeafRefPathParseException extends RuntimeException {
+
+ private static final long serialVersionUID = 7819033841757805240L;
+
+ public LeafRefPathParseException(final String errorMsg) {
+ super(errorMsg);
+
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.io.IOException;
+import java.io.InputStream;
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_argContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+final class LeafRefPathParserImpl {
+ private final SchemaContext schemaContext;
+ private final Module module;
+ private final SchemaNode node;
+
+ public LeafRefPathParserImpl(final SchemaContext schemaContext, final Module currentModule, final SchemaNode currentNode) {
+ this.schemaContext = schemaContext;
+ this.module = currentModule;
+ this.node = currentNode;
+ }
+
+ public LeafRefPath parseLeafRefPathSourceToSchemaPath(final InputStream stream) throws IOException, LeafRefYangSyntaxErrorException {
+
+ final Path_argContext pathCtx = parseLeafRefPathSource(stream);
+
+ final ParseTreeWalker walker = new ParseTreeWalker();
+ final LeafRefPathParserListenerImpl leafRefPathParserListenerImpl = new LeafRefPathParserListenerImpl(schemaContext, module, node);
+ walker.walk(leafRefPathParserListenerImpl,pathCtx);
+
+ final LeafRefPath leafRefPath = leafRefPathParserListenerImpl.getLeafRefPath();
+
+ return leafRefPath;
+ }
+
+
+ private Path_argContext parseLeafRefPathSource(final InputStream stream) throws IOException, LeafRefYangSyntaxErrorException {
+ final LeafRefPathLexer lexer = new LeafRefPathLexer(new ANTLRInputStream(stream));
+ final CommonTokenStream tokens = new CommonTokenStream(lexer);
+ final LeafRefPathParser parser = new LeafRefPathParser(tokens);
+ parser.removeErrorListeners();
+
+ final LeafRefPathErrorListener errorListener = new LeafRefPathErrorListener(module);
+ parser.addErrorListener(errorListener);
+
+ final Path_argContext result = parser.path_arg();
+ errorListener.validate();
+
+ return result;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import java.net.URI;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.IdentifierContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Node_identifierContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_argContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_equality_exprContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_predicateContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.PrefixContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Rel_path_keyexprContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Relative_pathContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+
+
+final class LeafRefPathParserListenerImpl extends LeafRefPathParserBaseListener{
+
+ private final SchemaContext schemaContext;
+ private final Module module;
+ private LeafRefPath leafRefPath;
+ private boolean relativePath=false;
+ private QNameWithPredicateBuilder currentLeafRefPathQName;
+ private QNamePredicateBuilder currentPredicate;
+ private QNameModule currentQnameModule;
+ private String currentQNameLocalName;
+ private final LinkedList<QNameWithPredicateBuilder> leafRefPathQnameList;
+ private LinkedList<QNameWithPredicateBuilder> predicatePathKeyQnameList;
+ private final SchemaNode node; //FIXME use for identifier path completion
+ private ParsingState currentParsingState;
+
+ Function<QNameWithPredicateBuilder, QNameWithPredicate> build = new Function<QNameWithPredicateBuilder, QNameWithPredicate>() {
+ @Override
+ public QNameWithPredicate apply(final QNameWithPredicateBuilder builder) {
+ return builder.build();
+ }
+ };
+
+ private enum ParsingState {
+ LEAF_REF_PATH, PATH_PREDICATE, PREDICATE_PATH_EQUALITY_EXPR, PATH_KEY_EXPR
+ }
+
+ public LeafRefPathParserListenerImpl(final SchemaContext schemaContext, final Module currentModule, final SchemaNode currentNode) {
+ this.schemaContext = schemaContext;
+ this.module = currentModule;
+ this.leafRefPathQnameList = new LinkedList<QNameWithPredicateBuilder>();
+ this.node=currentNode;
+ this.currentParsingState = ParsingState.LEAF_REF_PATH;
+ }
+
+ @Override
+ public void enterPath_predicate(final Path_predicateContext ctx) {
+ currentParsingState=ParsingState.PATH_PREDICATE;
+ currentPredicate = new QNamePredicateBuilder();
+ }
+
+
+ @Override
+ public void exitPath_predicate(final Path_predicateContext ctx) {
+ currentLeafRefPathQName.addQNamePredicate(currentPredicate.build());
+ currentPredicate = null;
+ currentParsingState=ParsingState.LEAF_REF_PATH;
+ }
+
+
+ @Override
+ public void enterRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
+ currentParsingState=ParsingState.PATH_KEY_EXPR;
+ predicatePathKeyQnameList = new LinkedList<QNameWithPredicateBuilder>();
+ final List<TerminalNode> dots = ctx.DOTS();
+ for (final TerminalNode parent : dots) {
+ predicatePathKeyQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
+ }
+ }
+
+
+ @Override
+ public void exitRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
+
+ final LeafRefPath pathKeyExpression = LeafRefPath.create(Lists.transform(predicatePathKeyQnameList,build), false);
+ currentPredicate.setPathKeyExpression(pathKeyExpression);
+
+ currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
+ }
+
+ @Override
+ public void enterRelative_path(final Relative_pathContext ctx) {
+
+ relativePath = true;
+ final List<TerminalNode> dots = ctx.DOTS();
+ for (final TerminalNode parent : dots) {
+ leafRefPathQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
+ }
+
+ }
+
+ @Override
+ public void enterPath_equality_expr(final Path_equality_exprContext ctx) {
+ currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
+ }
+
+
+ @Override
+ public void exitPath_equality_expr(final Path_equality_exprContext ctx) {
+
+ currentParsingState=ParsingState.PATH_PREDICATE;
+ }
+
+ @Override
+ public void enterPrefix(final PrefixContext ctx) {
+
+ if (module.getPrefix().equals(ctx.getText())) {
+ currentQnameModule = module.getQNameModule();
+ } else {
+ currentQnameModule = getQNameModuleForImportPrefix(ctx.getText());
+ }
+ }
+
+ @Override
+ public void exitPath_arg(final Path_argContext ctx) {
+ leafRefPath = LeafRefPath.create(Lists.transform(leafRefPathQnameList,build), !relativePath);
+ }
+
+
+ @Override
+ public void enterIdentifier(final IdentifierContext ctx) {
+ currentQNameLocalName = ctx.getText();
+ }
+
+ @Override
+ public void exitNode_identifier(final Node_identifierContext ctx) {
+
+ if (currentQnameModule == null) {
+ currentQnameModule = module.getQNameModule();
+ }
+
+ if (currentParsingState == ParsingState.PREDICATE_PATH_EQUALITY_EXPR) {
+ final QName qname = QName.create(currentQnameModule,
+ currentQNameLocalName);
+ currentPredicate.setIdentifier(qname);
+ } else {
+
+ final QNameWithPredicateBuilder qnameBuilder = new QNameWithPredicateBuilder(
+ currentQnameModule, currentQNameLocalName);
+
+ if (currentParsingState == ParsingState.PATH_KEY_EXPR) {
+ predicatePathKeyQnameList.add(qnameBuilder);
+ } else if (currentParsingState == ParsingState.LEAF_REF_PATH) {
+ currentLeafRefPathQName = qnameBuilder;
+ leafRefPathQnameList.add(qnameBuilder);
+ }
+ }
+ currentQnameModule = null;
+ currentQNameLocalName = null;
+ }
+
+ public LeafRefPath getLeafRefPath() {
+ return leafRefPath;
+ }
+
+
+ private URI getNamespaceForImportPrefix(final String prefix){
+ final ModuleImport moduleImport = getModuleImport(prefix);
+ final Module findedModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
+
+ return findedModule.getNamespace();
+ }
+
+ private QNameModule getQNameModuleForImportPrefix(final String prefix) {
+ final ModuleImport moduleImport = getModuleImport(prefix);
+
+ if (moduleImport == null) {
+ throw new LeafRefPathParseException("No module import for prefix: "
+ + prefix + " in module: " + module.getName());
+ }
+
+ final String moduleName = moduleImport.getModuleName();
+ final Date revision = moduleImport.getRevision();
+ final Module findedModule = schemaContext.findModuleByName(moduleName,
+ revision);
+
+ return findedModule.getQNameModule();
+ }
+
+
+ private ModuleImport getModuleImport(final String prefix) {
+ final Set<ModuleImport> imports = module.getImports();
+
+ for (final ModuleImport moduleImport : imports) {
+ if(moduleImport.getPrefix().equals(prefix)) {
+ return moduleImport;
+ }
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+public class LeafRefPathSyntaxErrorException extends LeafRefYangSyntaxErrorException{
+
+ private static final long serialVersionUID = 1L;
+
+ public LeafRefPathSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+ final String message) {
+ super(module, line, charPositionInLine, message, null);
+ }
+
+ public LeafRefPathSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+ final String message, final Throwable cause) {
+ super(module,line,charPositionInLine,message,cause);
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class LeafRefUtils {
+
+ /**
+ * @param leafRefPath
+ * @param contextNodeSchemaPath
+ * @return
+ */
+ public static LeafRefPath createAbsoluteLeafRefPath(
+ final LeafRefPath leafRefPath, final SchemaPath contextNodeSchemaPath,
+ final Module module) {
+
+ if (leafRefPath.isAbsolute())
+ return leafRefPath;
+
+ final LinkedList<QNameWithPredicate> absoluteLeafRefTargetPathList = schemaPathToXPathQNames(
+ contextNodeSchemaPath, module);
+
+ final Iterable<QNameWithPredicate> leafRefTargetPathFromRoot = leafRefPath
+ .getPathFromRoot();
+ final Iterator<QNameWithPredicate> leafRefTgtPathFromRootIterator = leafRefTargetPathFromRoot
+ .iterator();
+
+ while (leafRefTgtPathFromRootIterator.hasNext()) {
+ final QNameWithPredicate qname = leafRefTgtPathFromRootIterator.next();
+ if (qname.equals(QNameWithPredicate.UP_PARENT)) {
+ absoluteLeafRefTargetPathList.removeLast();
+ } else {
+ absoluteLeafRefTargetPathList.add(qname);
+ }
+ }
+
+ return LeafRefPath.create(absoluteLeafRefTargetPathList, true);
+ }
+
+ /**
+ * @param currentNodePath
+ * @param module
+ * @param absoluteLeafRefTargetPathList
+ */
+ private static LinkedList<QNameWithPredicate> schemaPathToXPathQNames(
+ final SchemaPath nodePath, final Module module) {
+
+ final LinkedList<QNameWithPredicate> xpath = new LinkedList<QNameWithPredicate>();
+
+ final Iterator<QName> nodePathIterator = nodePath.getPathFromRoot()
+ .iterator();
+
+ DataNodeContainer currenDataNodeContainer = module;
+ while (nodePathIterator.hasNext()) {
+ final QName qname = nodePathIterator.next();
+ final DataSchemaNode child = currenDataNodeContainer
+ .getDataChildByName(qname);
+
+ if (child instanceof DataNodeContainer) {
+ if (!(child instanceof ChoiceCaseNode)) {
+ final QNameWithPredicate newQName = new QNameWithPredicateBuilder(
+ qname.getModule(), qname.getLocalName()).build();
+ xpath.add(newQName);
+ }
+ currenDataNodeContainer = (DataNodeContainer) child;
+ } else if (child instanceof ChoiceSchemaNode) {
+ if (nodePathIterator.hasNext()) {
+ currenDataNodeContainer = ((ChoiceSchemaNode) child)
+ .getCaseNodeByName(nodePathIterator.next());
+ } else {
+ break;
+ }
+ } else if (child instanceof LeafSchemaNode
+ || child instanceof LeafListSchemaNode) {
+
+ final QNameWithPredicate newQName = new QNameWithPredicateBuilder(
+ qname.getModule(), qname.getLocalName()).build();
+ xpath.add(newQName);
+ break;
+
+ } else if (child == null) {
+ throw new IllegalArgumentException("No child " + qname
+ + " found in node container " + currenDataNodeContainer
+ + " in module " + module.getName());
+ } else {
+ throw new IllegalStateException(
+ "Illegal schema node type in the path: "
+ + child.getClass());
+ }
+ }
+
+ return xpath;
+ }
+
+ public static LeafRefPath schemaPathToLeafRefPath(final SchemaPath nodePath,
+ final Module module) {
+ final LinkedList<QNameWithPredicate> xpathQNames = schemaPathToXPathQNames(
+ nodePath, module);
+ return LeafRefPath.create(xpathQNames, true);
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LeafRefValidatation {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LeafRefValidatation.class);
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ private final DataTreeCandidate tree;
+ private final LinkedList<String> errorsMessages = new LinkedList<String>();
+ private final HashSet<LeafRefContext> validatedLeafRefCtx = new HashSet<LeafRefContext>();
+
+ private LeafRefValidatation(final DataTreeCandidate tree) {
+ this.tree = tree;
+ }
+
+ public static void validate(final DataTreeCandidate tree, final LeafRefContext rootLeafRefCtx)
+ throws LeafRefDataValidationFailedException {
+ new LeafRefValidatation(tree).validate0(rootLeafRefCtx);
+ }
+ private void validate0(final LeafRefContext rootLeafRefCtx)
+ throws LeafRefDataValidationFailedException {
+
+ final DataTreeCandidateNode rootNode = tree.getRootNode();
+
+ final Collection<DataTreeCandidateNode> childNodes = rootNode.getChildNodes();
+ for (final DataTreeCandidateNode dataTreeCandidateNode : childNodes) {
+
+ final ModificationType modificationType = dataTreeCandidateNode
+ .getModificationType();
+ if (modificationType != ModificationType.UNMODIFIED) {
+
+ final PathArgument identifier = dataTreeCandidateNode.getIdentifier();
+ final QName childQName = identifier.getNodeType();
+
+ final LeafRefContext referencedByCtx = rootLeafRefCtx
+ .getReferencedChildByName(childQName);
+ final LeafRefContext referencingCtx = rootLeafRefCtx
+ .getReferencingChildByName(childQName);
+ if (referencedByCtx != null || referencingCtx != null) {
+ final YangInstanceIdentifier yangInstanceIdentifier = YangInstanceIdentifier
+ .create(dataTreeCandidateNode.getIdentifier());
+ validateNode(dataTreeCandidateNode, referencedByCtx,
+ referencingCtx, yangInstanceIdentifier);
+ }
+ }
+
+ }
+
+ if (!errorsMessages.isEmpty()) {
+ final StringBuilder message = new StringBuilder();
+ int errCount = 0;
+ for (final String errorMessage : errorsMessages) {
+ message.append(errorMessage);
+ errCount++;
+ }
+ throw new LeafRefDataValidationFailedException(message.toString(),
+ errCount);
+ }
+
+ }
+
+ private void validateNode(final DataTreeCandidateNode node,
+ final LeafRefContext referencedByCtx, final LeafRefContext referencingCtx,
+ final YangInstanceIdentifier current) {
+
+ if ((node.getModificationType() == ModificationType.WRITE)
+ && node.getDataAfter().isPresent()) {
+ final Optional<NormalizedNode<?, ?>> dataAfter = node.getDataAfter();
+ final NormalizedNode<?, ?> normalizedNode = dataAfter.get();
+ validateNodeData(normalizedNode, referencedByCtx, referencingCtx,
+ node.getModificationType(), current);
+ return;
+ }
+
+ if (node.getModificationType() == ModificationType.DELETE
+ && referencedByCtx != null) {
+ final Optional<NormalizedNode<?, ?>> dataBefor = node.getDataBefore();
+ final NormalizedNode<?, ?> normalizedNode = dataBefor.get();
+ validateNodeData(normalizedNode, referencedByCtx, null,
+ node.getModificationType(), current);
+ return;
+ }
+
+ final Collection<DataTreeCandidateNode> childNodes = node.getChildNodes();
+ for (final DataTreeCandidateNode childNode : childNodes) {
+ final ModificationType modificationType = childNode.getModificationType();
+
+ if (modificationType != ModificationType.UNMODIFIED) {
+
+ final LeafRefContext childReferencedByCtx = getReferencedByCtxChild(
+ referencedByCtx, childNode);
+ final LeafRefContext childReferencingCtx = getReferencingCtxChild(
+ referencingCtx, childNode);
+
+ if (childReferencedByCtx != null || childReferencingCtx != null) {
+ final YangInstanceIdentifier childYangInstanceIdentifier = current
+ .node(childNode.getIdentifier());
+ validateNode(childNode, childReferencedByCtx,
+ childReferencingCtx, childYangInstanceIdentifier);
+ }
+ }
+
+ }
+
+ }
+
+ private LeafRefContext getReferencingCtxChild(
+ final LeafRefContext referencingCtx, final DataTreeCandidateNode childNode) {
+
+ LeafRefContext childReferencingCtx = null;
+ if (referencingCtx != null) {
+ final PathArgument identifier = childNode.getIdentifier();
+ final QName childQName = identifier.getNodeType();
+
+ childReferencingCtx = referencingCtx
+ .getReferencingChildByName(childQName);
+
+ if (childReferencingCtx == null) {
+ final NormalizedNode<?, ?> data = childNode.getDataAfter().get();
+ if (data instanceof MapEntryNode
+ || data instanceof UnkeyedListEntryNode) {
+ childReferencingCtx = referencingCtx;
+ }
+ }
+ }
+
+ return childReferencingCtx;
+ }
+
+ private LeafRefContext getReferencedByCtxChild(
+ final LeafRefContext referencedByCtx, final DataTreeCandidateNode childNode) {
+
+ LeafRefContext childReferencedByCtx = null;
+ if (referencedByCtx != null) {
+ final PathArgument identifier = childNode.getIdentifier();
+ final QName childQName = identifier.getNodeType();
+
+ childReferencedByCtx = referencedByCtx
+ .getReferencedChildByName(childQName);
+ if (childReferencedByCtx == null) {
+ final NormalizedNode<?, ?> data = childNode.getDataAfter().get();
+ if (data instanceof MapEntryNode
+ || data instanceof UnkeyedListEntryNode) {
+ childReferencedByCtx = referencedByCtx;
+ }
+ }
+ }
+
+ return childReferencedByCtx;
+ }
+
+ private void validateNodeData(final NormalizedNode<?, ?> node,
+ final LeafRefContext referencedByCtx, final LeafRefContext referencingCtx,
+ final ModificationType modificationType, final YangInstanceIdentifier current) {
+
+ if (node instanceof LeafNode) {
+ final LeafNode<?> leaf = (LeafNode<?>) node;
+
+ if (referencedByCtx != null && referencedByCtx.isReferenced()) {
+ validateLeafRefTargetNodeData(leaf, referencedByCtx,
+ modificationType);
+ }
+ if (referencingCtx != null && referencingCtx.isReferencing()) {
+ validateLeafRefNodeData(leaf, referencingCtx, modificationType,
+ current);
+ }
+
+ return;
+ }
+
+ if (node instanceof LeafSetNode) {
+ final LeafSetNode<?> leafSet = (LeafSetNode<?>) node;
+
+ if (referencedByCtx == null && referencingCtx == null) {
+ return;
+ }
+
+ final Iterable<? extends NormalizedNode<?, ?>> leafSetEntries = leafSet
+ .getValue();
+ for (final NormalizedNode<?, ?> leafSetEntry : leafSetEntries) {
+ if (referencedByCtx != null && referencedByCtx.isReferenced()) {
+ validateLeafRefTargetNodeData(leafSetEntry,
+ referencedByCtx, modificationType);
+ }
+ if (referencingCtx != null && referencingCtx.isReferencing()) {
+ validateLeafRefNodeData(leafSetEntry, referencingCtx,
+ modificationType, current);
+ }
+ }
+
+ return;
+ }
+
+ if (node instanceof ChoiceNode) {
+ final ChoiceNode choice = (ChoiceNode) node;
+ final Iterable<DataContainerChild<? extends PathArgument, ?>> childs = choice
+ .getValue();
+ for (final DataContainerChild<? extends PathArgument, ?> dataContainerChild : childs) {
+ final QName qname = dataContainerChild.getNodeType();
+
+ LeafRefContext childReferencedByCtx = null;
+ LeafRefContext childReferencingCtx = null;
+ if (referencedByCtx != null) {
+ childReferencedByCtx = findReferencedByCtxUnderChoice(
+ referencedByCtx, qname);
+ }
+ if (referencingCtx != null) {
+ childReferencingCtx = findReferencingCtxUnderChoice(
+ referencingCtx, qname);
+ }
+ if (childReferencedByCtx != null || childReferencingCtx != null) {
+ final YangInstanceIdentifier childYangInstanceIdentifier = current
+ .node(dataContainerChild.getIdentifier());
+ validateNodeData(dataContainerChild, childReferencedByCtx,
+ childReferencingCtx, modificationType,
+ childYangInstanceIdentifier);
+ }
+ }
+ } else if (node instanceof DataContainerNode) {
+ final DataContainerNode<?> dataContainerNode = (DataContainerNode<?>) node;
+ final Iterable<DataContainerChild<? extends PathArgument, ?>> dataContainerChilds = dataContainerNode
+ .getValue();
+
+ for (final DataContainerChild<? extends PathArgument, ?> dataContainerChild : dataContainerChilds) {
+ final QName qname = dataContainerChild.getNodeType();
+
+ LeafRefContext childReferencedByCtx = null;
+ LeafRefContext childReferencingCtx = null;
+ if (referencedByCtx != null) {
+ childReferencedByCtx = referencedByCtx
+ .getReferencedChildByName(qname);
+ }
+ if (referencingCtx != null) {
+ childReferencingCtx = referencingCtx
+ .getReferencingChildByName(qname);
+ }
+ if (childReferencedByCtx != null || childReferencingCtx != null) {
+ final YangInstanceIdentifier childYangInstanceIdentifier = current
+ .node(dataContainerChild.getIdentifier());
+ validateNodeData(dataContainerChild, childReferencedByCtx,
+ childReferencingCtx, modificationType,
+ childYangInstanceIdentifier);
+ }
+ }
+ } else if (node instanceof MapNode) {
+ final MapNode map = (MapNode) node;
+ final Iterable<MapEntryNode> mapEntries = map.getValue();
+ for (final MapEntryNode mapEntry : mapEntries) {
+ final Iterable<DataContainerChild<? extends PathArgument, ?>> mapEntryNodes = mapEntry
+ .getValue();
+ final YangInstanceIdentifier mapEntryYangInstanceIdentifier = current
+ .node(mapEntry.getIdentifier());
+ for (final DataContainerChild<? extends PathArgument, ?> mapEntryNode : mapEntryNodes) {
+ final QName qname = mapEntryNode.getNodeType();
+
+ LeafRefContext childReferencedByCtx = null;
+ LeafRefContext childReferencingCtx = null;
+ if (referencedByCtx != null) {
+ childReferencedByCtx = referencedByCtx
+ .getReferencedChildByName(qname);
+ }
+ if (referencingCtx != null) {
+ childReferencingCtx = referencingCtx
+ .getReferencingChildByName(qname);
+ }
+ if (childReferencedByCtx != null
+ || childReferencingCtx != null) {
+ final YangInstanceIdentifier mapEntryNodeYangInstanceIdentifier = mapEntryYangInstanceIdentifier
+ .node(mapEntryNode.getIdentifier());
+ validateNodeData(mapEntryNode, childReferencedByCtx,
+ childReferencingCtx, modificationType,
+ mapEntryNodeYangInstanceIdentifier);
+ }
+ }
+ }
+
+ }
+ // FIXME if(node instance of UnkeyedListNode ...
+ }
+
+ private LeafRefContext findReferencingCtxUnderChoice(
+ final LeafRefContext referencingCtx, final QName qname) {
+
+ final Map<QName, LeafRefContext> referencingChilds = referencingCtx
+ .getReferencingChilds();
+ final Set<Entry<QName, LeafRefContext>> childs = referencingChilds.entrySet();
+ for (final Entry<QName, LeafRefContext> child : childs) {
+ final LeafRefContext referencingChildByName = child.getValue()
+ .getReferencingChildByName(qname);
+ if (referencingChildByName != null) {
+ return referencingChildByName;
+ }
+ }
+
+ return null;
+ }
+
+ private LeafRefContext findReferencedByCtxUnderChoice(
+ final LeafRefContext referencedByCtx, final QName qname) {
+
+ final Map<QName, LeafRefContext> referencedByChilds = referencedByCtx
+ .getReferencedByChilds();
+ final Set<Entry<QName, LeafRefContext>> childs = referencedByChilds
+ .entrySet();
+ for (final Entry<QName, LeafRefContext> child : childs) {
+ final LeafRefContext referencedByChildByName = child.getValue()
+ .getReferencedChildByName(qname);
+ if (referencedByChildByName != null) {
+ return referencedByChildByName;
+ }
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void validateLeafRefTargetNodeData(final NormalizedNode<?, ?> leaf,
+ final LeafRefContext referencedByCtx, final ModificationType modificationType) {
+
+ final StringBuilder header_log = new StringBuilder();
+ final StringBuilder log = new StringBuilder();
+ header_log.append("Operation [" + modificationType
+ + "] validate data of leafref TARGET node: name["
+ + referencedByCtx.getNodeName() + "] = value["
+ + leaf.getValue() + "]");
+
+ if (validatedLeafRefCtx.contains(referencedByCtx)) {
+ header_log.append(" -> SKIP: Already validated");
+ LOG.debug(header_log.toString());
+ return;
+ }
+
+ final Map<QName, LeafRefContext> allReferencedByLeafRefCtxs = referencedByCtx
+ .getAllReferencedByLeafRefCtxs();
+
+ final HashMap<LeafRefContext, HashSet> leafRefsValues = new HashMap<LeafRefContext, HashSet>();
+ final Collection<LeafRefContext> leafrefs = allReferencedByLeafRefCtxs
+ .values();
+ for (final LeafRefContext leafRefContext : leafrefs) {
+ if (leafRefContext.isReferencing()) {
+ final HashSet<Object> values = new HashSet<>();
+
+ final SchemaPath leafRefNodeSchemaPath = leafRefContext
+ .getCurrentNodePath();
+ final LeafRefPath leafRefNodePath = LeafRefUtils
+ .schemaPathToLeafRefPath(leafRefNodeSchemaPath,
+ leafRefContext.getLeafRefContextModule());
+ final Iterable<QNameWithPredicate> pathFromRoot = leafRefNodePath
+ .getPathFromRoot();
+ addValues(values, tree.getRootNode().getDataAfter(),
+ pathFromRoot, null, QNameWithPredicate.ROOT);
+ leafRefsValues.put(leafRefContext, values);
+ }
+ }
+
+ final HashSet<Object> leafRefTargetNodeValues = new HashSet<>();
+ final SchemaPath nodeSchemaPath = referencedByCtx.getCurrentNodePath();
+ final LeafRefPath nodePath = LeafRefUtils.schemaPathToLeafRefPath(
+ nodeSchemaPath, referencedByCtx.getLeafRefContextModule());
+ addValues(leafRefTargetNodeValues, tree.getRootNode().getDataAfter(),
+ nodePath.getPathFromRoot(), null, QNameWithPredicate.ROOT);
+
+ boolean valid = true;
+ final Set<Entry<LeafRefContext, HashSet>> entrySet = leafRefsValues
+ .entrySet();
+ for (final Entry<LeafRefContext, HashSet> entry : entrySet) {
+ final LeafRefContext leafRefContext = entry.getKey();
+ final HashSet leafRefValuesSet = entry.getValue();
+ for (final Object leafRefsValue : leafRefValuesSet) {
+ if (!leafRefTargetNodeValues.contains(leafRefsValue)) {
+
+ final StringBuilder sb = createInvalidTargetMessage(leaf,
+ leafRefTargetNodeValues, leafRefContext,
+ leafRefsValue);
+ log.append(NEW_LINE);
+ log.append(sb.toString());
+ log.append(" -> FAILED");
+
+ sb.append(NEW_LINE);
+ errorsMessages.add(sb.toString());
+
+ valid = false;
+ } else {
+ log.append(NEW_LINE);
+ log.append("Valid leafref value [");
+ log.append(leafRefsValue);
+ log.append("]");
+ log.append(" -> OK");
+ }
+ }
+ }
+
+ header_log.append(valid ? " -> OK" : " -> FAILED");
+ LOG.debug(header_log.append(log.toString()).toString());
+
+ validatedLeafRefCtx.add(referencedByCtx);
+ }
+
+ private StringBuilder createInvalidTargetMessage(final NormalizedNode<?, ?> leaf,
+ final HashSet<?> leafRefTargetNodeValues, final LeafRefContext leafRefContext,
+ final Object leafRefsValue) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Invalid leafref value [");
+ sb.append(leafRefsValue);
+ sb.append("]");
+ sb.append(" allowed values ");
+ sb.append(leafRefTargetNodeValues);
+ sb.append(" by validation of leafref TARGET node: ");
+ sb.append(leaf.getNodeType());
+ sb.append(" path of invalid LEAFREF node: ");
+ sb.append(leafRefContext.getCurrentNodePath());
+ sb.append(" leafRef target path: ");
+ sb.append(leafRefContext.getAbsoluteLeafRefTargetPath());
+ return sb;
+ }
+
+ private void validateLeafRefNodeData(final NormalizedNode<?, ?> leaf,
+ final LeafRefContext referencingCtx, final ModificationType modificationType,
+ final YangInstanceIdentifier current) {
+
+ final StringBuilder header_log = new StringBuilder();
+ final StringBuilder log = new StringBuilder();
+
+ header_log.append("Operation [" + modificationType
+ + "] validate data of LEAFREF node: name["
+ + referencingCtx.getNodeName() + "] = value["
+ + leaf.getValue() + "]");
+
+ final HashSet<Object> values = new HashSet<>();
+ final LeafRefPath targetPath = referencingCtx.getAbsoluteLeafRefTargetPath();
+ final Iterable<QNameWithPredicate> pathFromRoot = targetPath
+ .getPathFromRoot();
+
+ addValues(values, tree.getRootNode().getDataAfter(), pathFromRoot,
+ current, QNameWithPredicate.ROOT);
+
+ if (!values.contains(leaf.getValue())) {
+ final StringBuilder sb = createInvalidLeafRefMessage(leaf,
+ referencingCtx, values);
+ errorsMessages.add(sb.toString());
+
+ header_log.append(" -> FAILED");
+ log.append(sb.toString());
+ } else {
+ header_log.append(" -> OK");
+ }
+
+ LOG.debug(header_log.toString());
+ if (!log.toString().equals(""))
+ LOG.debug(log.toString());
+ }
+
+ private StringBuilder createInvalidLeafRefMessage(
+ final NormalizedNode<?, ?> leaf, final LeafRefContext referencingCtx,
+ final Set<?> values) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Invalid leafref value [");
+ sb.append(leaf.getValue());
+ sb.append("]");
+ sb.append(" allowed values ");
+ sb.append(values);
+ sb.append(" of LEAFREF node: ");
+ sb.append(leaf.getNodeType());
+ sb.append(" leafRef target path: ");
+ sb.append(referencingCtx.getAbsoluteLeafRefTargetPath());
+ sb.append(NEW_LINE);
+ return sb;
+ }
+
+ private void addValues(final Set<Object> values,
+ final Optional<? extends NormalizedNode<?, ?>> optDataNode,
+ final Iterable<QNameWithPredicate> path, final YangInstanceIdentifier current,
+ final QNameWithPredicate previousQName) {
+
+ if (!optDataNode.isPresent()) {
+ return;
+ }
+ final NormalizedNode<?, ?> node = optDataNode.get();
+
+ if (node instanceof LeafNode || node instanceof LeafSetEntryNode) {
+ values.add(node.getValue());
+ return;
+ } else if (node instanceof LeafSetNode<?>) {
+ final LeafSetNode<?> leafSetNode = (LeafSetNode<?>) node;
+ final Iterable<? extends NormalizedNode<?, ?>> entries = leafSetNode
+ .getValue();
+ for (final NormalizedNode<?, ?> entry : entries) {
+ values.add(entry.getValue());
+ }
+ return;
+ }
+
+ final Iterator<QNameWithPredicate> iterator = path.iterator();
+ if (!iterator.hasNext()) {
+ return;
+ }
+ final QNameWithPredicate qnameWithPredicate = iterator.next();
+ final QName qName = qnameWithPredicate.getQName();
+ final PathArgument pathArgument = toPathArgument(qName);
+
+ if (node instanceof DataContainerNode) {
+ final DataContainerNode<?> dataContainerNode = (DataContainerNode<?>) node;
+ final Optional<DataContainerChild<? extends PathArgument, ?>> child = dataContainerNode
+ .getChild(pathArgument);
+
+ if (child.isPresent()) {
+ addValues(values, child, nextLevel(path), current,
+ qnameWithPredicate);
+ } else {
+ final Iterable<ChoiceNode> choiceNodes = getChoiceNodes(dataContainerNode);
+ for (final ChoiceNode choiceNode : choiceNodes) {
+ addValues(values, Optional.of(choiceNode), path, current,
+ qnameWithPredicate);
+ }
+ }
+
+ } else if (node instanceof MapNode) {
+ final MapNode map = (MapNode) node;
+ final List<QNamePredicate> qNamePredicates = previousQName
+ .getQNamePredicates();
+ if (qNamePredicates.isEmpty() || current == null) {
+ final Iterable<MapEntryNode> value = map.getValue();
+ for (final MapEntryNode mapEntryNode : value) {
+ final Optional<DataContainerChild<? extends PathArgument, ?>> child = mapEntryNode
+ .getChild(pathArgument);
+
+ if (child.isPresent()) {
+ addValues(values, child, nextLevel(path), current,
+ qnameWithPredicate);
+ } else {
+ final Iterable<ChoiceNode> choiceNodes = getChoiceNodes(mapEntryNode);
+ for (final ChoiceNode choiceNode : choiceNodes) {
+ addValues(values, Optional.of(choiceNode), path,
+ current, qnameWithPredicate);
+ }
+ }
+ }
+ } else {
+ final Map<QName, Set<?>> keyValues = new HashMap<QName, Set<?>>();
+
+ final Iterator<QNamePredicate> predicates = qNamePredicates
+ .iterator();
+ while (predicates.hasNext()) {
+ final QNamePredicate predicate = predicates.next();
+ final QName identifier = predicate.getIdentifier();
+ final LeafRefPath predicatePathKeyExpression = predicate
+ .getPathKeyExpression();
+
+ final Set<?> pathKeyExprValues = getPathKeyExpressionValues(
+ predicatePathKeyExpression, current);
+
+ keyValues.put(identifier, pathKeyExprValues);
+ }
+
+ final Iterable<MapEntryNode> mapEntryNodes = map.getValue();
+ for (final MapEntryNode mapEntryNode : mapEntryNodes) {
+ if (isMatchingPredicate(mapEntryNode, keyValues)) {
+ final Optional<DataContainerChild<? extends PathArgument, ?>> child = mapEntryNode
+ .getChild(pathArgument);
+
+ if (child.isPresent()) {
+ addValues(values, child, nextLevel(path), current,
+ qnameWithPredicate);
+ } else {
+ final Iterable<ChoiceNode> choiceNodes = getChoiceNodes(mapEntryNode);
+ for (final ChoiceNode choiceNode : choiceNodes) {
+ addValues(values, Optional.of(choiceNode),
+ path, current, qnameWithPredicate);
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ private Iterable<ChoiceNode> getChoiceNodes(
+ final DataContainerNode<?> dataContainerNode) {
+
+ final LinkedList<ChoiceNode> choiceNodes = new LinkedList<ChoiceNode>();
+
+ final Iterable<DataContainerChild<? extends PathArgument, ?>> childs = dataContainerNode
+ .getValue();
+ for (final DataContainerChild<? extends PathArgument, ?> child : childs) {
+ if (child instanceof ChoiceNode) {
+ choiceNodes.add((ChoiceNode) child);
+ }
+ }
+ return choiceNodes;
+ }
+
+ private boolean isMatchingPredicate(final MapEntryNode mapEntryNode,
+ final Map<QName, Set<?>> allowedKeyValues) {
+
+ final NodeIdentifierWithPredicates identifier = mapEntryNode.getIdentifier();
+ final Map<QName, Object> entryKeyValues = identifier.getKeyValues();
+
+ final Set<Entry<QName, Object>> entryKeyValueSet = entryKeyValues.entrySet();
+ for (final Entry<QName, Object> entryKeyValue : entryKeyValueSet) {
+ final QName key = entryKeyValue.getKey();
+ final Object value = entryKeyValue.getValue();
+
+ final Set<?> allowedValues = allowedKeyValues.get(key);
+ if (allowedValues != null && !allowedValues.contains(value)) {
+ return false;
+ }
+
+ }
+
+ return true;
+ }
+
+ private Set<?> getPathKeyExpressionValues(
+ final LeafRefPath predicatePathKeyExpression,
+ final YangInstanceIdentifier current) {
+
+ final Optional<NormalizedNode<?, ?>> parent = findParentNode(tree
+ .getRootNode().getDataAfter(), current);
+
+ final Iterable<QNameWithPredicate> predicatePathExpr = predicatePathKeyExpression
+ .getPathFromRoot();
+ final Iterable<QNameWithPredicate> predicatePath = nextLevel(predicatePathExpr);
+
+ final Set<Object> values = new HashSet<>();
+ if (parent != null) {
+ addValues(values, parent, predicatePath, null,
+ QNameWithPredicate.ROOT);
+ }
+
+ return values;
+ }
+
+ private Optional<NormalizedNode<?, ?>> findParentNode(
+ final Optional<NormalizedNode<?, ?>> root, final YangInstanceIdentifier path) {
+ Optional<NormalizedNode<?, ?>> currentNode = root;
+ final Iterator<PathArgument> pathIterator = path.getPathArguments()
+ .iterator();
+ while (pathIterator.hasNext()) {
+ final PathArgument childPathArgument = pathIterator.next();
+ if (pathIterator.hasNext() && currentNode.isPresent()) {
+ currentNode = NormalizedNodes.getDirectChild(currentNode.get(),
+ childPathArgument);
+ } else {
+ return currentNode;
+ }
+ }
+ return Optional.absent();
+ }
+
+ private Iterable<QNameWithPredicate> nextLevel(
+ final Iterable<QNameWithPredicate> path) {
+ return Iterables.skip(path, 1);
+ }
+
+ private PathArgument toPathArgument(final QName qName) {
+ return YangInstanceIdentifier.of(qName).getLastPathArgument();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Preconditions;
+
+public class LeafRefYangSyntaxErrorException extends Exception {
+ private static final long serialVersionUID = 1L;
+ private final String module;
+ private final int line;
+ private final int charPositionInLine;
+
+ public LeafRefYangSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+ final String message) {
+ this(module, line, charPositionInLine, message, null);
+ }
+
+ public LeafRefYangSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+ final String message, final Throwable cause) {
+ super(Preconditions.checkNotNull(message), cause);
+ this.module = module;
+ this.line = line;
+ this.charPositionInLine = charPositionInLine;
+ }
+
+ public String getModule() {
+ return module;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public int getCharPositionInLine() {
+ return charPositionInLine;
+ }
+
+ public String getFormattedMessage() {
+ final StringBuilder sb = new StringBuilder(getMessage());
+ if (module != null) {
+ sb.append(" in module ");
+ sb.append(module);
+ }
+ if (line != 0) {
+ sb.append(" on line ");
+ sb.append(line);
+ if (charPositionInLine != 0) {
+ sb.append(" character ");
+ sb.append(charPositionInLine);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getName() + ": " + getFormattedMessage();
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface QNamePredicate {
+
+ public QName getIdentifier();
+
+ public LeafRefPath getPathKeyExpression();
+
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+class QNamePredicateBuilder {
+
+ private QName identifier;
+ private LeafRefPath pathKeyExpression;
+
+ public QNamePredicateBuilder() {
+ }
+
+ public QNamePredicateBuilder(final QName identifier, final LeafRefPath pathKeyExpression) {
+ this.identifier = identifier;
+ this.pathKeyExpression = pathKeyExpression;
+ }
+
+ public QName getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(final QName identifier) {
+ this.identifier = identifier;
+ }
+
+ public LeafRefPath getPathKeyExpression() {
+ return pathKeyExpression;
+ }
+
+ public void setPathKeyExpression(final LeafRefPath pathKeyExpression) {
+ this.pathKeyExpression = pathKeyExpression;
+ }
+
+ public QNamePredicate build() {
+ return new QNamePredicateImpl(identifier, pathKeyExpression);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+
+ sb.append(identifier);
+ sb.append("=current()");
+
+ final Iterable<QNameWithPredicate> pathFromRoot = pathKeyExpression
+ .getPathFromRoot();
+
+ for (final QNameWithPredicate qName : pathFromRoot) {
+ sb.append("/" + qName);
+ }
+
+ sb.append("]");
+ return sb.toString();
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Preconditions;
+import java.io.Serializable;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+class QNamePredicateImpl implements Immutable, Serializable,
+ QNamePredicate {
+
+ private static final long serialVersionUID = 1L;
+ private final QName identifier;
+ private final LeafRefPath pathKeyExpression;
+
+ public QNamePredicateImpl(final QName identifier, final LeafRefPath pathKeyExpression) {
+ this.identifier = Preconditions.checkNotNull(identifier, "QNamePredicate: identifier should not be null");
+ this.pathKeyExpression = Preconditions.checkNotNull(pathKeyExpression, "QNamePredicate: pathKeyExpression should not be null");
+ }
+
+ @Override
+ public QName getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ public LeafRefPath getPathKeyExpression() {
+ return pathKeyExpression;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+
+ sb.append(identifier);
+ sb.append("=current()");
+
+ final Iterable<QNameWithPredicate> pathFromRoot = pathKeyExpression
+ .getPathFromRoot();
+
+ for (final QNameWithPredicate qName : pathFromRoot) {
+ sb.append("/" + qName);
+ }
+
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+public interface QNameWithPredicate {
+
+ static final QNameWithPredicate UP_PARENT = new QNameWithPredicateBuilder(
+ null, "..").build();
+
+ static final QNameWithPredicate ROOT = new QNameWithPredicateBuilder(
+ null, "").build();
+
+ public List<QNamePredicate> getQNamePredicates();
+
+ public QNameModule getModuleQname();
+
+ public String getLocalName();
+
+ public QName getQName();
+
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.LinkedList;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+class QNameWithPredicateBuilder {
+
+ private LinkedList<QNamePredicate> qnamePredicates;
+ private QNameModule moduleQname;
+ private String localName;
+
+ public static QNameWithPredicateBuilder UP_PARENT_BUILDER = new QNameWithPredicateBuilder(
+ null, "..") {
+ @Override
+ public QNameWithPredicate build() {
+ return QNameWithPredicate.UP_PARENT;
+ }
+ };
+
+ public QNameWithPredicateBuilder(final QNameModule moduleQname, final String localName) {
+ this.moduleQname = moduleQname;
+ this.localName = localName;
+ this.qnamePredicates = new LinkedList<QNamePredicate>();
+ }
+
+ public QNameWithPredicate build() {
+ final QNameWithPredicateImpl qNameWithPredicateImpl = new QNameWithPredicateImpl(
+ moduleQname, localName, qnamePredicates);
+
+ this.qnamePredicates = new LinkedList<QNamePredicate>();
+
+ return qNameWithPredicateImpl;
+ }
+
+ public LinkedList<QNamePredicate> getQNamePredicates() {
+ return qnamePredicates;
+ }
+
+ public void addQNamePredicate(final QNamePredicate qnamePredicate) {
+ qnamePredicates.add(qnamePredicate);
+ }
+
+ public QNameModule getModuleQname() {
+ return moduleQname;
+ }
+
+ public void setModuleQname(final QNameModule moduleQname) {
+ this.moduleQname = moduleQname;
+ }
+
+ public String getLocalName() {
+ return localName;
+ }
+
+ public void setLocalName(final String localName) {
+ this.localName = localName;
+ }
+
+ // FIXME: check also predicates ...
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof QNameWithPredicateBuilder)) {
+ return false;
+ }
+ final QNameWithPredicateBuilder other = (QNameWithPredicateBuilder) obj;
+ if (localName == null) {
+ if (other.localName != null) {
+ return false;
+ }
+ } else if (!localName.equals(other.localName)) {
+ return false;
+ }
+ return moduleQname.equals(other.moduleQname);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+
+ if (moduleQname != null) {
+ sb.append("(" + moduleQname.getNamespace());
+ sb.append("?revision=" + moduleQname.getRevision());
+ sb.append(")");
+ }
+
+ sb.append(localName);
+
+ for (final QNamePredicate predicate : qnamePredicates) {
+ sb.append(predicate);
+ }
+
+ return sb.toString();
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+final class QNameWithPredicateImpl implements Immutable, Serializable,
+ QNameWithPredicate {
+
+ private static final long serialVersionUID = 1L;
+
+ private final LinkedList<QNamePredicate> qnamePredicates;
+ private final QNameModule moduleQname;
+ private final String localName;
+
+ public QNameWithPredicateImpl(final QNameModule moduleQname, final String localName,
+ final LinkedList<QNamePredicate> qnamePredicates) {
+ this.moduleQname = moduleQname;
+ this.localName = localName;
+ this.qnamePredicates = qnamePredicates;
+ }
+
+ @Override
+ public LinkedList<QNamePredicate> getQNamePredicates() {
+ return qnamePredicates;
+ }
+
+ @Override
+ public QNameModule getModuleQname() {
+ return moduleQname;
+ }
+
+ @Override
+ public String getLocalName() {
+ return localName;
+ }
+
+ @Override
+ public QName getQName() {
+ return QName.create(moduleQname, localName);
+ }
+
+ // FIXME: check also predicates ...
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof QNameWithPredicateImpl)) {
+ return false;
+ }
+ final QNameWithPredicateImpl other = (QNameWithPredicateImpl) obj;
+ if (localName == null) {
+ if (other.localName != null) {
+ return false;
+ }
+ } else if (!localName.equals(other.localName)) {
+ return false;
+ }
+ return moduleQname.equals(other.moduleQname);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+
+ if (moduleQname != null) {
+ sb.append("(" + moduleQname.getNamespace());
+ sb.append("?revision=" + moduleQname.getRevision());
+ sb.append(")");
+ }
+
+ sb.append(localName);
+
+ for (final QNamePredicate predicate : qnamePredicates) {
+ sb.append(predicate);
+ }
+
+ return sb.toString();
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest {
+
+ private static SchemaContext context;
+ private static Module valModule;
+ private static QNameModule valModuleQname;
+ private static LeafRefContext rootLeafRefContext;
+ public static TipProducingDataTree inMemoryDataTree;
+
+ private static QName odl;
+ private static QName project;
+ private static QName name;
+ private static QName desc;
+ private static QName lead;
+ private static QName owner;
+ private static QName odlContributor;
+ private static QName contributor;
+ private static QName odlProjectName;
+ private static QName odlProjectDesc;
+ private static QName login;
+ private static QName contributorName;
+ private static QName l1;
+ private static QName l2;
+ private static QName con1;
+ private static QName ch1;
+ private static QName ch2;
+ private static QName leafrefInChoice;
+ private static QName listInChoice;
+
+ private static QName leafrefInChoiceToChoice;
+ private static QName con3;
+ private static QName list3InChoice;
+ private static QName l3;
+ private static QName choiceInCon3;
+
+ private static QName listInChoiceKey;
+ private static QName k;
+
+ private static QName leafrefLeafList;
+
+ private static final Logger LOG = LoggerFactory.getLogger("");
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ static {
+ BasicConfigurator.configure();
+ }
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException,
+ YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+ initSchemaContext();
+
+ initLeafRefContext();
+
+ initQnames();
+
+ initDataTree();
+
+ }
+
+ private static void initSchemaContext() throws URISyntaxException,
+ IOException, YangSyntaxErrorException {
+ final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+ .getResource("/leafref-validation/leafref-validation.yang")
+ .toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ context = parser.parseFile(resourceFile, resourceDir);
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-validation")) {
+ valModule = module;
+ }
+ }
+
+ valModuleQname = valModule.getQNameModule();
+ }
+
+ private static void initLeafRefContext() throws IOException,
+ LeafRefYangSyntaxErrorException {
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ private static void initQnames() {
+ odl = QName.create(valModuleQname, "odl-project");
+ project = QName.create(valModuleQname, "project");
+ name = QName.create(valModuleQname, "name");
+ desc = QName.create(valModuleQname, "desc");
+ lead = QName.create(valModuleQname, "project-lead");
+ owner = QName.create(valModuleQname, "project-owner");
+
+ odlContributor = QName.create(valModuleQname, "odl-contributor");
+ contributor = QName.create(valModuleQname, "contributor");
+ odlProjectName = QName.create(valModuleQname, "odl-project-name");
+ login = QName.create(valModuleQname, "login");
+ contributorName = QName.create(valModuleQname, "contributor-name");
+
+ con1 = QName.create(valModuleQname, "con1");
+ l1 = QName.create(valModuleQname, "l1");
+ l2 = QName.create(valModuleQname, "l2");
+ odlProjectDesc = QName.create(valModuleQname, "odl-project-desc");
+
+ ch1 = QName.create(valModuleQname, "ch1");
+ ch2 = QName.create(valModuleQname, "ch2");
+ leafrefInChoice = QName.create(valModuleQname, "leafref-in-choice");
+ listInChoice = QName.create(valModuleQname, "list-in-choice");
+
+ leafrefInChoiceToChoice = QName.create(valModuleQname,
+ "leafref-in-choice-to-choice");
+ con3 = QName.create(valModuleQname, "con3");
+ list3InChoice = QName.create(valModuleQname, "list3-in-choice");
+ l3 = QName.create(valModuleQname, "l3");
+ choiceInCon3 = QName.create(valModuleQname, "choice-in-con3");
+
+ listInChoiceKey = QName.create(valModuleQname, "list-in-choice-key");
+ k = QName.create(valModuleQname, "k");
+
+ leafrefLeafList = QName.create(valModuleQname, "leafref-leaf-list");
+
+ }
+
+ private static void initDataTree() {
+ inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(context);
+
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+
+ final ContainerSchemaNode odlProjContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odl);
+
+ final ContainerNode odlProjectContainer = createOdlContainer(odlProjContSchemaNode);
+
+ final YangInstanceIdentifier path = YangInstanceIdentifier.of(odl);
+ initialDataTreeModification.write(path, odlProjectContainer);
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(initialDataTreeModification);
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ }
+
+ @Test
+ public void dataTreeCanditateValidationTest() {
+ write();
+
+ write2();
+
+ delete();
+
+ writeContributors();
+
+ writeMapEntry();
+
+ writeIntoMapEntry();
+ }
+
+ private void writeContributors() {
+
+ final ContainerSchemaNode contributorContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odlContributor);
+
+ final ContainerNode contributorContainer = createBasicContributorContainer(contributorContSchemaNode);
+
+ final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+ .of(odlContributor);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(contributorPath, contributorContainer);
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write of contributors: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(3, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write of contributors: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+
+ }
+
+ private void writeIntoMapEntry() {
+
+ final Map<QName, Object> keys = new HashMap<QName, Object>();
+ keys.put(name, "New Project");
+ final NodeIdentifierWithPredicates mapEntryPath = new NodeIdentifierWithPredicates(
+ project, keys);
+
+ final YangInstanceIdentifier leaderPath = YangInstanceIdentifier.of(odl)
+ .node(project).node(mapEntryPath).node(lead);
+
+ final LeafNode<String> leader = ImmutableNodes.leafNode(lead,
+ "Updated leader");
+
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(leaderPath, leader);
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write into map entry (update of leader name): ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(1, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write into map entry (update of leader name): ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+
+ }
+
+ private void writeMapEntry() {
+
+ final Map<QName, Object> keys = new HashMap<QName, Object>();
+ keys.put(name, "New Project");
+ final NodeIdentifierWithPredicates mapEntryPath = new NodeIdentifierWithPredicates(
+ project, keys);
+
+ final YangInstanceIdentifier newOdlProjectMapEntryPath = YangInstanceIdentifier
+ .of(odl).node(project).node(mapEntryPath);
+
+ final ContainerSchemaNode odlProjContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odl);
+ final ListSchemaNode projListSchemaNode = (ListSchemaNode) odlProjContSchemaNode
+ .getDataChildByName(project);
+ final MapEntryNode newProjectMapEntry = createProjectListEntry("New Project",
+ "New Project description ...", "Leader of New Project",
+ "Owner of New Project", projListSchemaNode);
+
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(newOdlProjectMapEntryPath, newProjectMapEntry);
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before map entry write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(2, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After map entry write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+
+ }
+
+ private void write() {
+
+ final ContainerSchemaNode contributorContSchemaNode = (ContainerSchemaNode) valModule
+ .getDataChildByName(odlContributor);
+
+ final ContainerNode contributorContainer = createContributorContainer(contributorContSchemaNode);
+
+ final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+ .of(odlContributor);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(contributorPath, contributorContainer);
+
+ writeModification.write(YangInstanceIdentifier.of(l1),
+ ImmutableNodes.leafNode(l1, "Leafref l1 under the root"));
+ writeModification
+ .write(YangInstanceIdentifier.of(l2), ImmutableNodes.leafNode(
+ l2, "Leafref target l2 under the root"));
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(12, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+ }
+
+ private void write2() {
+
+ final ContainerSchemaNode odlCon = (ContainerSchemaNode) valModule
+ .getDataChildByName(odl);
+ final ContainerSchemaNode con1Con = (ContainerSchemaNode) odlCon
+ .getDataChildByName(con1);
+ final LeafNode<String> l1Leaf = ImmutableNodes.leafNode(l1, "l1 value");
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+ .containerBuilder(con1Con);
+ containerBuilder.addChild(l1Leaf);
+ final ContainerNode con1Node = containerBuilder.build();
+
+ final YangInstanceIdentifier con1Path = YangInstanceIdentifier.of(odl).node(
+ con1);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(con1Path, con1Node);
+
+ final ChoiceNode choiceNode = createChoiceNode();
+ final YangInstanceIdentifier choicePath = YangInstanceIdentifier.of(odl)
+ .node(ch1);
+ writeModification.write(choicePath, choiceNode);
+
+ final ContainerNode con3Node = createCon3Node();
+ final YangInstanceIdentifier con3Path = YangInstanceIdentifier.of(odl).node(
+ con3);
+ writeModification.write(con3Path, con3Node);
+
+ final LeafSetNode leafListNode = createLeafRefLeafListNode();
+ final YangInstanceIdentifier leafListPath = YangInstanceIdentifier.of(odl)
+ .node(leafrefLeafList);
+ writeModification.write(leafListPath, leafListNode);
+
+ final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before write2: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(writeContributorsCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write2: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ }
+
+ private LeafSetNode createLeafRefLeafListNode() {
+
+ final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders
+ .leafSetBuilder();
+ leafSetBuilder.withNodeIdentifier(new NodeIdentifier(leafrefLeafList));
+
+ leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k1"));
+ leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k2"));
+ leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k3"));
+
+ return leafSetBuilder.build();
+ }
+
+ private ContainerNode createCon3Node() {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder = Builders
+ .mapBuilder();
+ mapBuilder.withNodeIdentifier(new NodeIdentifier(list3InChoice));
+
+ mapBuilder.addChild(createList3Entry("k1", "val1", "valA", "valX"));
+ mapBuilder.addChild(createList3Entry("k2", "val2", "valB", "valY"));
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choiceBuilder = Builders
+ .choiceBuilder();
+ choiceBuilder.withNodeIdentifier(new NodeIdentifier(choiceInCon3));
+
+ choiceBuilder.addChild(mapBuilder.build());
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+ .containerBuilder();
+ containerBuilder.withNodeIdentifier(new NodeIdentifier(con3));
+
+ containerBuilder.addChild(choiceBuilder.build());
+
+ return containerBuilder.build();
+ }
+
+ private MapEntryNode createList3Entry(final String kVal, final String l3Val1,
+ final String l3Val2, final String l3Val3) {
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = Builders
+ .mapEntryBuilder();
+ mapEntryBuilder.withNodeIdentifier(new NodeIdentifierWithPredicates(
+ list3InChoice, k, kVal));
+
+ final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders
+ .leafSetBuilder();
+ leafSetBuilder.withNodeIdentifier(new NodeIdentifier(l3));
+
+ leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val1));
+ leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val2));
+ leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val3));
+
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(k, kVal));
+ mapEntryBuilder.addChild(leafSetBuilder.build());
+
+ return mapEntryBuilder.build();
+ }
+
+ private LeafSetEntryNode<Object> createLeafSetEntry(final QName qname, final String val) {
+ final NormalizedNodeAttrBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder = Builders
+ .leafSetEntryBuilder();
+ leafSetEntryBuilder.withNodeIdentifier(new NodeWithValue(qname, val));
+ leafSetEntryBuilder.withValue(val);
+ return leafSetEntryBuilder.build();
+ }
+
+ private ChoiceNode createChoiceNode() {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> listInChoiceBuilder = Builders
+ .mapBuilder();
+ listInChoiceBuilder
+ .withNodeIdentifier(new NodeIdentifier(listInChoice));
+
+ listInChoiceBuilder.addChild(createListInChoiceEntry("key1",
+ "leafref-in-choice value", "val1"));
+ listInChoiceBuilder.addChild(createListInChoiceEntry("key2",
+ "l1 value", "val2"));
+ listInChoiceBuilder.addChild(createListInChoiceEntry("key3",
+ "l1 value", "val3"));
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choice2Builder = Builders
+ .choiceBuilder();
+ choice2Builder.withNodeIdentifier(new NodeIdentifier(ch2));
+
+ choice2Builder.addChild(listInChoiceBuilder.build());
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choiceBuilder = Builders
+ .choiceBuilder();
+ choiceBuilder.withNodeIdentifier(new NodeIdentifier(ch1));
+ choiceBuilder.addChild(choice2Builder.build());
+
+ return choiceBuilder.build();
+ }
+
+ private MapEntryNode createListInChoiceEntry(final String keyVal,
+ final String leafrefInChoiceVal, final String leafrefInChoiceToChoiceVal) {
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = Builders
+ .mapEntryBuilder();
+
+ mapEntryBuilder.withNodeIdentifier(new NodeIdentifierWithPredicates(
+ listInChoice, listInChoiceKey, keyVal));
+
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(listInChoiceKey,
+ keyVal));
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(leafrefInChoice,
+ leafrefInChoiceVal));
+ mapEntryBuilder.addChild(ImmutableNodes.leafNode(
+ leafrefInChoiceToChoice, leafrefInChoiceToChoiceVal));
+
+ return mapEntryBuilder.build();
+ }
+
+ private void delete() {
+
+ final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+ .of(odlContributor);
+ final DataTreeModification delete = inMemoryDataTree.takeSnapshot()
+ .newModification();
+ delete.delete(contributorPath);
+
+ final DataTreeCandidate deleteContributorsCanditate = inMemoryDataTree
+ .prepare(delete);
+
+ LOG.debug("*************************");
+ LOG.debug("Before delete: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(deleteContributorsCanditate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(deleteContributorsCanditate);
+
+ LOG.debug("*************************");
+ LOG.debug("After delete: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ }
+
+ private ContainerNode createContributorContainer(
+ final ContainerSchemaNode contributorContSchemaNode) {
+
+ final ListSchemaNode contributorListSchemaNode = (ListSchemaNode) contributorContSchemaNode
+ .getDataChildByName(contributor);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contributorContainerBldr = Builders
+ .containerBuilder(contributorContSchemaNode);
+
+ final MapNode contributorMap = createContributorList(contributorListSchemaNode);
+ contributorContainerBldr.addChild(contributorMap);
+
+ final ContainerNode contributorContainer = contributorContainerBldr.build();
+
+ return contributorContainer;
+
+ }
+
+ private MapNode createContributorList(
+ final ListSchemaNode contributorListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> contributorMapBldr = Builders
+ .mapBuilder(contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry1 = createContributorListEntry(
+ "Leader of Yangtools", "Yangtools Leader name", "Yangtools",
+ "Yangtools description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry2 = createContributorListEntry(
+ "Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
+ "MD-SAL description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry3 = createContributorListEntry(
+ "Leader of Controller", "Controller Leader name", "Controller",
+ "Controller description ...", contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry4 = createContributorListEntry("jdoe",
+ "John Doe", "MD-SAL", "Yangtools description ...",
+ contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry5 = createContributorListEntry("foo",
+ "foo name", "Controller", "MD-SAL description ...",
+ contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry6 = createContributorListEntry("bar",
+ "bar name", "Yangtools", "Controller description ...",
+ contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry7 = createContributorListEntry("baz",
+ "baz name", "Unknown Project",
+ "Unknown Project description ...", contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry8 = createContributorListEntry("pk",
+ "pk name", "Unknown Project 2", "Controller description ...",
+ contributorListSchemaNode);
+
+ contributorMapBldr.addChild(contributorMapEntry1);
+ contributorMapBldr.addChild(contributorMapEntry2);
+ contributorMapBldr.addChild(contributorMapEntry3);
+ contributorMapBldr.addChild(contributorMapEntry4);
+ contributorMapBldr.addChild(contributorMapEntry5);
+ contributorMapBldr.addChild(contributorMapEntry6);
+ contributorMapBldr.addChild(contributorMapEntry7);
+ contributorMapBldr.addChild(contributorMapEntry8);
+
+ final MapNode contributorMap = contributorMapBldr.build();
+
+ return contributorMap;
+
+ }
+
+ private MapEntryNode createContributorListEntry(final String loginVal,
+ final String contributorNameVal, final String odlProjectNameVal,
+ final String odlProjectDescVal, final ListSchemaNode contributorListSchemaNode) {
+
+ final LeafNode<String> loginLeaf = ImmutableNodes.leafNode(login, loginVal);
+ final LeafNode<String> contributorNameLeaf = ImmutableNodes.leafNode(
+ contributorName, contributorNameVal);
+ final LeafNode<String> odlProjectNameLeafRef = ImmutableNodes.leafNode(
+ odlProjectName, odlProjectNameVal);
+ final LeafNode<String> odlProjectDescLeafRef = ImmutableNodes.leafNode(
+ odlProjectDesc, odlProjectDescVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> contributorMapEntryBldr = Builders
+ .mapEntryBuilder(contributorListSchemaNode);
+
+ contributorMapEntryBldr.addChild(loginLeaf);
+ contributorMapEntryBldr.addChild(contributorNameLeaf);
+ contributorMapEntryBldr.addChild(odlProjectNameLeafRef);
+ contributorMapEntryBldr.addChild(odlProjectDescLeafRef);
+
+ final MapEntryNode contributorMapEntry = contributorMapEntryBldr.build();
+
+ return contributorMapEntry;
+ }
+
+ private static ContainerNode createOdlContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode projListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(project);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> odlProjectContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode projectMap = createProjectList(projListSchemaNode);
+ odlProjectContainerBldr.addChild(projectMap);
+
+ final ContainerNode odlProjectContainer = odlProjectContainerBldr.build();
+
+ return odlProjectContainer;
+ }
+
+ private static MapNode createProjectList(final ListSchemaNode projListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> projectMapBldr = Builders
+ .mapBuilder(projListSchemaNode);
+
+ final MapEntryNode projMapEntry1 = createProjectListEntry("Yangtools",
+ "Yangtools description ...", "Leader of Yangtools",
+ "Owner of Yangtools", projListSchemaNode);
+ final MapEntryNode projMapEntry2 = createProjectListEntry("MD-SAL",
+ "MD-SAL description ...", "Leader of MD-SAL",
+ "Owner of MD-SAL", projListSchemaNode);
+ final MapEntryNode projMapEntry3 = createProjectListEntry("Controller",
+ "Controller description ...", "Leader of Controller",
+ "Owner of Controller", projListSchemaNode);
+
+ projectMapBldr.addChild(projMapEntry1);
+ projectMapBldr.addChild(projMapEntry2);
+ projectMapBldr.addChild(projMapEntry3);
+
+ final MapNode projectMap = projectMapBldr.build();
+
+ return projectMap;
+ }
+
+ private static MapEntryNode createProjectListEntry(final String nameVal,
+ final String descVal, final String leadVal, final String ownerVal,
+ final ListSchemaNode projListSchemaNode) {
+
+ final LeafNode<String> nameLeaf = ImmutableNodes.leafNode(name, nameVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+ final LeafNode<String> leadLeafRef = ImmutableNodes.leafNode(lead, leadVal);
+ final LeafNode<String> ownerLeafRef = ImmutableNodes
+ .leafNode(owner, ownerVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> projMapEntryBldr = Builders
+ .mapEntryBuilder(projListSchemaNode);
+
+ projMapEntryBldr.addChild(nameLeaf);
+ projMapEntryBldr.addChild(descLeaf);
+ projMapEntryBldr.addChild(leadLeafRef);
+ projMapEntryBldr.addChild(ownerLeafRef);
+ final MapEntryNode projMapEntry = projMapEntryBldr.build();
+
+ return projMapEntry;
+ }
+
+ private ContainerNode createBasicContributorContainer(
+ final ContainerSchemaNode contributorContSchemaNode) {
+
+ final ListSchemaNode contributorListSchemaNode = (ListSchemaNode) contributorContSchemaNode
+ .getDataChildByName(contributor);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contributorContainerBldr = Builders
+ .containerBuilder(contributorContSchemaNode);
+
+ final MapNode contributorMap = createBasicContributorList(contributorListSchemaNode);
+ contributorContainerBldr.addChild(contributorMap);
+
+ final ContainerNode contributorContainer = contributorContainerBldr.build();
+
+ return contributorContainer;
+
+ }
+
+ private MapNode createBasicContributorList(
+ final ListSchemaNode contributorListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> contributorMapBldr = Builders
+ .mapBuilder(contributorListSchemaNode);
+
+ final MapEntryNode contributorMapEntry1 = createContributorListEntry(
+ "Leader of Yangtools", "Yangtools Leader name", "Yangtools",
+ "Yangtools description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry2 = createContributorListEntry(
+ "Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
+ "MD-SAL description ...", contributorListSchemaNode);
+ final MapEntryNode contributorMapEntry3 = createContributorListEntry(
+ "Leader of Controller", "Controller Leader name", "Controller",
+ "Controller description ...", contributorListSchemaNode);
+
+ contributorMapBldr.addChild(contributorMapEntry1);
+ contributorMapBldr.addChild(contributorMapEntry2);
+ contributorMapBldr.addChild(contributorMapEntry3);
+
+ final MapNode contributorMap = contributorMapBldr.build();
+
+ return contributorMap;
+
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest2 {
+
+ private static SchemaContext context;
+ private static Module mainModule;
+ private static QNameModule rootModuleQname;
+ private static LeafRefContext rootLeafRefContext;
+ public static TipProducingDataTree inMemoryDataTree;
+
+ private static QName chips;
+ private static QName chip;
+ private static QName devType;
+ private static QName chipDesc;
+
+ private static QName devices;
+ private static QName device;
+ private static QName typeChoice;
+ private static QName typeText;
+ private static QName devDesc;
+ private static QName sn;
+ private static QName defaultIp;
+
+ private static QName deviceTypeStr;
+ private static QName deviceType;
+ private static QName type;
+ private static QName desc;
+
+ private static final Logger LOG = LoggerFactory.getLogger("");
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ static {
+ BasicConfigurator.configure();
+ }
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException,
+ YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+
+ initSchemaContext();
+ initLeafRefContext();
+ initQnames();
+ initDataTree();
+ }
+
+ @Test
+ public void dataTreeCanditateValidationTest2() {
+
+ writeDevices();
+ }
+
+ private static void writeDevices() {
+
+ final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(devices);
+
+ final ContainerNode devicesContainer = createDevicesContainer(devicesContSchemaNode);
+
+ final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(devicesPath, devicesContainer);
+
+ final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before writeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeDevicesCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+
+ assertEquals(4, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(writeDevicesCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After write: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+ }
+
+ private static void initQnames() {
+
+ chips = QName.create(rootModuleQname, "chips");
+ chip = QName.create(rootModuleQname, "chip");
+ devType = QName.create(rootModuleQname, "dev_type");
+ chipDesc = QName.create(rootModuleQname, "chip_desc");
+
+ devices = QName.create(rootModuleQname, "devices");
+ device = QName.create(rootModuleQname, "device");
+ typeText = QName.create(rootModuleQname, "type_text");
+ devDesc = QName.create(rootModuleQname, "dev_desc");
+ sn = QName.create(rootModuleQname, "sn");
+ defaultIp = QName.create(rootModuleQname, "default_ip");
+
+ deviceTypeStr = QName.create(rootModuleQname, "device_types");
+ deviceType = QName.create(rootModuleQname, "device_type");
+ type = QName.create(rootModuleQname, "type");
+ desc = QName.create(rootModuleQname, "desc");
+ }
+
+ private static void initSchemaContext() throws URISyntaxException,
+ IOException, YangSyntaxErrorException {
+
+ final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+ .getResource("/leafref-validation/leafref-validation2.yang")
+ .toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ context = parser.parseFile(resourceFile, resourceDir);
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-validation2")) {
+ mainModule = module;
+ }
+ }
+
+ rootModuleQname = mainModule.getQNameModule();
+ }
+
+ private static void initDataTree() {
+
+ inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(context);
+
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+
+ final ContainerSchemaNode chipsListContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(chips);
+ final ContainerNode chipsContainer = createChipsContainer(chipsListContSchemaNode);
+ final YangInstanceIdentifier path1 = YangInstanceIdentifier.of(chips);
+ initialDataTreeModification.write(path1, chipsContainer);
+
+ final ContainerSchemaNode devTypesListContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(deviceTypeStr);
+ final ContainerNode deviceTypesContainer = createDevTypeStrContainer(devTypesListContSchemaNode);
+ final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
+ initialDataTreeModification.write(path2, deviceTypesContainer);
+
+ final DataTreeCandidate writeChipsCandidate = inMemoryDataTree
+ .prepare(initialDataTreeModification);
+
+ inMemoryDataTree.commit(writeChipsCandidate);
+
+ System.out.println(inMemoryDataTree.toString());
+ }
+
+ private static void initLeafRefContext() throws IOException,
+ LeafRefYangSyntaxErrorException {
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ private static ContainerNode createDevTypeStrContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode devTypeListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(deviceType);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devTypeContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devTypeMap = createDevTypeList(devTypeListSchemaNode);
+ devTypeContainerBldr.addChild(devTypeMap);
+
+ return devTypeContainerBldr.build();
+ }
+
+ private static MapNode createDevTypeList(
+ final ListSchemaNode devTypeListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devTypeMapBldr = Builders
+ .mapBuilder(devTypeListSchemaNode);
+
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_1",
+ "typedesc1", devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_2",
+ "typedesc2", devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_3",
+ "typedesc3", devTypeListSchemaNode));
+
+ return devTypeMapBldr.build();
+ }
+
+ private static MapEntryNode createDevTypeListEntry(final String typeVal,
+ final String descVal, final ListSchemaNode devTypeListSchemaNode) {
+
+ final LeafNode<String> typeLeaf = ImmutableNodes.leafNode(type, typeVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devTypeMapEntryBldr = Builders
+ .mapEntryBuilder(devTypeListSchemaNode);
+
+ devTypeMapEntryBldr.addChild(typeLeaf);
+ devTypeMapEntryBldr.addChild(descLeaf);
+
+ return devTypeMapEntryBldr.build();
+ }
+
+ private static ContainerNode createChipsContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode chipsListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(chip);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> chipsContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode chipsMap = createChipsList(chipsListSchemaNode);
+ chipsContainerBldr.addChild(chipsMap);
+
+ return chipsContainerBldr.build();
+ }
+
+ private static MapNode createChipsList(final ListSchemaNode chipsListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> chipsMapBldr = Builders
+ .mapBuilder(chipsListSchemaNode);
+
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_1", "desc1",
+ chipsListSchemaNode));
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_2", "desc2",
+ chipsListSchemaNode));
+
+ return chipsMapBldr.build();
+ }
+
+ private static MapEntryNode createChipsListEntry(final String devTypeVal,
+ final String chipDescVal, final ListSchemaNode chipsListSchemaNode) {
+
+ final LeafNode<String> devTypeLeaf = ImmutableNodes.leafNode(devType,
+ devTypeVal);
+ final LeafNode<String> chipDescLeaf = ImmutableNodes.leafNode(chipDesc,
+ chipDescVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> chipsMapEntryBldr = Builders
+ .mapEntryBuilder(chipsListSchemaNode);
+
+ chipsMapEntryBldr.addChild(devTypeLeaf);
+ chipsMapEntryBldr.addChild(chipDescLeaf);
+
+ return chipsMapEntryBldr.build();
+ }
+
+ private static ContainerNode createDevicesContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(device);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devicesMap = createDeviceList(devicesListSchemaNode);
+ devicesContainerBldr.addChild(devicesMap);
+
+ return devicesContainerBldr.build();
+ }
+
+ private static MapNode createDeviceList(final ListSchemaNode deviceListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders
+ .mapBuilder(deviceListSchemaNode);
+
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_1",
+ "typedesc1", 123456, "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_2",
+ "typedesc2", 123457, "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_2",
+ "typedesc3", 123457, "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type_1",
+ "typedesc2", 123458, "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("unknown", "unknown",
+ 123457, "192.168.0.1", deviceListSchemaNode));
+
+ return devicesMapBldr.build();
+ }
+
+ private static MapEntryNode createDeviceListEntry(final String typeTextVal,
+ final String descVal, final int snVal, final String defaultIpVal,
+ final ListSchemaNode devicesListSchemaNode) {
+
+ final LeafNode<String> typeTextLeaf = ImmutableNodes.leafNode(typeText,
+ typeTextVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(devDesc, descVal);
+ final LeafNode<Integer> snValLeaf = ImmutableNodes.leafNode(sn, snVal);
+ final LeafNode<String> defaultIpLeaf = ImmutableNodes.leafNode(defaultIp,
+ defaultIpVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devicesMapEntryBldr = Builders
+ .mapEntryBuilder(devicesListSchemaNode);
+
+ devicesMapEntryBldr.addChild(typeTextLeaf);
+ devicesMapEntryBldr.addChild(descLeaf);
+ devicesMapEntryBldr.addChild(snValLeaf);
+ devicesMapEntryBldr.addChild(defaultIpLeaf);
+
+ return devicesMapEntryBldr.build();
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest3 {
+
+ private static SchemaContext context;
+ private static Module mainModule;
+ private static QNameModule rootModuleQname;
+ private static LeafRefContext rootLeafRefContext;
+ public static TipProducingDataTree inMemoryDataTree;
+
+ private static QName chips;
+ private static QName chip;
+ private static QName devType;
+ private static QName chipDesc;
+
+ private static QName devices;
+ private static QName device;
+ private static QName typeText1;
+ private static QName typeText2;
+ private static QName typeText3;
+ private static QName devDesc;
+ private static QName sn;
+ private static QName defaultIp;
+
+ private static QName deviceTypeStr;
+ private static QName deviceType;
+ private static QName type1;
+ private static QName type2;
+ private static QName type3;
+ private static QName desc;
+
+ private static final Logger LOG = LoggerFactory.getLogger("");
+ private static final String NEW_LINE = System.getProperty("line.separator");
+
+ static {
+ BasicConfigurator.configure();
+ }
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException,
+ YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+
+ initSchemaContext();
+ initLeafRefContext();
+ initQnames();
+ initDataTree();
+ }
+
+ @Test
+ public void dataTreeCanditateValidationTest2() {
+
+ writeDevices();
+
+ mergeDevices();
+ }
+
+ private static void writeDevices() {
+
+ final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(devices);
+
+ final ContainerNode devicesContainer = createDevicesContainer(devicesContSchemaNode);
+
+ final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+ final DataTreeModification writeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ writeModification.write(devicesPath, devicesContainer);
+
+ final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree
+ .prepare(writeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before writeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(writeDevicesCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ assertTrue(exception);
+
+ inMemoryDataTree.commit(writeDevicesCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After writeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+ }
+
+ private static void mergeDevices() {
+
+ final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(devices);
+
+ final ContainerNode devicesContainer = createDevices2Container(devicesContSchemaNode);
+
+ final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+ final DataTreeModification mergeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+ // mergeModification.write(devicesPath, devicesContainer);
+ mergeModification.merge(devicesPath, devicesContainer);
+
+ final DataTreeCandidate mergeDevicesCandidate = inMemoryDataTree
+ .prepare(mergeModification);
+
+ LOG.debug("*************************");
+ LOG.debug("Before mergeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ boolean exception = false;
+ try {
+ LeafRefValidatation.validate(mergeDevicesCandidate, rootLeafRefContext);
+ } catch (final LeafRefDataValidationFailedException e) {
+ LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+ // :TODO verify errors count gz
+ assertEquals(6, e.getValidationsErrorsCount());
+ exception = true;
+ }
+
+ inMemoryDataTree.commit(mergeDevicesCandidate);
+
+ LOG.debug("*************************");
+ LOG.debug("After mergeDevices: ");
+ LOG.debug("*************************");
+ LOG.debug(inMemoryDataTree.toString());
+
+ assertTrue(exception);
+ }
+
+ private static void initQnames() {
+
+ chips = QName.create(rootModuleQname, "chips");
+ chip = QName.create(rootModuleQname, "chip");
+ devType = QName.create(rootModuleQname, "dev_type");
+ chipDesc = QName.create(rootModuleQname, "chip_desc");
+
+ devices = QName.create(rootModuleQname, "devices");
+ device = QName.create(rootModuleQname, "device");
+ typeText1 = QName.create(rootModuleQname, "type_text1");
+ typeText2 = QName.create(rootModuleQname, "type_text2");
+ typeText3 = QName.create(rootModuleQname, "type_text3");
+ devDesc = QName.create(rootModuleQname, "dev_desc");
+ sn = QName.create(rootModuleQname, "sn");
+ defaultIp = QName.create(rootModuleQname, "default_ip");
+
+ deviceTypeStr = QName.create(rootModuleQname, "device_types");
+ deviceType = QName.create(rootModuleQname, "device_type");
+ type1 = QName.create(rootModuleQname, "type1");
+ type2 = QName.create(rootModuleQname, "type2");
+ type3 = QName.create(rootModuleQname, "type3");
+ desc = QName.create(rootModuleQname, "desc");
+ }
+
+ private static void initSchemaContext() throws URISyntaxException,
+ IOException, YangSyntaxErrorException {
+
+ final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+ .getResource("/leafref-validation/leafref-validation3.yang")
+ .toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ context = parser.parseFile(resourceFile, resourceDir);
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-validation3")) {
+ mainModule = module;
+ }
+ }
+
+ rootModuleQname = mainModule.getQNameModule();
+ }
+
+ private static void initDataTree() {
+
+ inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+ inMemoryDataTree.setSchemaContext(context);
+
+ final DataTreeModification initialDataTreeModification = inMemoryDataTree
+ .takeSnapshot().newModification();
+
+ final ContainerSchemaNode chipsListContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(chips);
+ final ContainerNode chipsContainer = createChipsContainer(chipsListContSchemaNode);
+ final YangInstanceIdentifier path1 = YangInstanceIdentifier.of(chips);
+ initialDataTreeModification.write(path1, chipsContainer);
+
+ final ContainerSchemaNode devTypesListContSchemaNode = (ContainerSchemaNode) mainModule
+ .getDataChildByName(deviceTypeStr);
+ final ContainerNode deviceTypesContainer = createDevTypeStrContainer(devTypesListContSchemaNode);
+ final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
+ initialDataTreeModification.write(path2, deviceTypesContainer);
+
+ final DataTreeCandidate writeChipsCandidate = inMemoryDataTree
+ .prepare(initialDataTreeModification);
+
+ inMemoryDataTree.commit(writeChipsCandidate);
+
+ System.out.println(inMemoryDataTree.toString());
+ }
+
+ private static void initLeafRefContext() throws IOException,
+ LeafRefYangSyntaxErrorException {
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ private static ContainerNode createDevTypeStrContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode devTypeListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(deviceType);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devTypeContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devTypeMap = createDevTypeList(devTypeListSchemaNode);
+ devTypeContainerBldr.addChild(devTypeMap);
+
+ return devTypeContainerBldr.build();
+ }
+
+ private static MapNode createDevTypeList(
+ final ListSchemaNode devTypeListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devTypeMapBldr = Builders
+ .mapBuilder(devTypeListSchemaNode);
+
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_1",
+ "dev_type2_1", "dev_type3_1", "typedesc1",
+ devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_2",
+ "dev_type2_2", "dev_type3_2", "typedesc2",
+ devTypeListSchemaNode));
+ devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_3",
+ "dev_type2_3", "dev_type3_3", "typedesc3",
+ devTypeListSchemaNode));
+
+ return devTypeMapBldr.build();
+ }
+
+ private static MapEntryNode createDevTypeListEntry(final String type1Val,
+ final String type2Val, final String type3Val, final String descVal,
+ final ListSchemaNode devTypeListSchemaNode) {
+
+ final LeafNode<String> type1Leaf = ImmutableNodes.leafNode(type1, type1Val);
+ final LeafNode<String> type2Leaf = ImmutableNodes.leafNode(type2, type2Val);
+ final LeafNode<String> type3Leaf = ImmutableNodes.leafNode(type3, type3Val);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devTypeMapEntryBldr = Builders
+ .mapEntryBuilder(devTypeListSchemaNode);
+
+ devTypeMapEntryBldr.addChild(type1Leaf);
+ devTypeMapEntryBldr.addChild(type2Leaf);
+ devTypeMapEntryBldr.addChild(type3Leaf);
+ devTypeMapEntryBldr.addChild(descLeaf);
+
+ return devTypeMapEntryBldr.build();
+ }
+
+ private static ContainerNode createChipsContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode chipsListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(chip);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> chipsContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode chipsMap = createChipsList(chipsListSchemaNode);
+ chipsContainerBldr.addChild(chipsMap);
+
+ return chipsContainerBldr.build();
+ }
+
+ private static MapNode createChipsList(final ListSchemaNode chipsListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> chipsMapBldr = Builders
+ .mapBuilder(chipsListSchemaNode);
+
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_1", "desc1",
+ chipsListSchemaNode));
+ chipsMapBldr.addChild(createChipsListEntry("dev_type_2", "desc2",
+ chipsListSchemaNode));
+
+ return chipsMapBldr.build();
+ }
+
+ private static MapEntryNode createChipsListEntry(final String devTypeVal,
+ final String chipDescVal, final ListSchemaNode chipsListSchemaNode) {
+
+ final LeafNode<String> devTypeLeaf = ImmutableNodes.leafNode(devType,
+ devTypeVal);
+ final LeafNode<String> chipDescLeaf = ImmutableNodes.leafNode(chipDesc,
+ chipDescVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> chipsMapEntryBldr = Builders
+ .mapEntryBuilder(chipsListSchemaNode);
+
+ chipsMapEntryBldr.addChild(devTypeLeaf);
+ chipsMapEntryBldr.addChild(chipDescLeaf);
+
+ return chipsMapEntryBldr.build();
+ }
+
+ private static ContainerNode createDevicesContainer(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(device);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devicesMap = createDeviceList(devicesListSchemaNode);
+ devicesContainerBldr.addChild(devicesMap);
+
+ return devicesContainerBldr.build();
+ }
+
+ private static MapNode createDeviceList(final ListSchemaNode deviceListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders
+ .mapBuilder(deviceListSchemaNode);
+
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_1",
+ "dev_type2_1", "dev_type3_1", "typedesc1", 123456,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_2",
+ "dev_type2_2", "dev_type3_2", "typedesc1", 123457,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_1",
+ "dev_type2_2", "dev_type3_3", "typedesc2", 123458,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("unk11", "unk22",
+ "unk33", "unk_desc2", 123457, "192.168.0.1",
+ deviceListSchemaNode));
+
+ return devicesMapBldr.build();
+ }
+
+ private static ContainerNode createDevices2Container(
+ final ContainerSchemaNode container) {
+
+ final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container
+ .getDataChildByName(device);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+ .containerBuilder(container);
+
+ final MapNode devicesMap = createDevice2List(devicesListSchemaNode);
+ devicesContainerBldr.addChild(devicesMap);
+
+ return devicesContainerBldr.build();
+ }
+
+ private static MapNode createDevice2List(final ListSchemaNode deviceListSchemaNode) {
+
+ final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders
+ .mapBuilder(deviceListSchemaNode);
+
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3",
+ "dev_type2_3", "dev_type3_3", "typedesc3", 123459,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3",
+ "dev_type2_3", "dev_type3_3", "typedesc2", 123460,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3",
+ "dev_type2_2", "dev_type3_1", "typedesc1", 123461,
+ "192.168.0.1", deviceListSchemaNode));
+ devicesMapBldr.addChild(createDeviceListEntry("unk1", "unk2", "unk3",
+ "unk_desc", 123462, "192.168.0.1", deviceListSchemaNode));
+
+ return devicesMapBldr.build();
+ }
+
+ private static MapEntryNode createDeviceListEntry(final String type1TextVal,
+ final String type2TextVal, final String type3TextVal, final String descVal,
+ final int snVal, final String defaultIpVal, final ListSchemaNode devicesListSchemaNode) {
+
+ final LeafNode<String> typeText1Leaf = ImmutableNodes.leafNode(typeText1,
+ type1TextVal);
+ final LeafNode<String> typeText2Leaf = ImmutableNodes.leafNode(typeText2,
+ type2TextVal);
+ final LeafNode<String> typeText3Leaf = ImmutableNodes.leafNode(typeText3,
+ type3TextVal);
+ final LeafNode<String> descLeaf = ImmutableNodes.leafNode(devDesc, descVal);
+ final LeafNode<Integer> snValLeaf = ImmutableNodes.leafNode(sn, snVal);
+ final LeafNode<String> defaultIpLeaf = ImmutableNodes.leafNode(defaultIp,
+ defaultIpVal);
+
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devicesMapEntryBldr = Builders
+ .mapEntryBuilder(devicesListSchemaNode);
+
+ devicesMapEntryBldr.addChild(typeText1Leaf);
+ devicesMapEntryBldr.addChild(typeText2Leaf);
+ devicesMapEntryBldr.addChild(typeText3Leaf);
+ devicesMapEntryBldr.addChild(descLeaf);
+ devicesMapEntryBldr.addChild(snValLeaf);
+ devicesMapEntryBldr.addChild(defaultIpLeaf);
+
+ return devicesMapEntryBldr.build();
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContextUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class LeafRefContextTest {
+
+ private static SchemaContext context;
+ private static Module rootMod;
+ private static QNameModule root;
+ private static LeafRefContext rootLeafRefContext;
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException,
+ YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+
+ final File resourceFile = new File(
+ LeafRefContextTreeBuilderTest.class
+ .getResource(
+ "/leafref-context-test/correct-modules/leafref-test2.yang")
+ .toURI());
+
+ final File resourceDir = resourceFile.getParentFile();
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ context = parser.parseFile(resourceFile, resourceDir);
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("leafref-test2")) {
+ rootMod = module;
+ }
+ }
+
+ root = rootMod.getQNameModule();
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ @Test
+ public void test() {
+
+ final QName q1 = QName.create(root, "ref1");
+ final QName q2 = QName.create(root, "leaf1");
+ final QName q3 = QName.create(root, "cont1");
+ final QName q4 = QName.create(root, "cont2");
+ final QName q5 = QName.create(root, "list1");
+ final QName q6 = QName.create(root, "name");
+
+ final DataSchemaNode leafRefNode = rootMod.getDataChildByName(q1);
+ final DataSchemaNode targetNode = rootMod.getDataChildByName(q2);
+ final DataSchemaNode cont1Node = rootMod.getDataChildByName(q3);
+ final DataSchemaNode cont2Node = rootMod.getDataChildByName(q4);
+ final DataSchemaNode name1Node = ((DataNodeContainer) ((DataNodeContainer) rootMod
+ .getDataChildByName(q3)).getDataChildByName(q5))
+ .getDataChildByName(q6);
+
+ assertTrue(LeafRefContextUtils.isLeafRef(leafRefNode,
+ rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.isLeafRef(targetNode,
+ rootLeafRefContext));
+
+ assertTrue(LeafRefContextUtils.hasLeafRefChild(cont1Node,
+ rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.hasLeafRefChild(leafRefNode,
+ rootLeafRefContext));
+
+ assertTrue(LeafRefContextUtils.isReferencedByLeafRef(targetNode,
+ rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.isReferencedByLeafRef(leafRefNode,
+ rootLeafRefContext));
+
+ assertTrue(LeafRefContextUtils.hasChildReferencedByLeafRef(cont2Node,
+ rootLeafRefContext));
+ assertFalse(LeafRefContextUtils.hasChildReferencedByLeafRef(
+ leafRefNode, rootLeafRefContext));
+
+ Map<QName, LeafRefContext> leafRefs = LeafRefContextUtils
+ .getAllLeafRefsReferencingThisNode(name1Node,
+ rootLeafRefContext);
+ assertEquals(4, leafRefs.size());
+ leafRefs = LeafRefContextUtils.getAllLeafRefsReferencingThisNode(
+ leafRefNode, rootLeafRefContext);
+ assertTrue(leafRefs.isEmpty());
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContextUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class LeafRefContextTreeBuilderTest {
+
+ private static SchemaContext context;
+ private static Module impMod;
+ private static Module tstMod;
+ private static QNameModule imp;
+ private static QNameModule tst;
+ private static LeafRefContext rootLeafRefContext;
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException,
+ YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+ final File resourceFile = new File(
+ LeafRefContextTreeBuilderTest.class
+ .getResource(
+ "/leafref-context-test/correct-modules/leafref-test.yang")
+ .toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ context = parser.parseFile(resourceFile, resourceDir);
+
+ final Set<Module> modules = context.getModules();
+ for (final Module module : modules) {
+ if (module.getName().equals("import-mod")) {
+ impMod = module;
+ }
+ if (module.getName().equals("leafref-test")) {
+ tstMod = module;
+ }
+ }
+
+ imp = impMod.getQNameModule();
+ tst = tstMod.getQNameModule();
+
+ rootLeafRefContext = LeafRefContext.create(context);
+ }
+
+ @Test
+ public void buildLeafRefContextTreeTest1() {
+
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q3 = QName.create(tst, "project-lead");
+
+ final LeafRefContext leafRefCtx = rootLeafRefContext
+ .getReferencingChildByName(q1).getReferencingChildByName(q2)
+ .getReferencingChildByName(q3);
+
+ assertTrue(leafRefCtx.isReferencing());
+ assertNotNull(leafRefCtx.getLeafRefTargetPath());
+ assertFalse(leafRefCtx.getLeafRefTargetPath().isAbsolute());
+ assertNotNull(leafRefCtx.getAbsoluteLeafRefTargetPath());
+ assertTrue(leafRefCtx.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+ System.out.println();
+ System.out.println("******* Test 1 ************");
+ System.out.println("Original definition string:");
+ System.out.println(leafRefCtx.getLeafRefTargetPathString());
+ System.out.println("Parsed leafref path:");
+ System.out.println(leafRefCtx.getLeafRefTargetPath().toString());
+ System.out.println("Absolute leafref path:");
+ System.out
+ .println(leafRefCtx.getAbsoluteLeafRefTargetPath().toString());
+ }
+
+ @Test
+ public void buildLeafRefContextTreeTest2() {
+
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q4 = QName.create(tst, "project-lead2");
+
+ final LeafRefContext leafRefCtx2 = rootLeafRefContext
+ .getReferencingChildByName(q1).getReferencingChildByName(q2)
+ .getReferencingChildByName(q4);
+
+ assertTrue(leafRefCtx2.isReferencing());
+ assertNotNull(leafRefCtx2.getLeafRefTargetPath());
+ assertTrue(leafRefCtx2.getLeafRefTargetPath().isAbsolute());
+ assertNotNull(leafRefCtx2.getAbsoluteLeafRefTargetPath());
+ assertTrue(leafRefCtx2.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+ System.out.println();
+ System.out.println("******* Test 2 ************");
+ System.out.println("Original definition string2:");
+ System.out.println(leafRefCtx2.getLeafRefTargetPathString());
+ System.out.println("Parsed leafref path2:");
+ System.out.println(leafRefCtx2.getLeafRefTargetPath().toString());
+ System.out.println("Absolute leafref path2:");
+ System.out.println(leafRefCtx2.getAbsoluteLeafRefTargetPath()
+ .toString());
+ System.out.println();
+
+ }
+
+ @Test
+ public void buildLeafRefContextTreeXPathTest() {
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q5 = QName.create(tst, "ch1");
+ final QName q6 = QName.create(tst, "c1");
+ final QName q7 = QName.create(tst, "ch2");
+ final QName q8 = QName.create(tst, "l1");
+ final LeafRefContext leafRefCtx3 = rootLeafRefContext
+ .getReferencingChildByName(q1).getReferencingChildByName(q2)
+ .getReferencingChildByName(q5).getReferencingChildByName(q6)
+ .getReferencingChildByName(q7).getReferencingChildByName(q6)
+ .getReferencingChildByName(q8);
+
+ assertTrue(leafRefCtx3.isReferencing());
+ assertNotNull(leafRefCtx3.getLeafRefTargetPath());
+ assertFalse(leafRefCtx3.getLeafRefTargetPath().isAbsolute());
+ assertNotNull(leafRefCtx3.getAbsoluteLeafRefTargetPath());
+ assertTrue(leafRefCtx3.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+ System.out.println();
+ System.out.println("******* Test 3 ************");
+ System.out.println("Original definition string2:");
+ System.out.println(leafRefCtx3.getLeafRefTargetPathString());
+ System.out.println("Parsed leafref path2:");
+ System.out.println(leafRefCtx3.getLeafRefTargetPath().toString());
+ System.out.println("Absolute leafref path2:");
+ System.out.println(leafRefCtx3.getAbsoluteLeafRefTargetPath()
+ .toString());
+ System.out.println();
+ }
+
+ @Test
+ public void buildLeafRefContextTreeTest4() {
+ final QName q9 = QName.create(tst, "odl-project");
+ final QName q10 = QName.create(tst, "project");
+ final QName q11 = QName.create(tst, "name");
+
+ final LeafRefContext leafRefCtx4 = rootLeafRefContext
+ .getReferencedChildByName(q9).getReferencedChildByName(q10)
+ .getReferencedChildByName(q11);
+
+ assertNotNull(leafRefCtx4);
+ assertTrue(leafRefCtx4.isReferenced());
+ assertEquals(6, leafRefCtx4.getAllReferencedByLeafRefCtxs().size());
+
+ }
+
+ @Test
+ public void leafRefContextUtilsTest() {
+ final QName q1 = QName.create(tst, "odl-contributor");
+ final QName q2 = QName.create(tst, "contributor");
+ final QName q3 = QName.create(tst, "odl-project-name");
+
+ final LeafRefContext odlContrProjNameCtx = rootLeafRefContext
+ .getReferencingChildByName(q1).getReferencingChildByName(q2)
+ .getReferencingChildByName(q3);
+
+ final DataSchemaNode odlContrProjNameNode = ((DataNodeContainer) ((DataNodeContainer) tstMod
+ .getDataChildByName(q1)).getDataChildByName(q2))
+ .getDataChildByName(q3);
+
+ final LeafRefContext foundOdlContrProjNameCtx = LeafRefContextUtils
+ .getLeafRefReferencingContext(odlContrProjNameNode,
+ rootLeafRefContext);
+
+ assertNotNull(foundOdlContrProjNameCtx);
+ assertTrue(foundOdlContrProjNameCtx.isReferencing());
+ assertNotNull(foundOdlContrProjNameCtx.getLeafRefTargetPath());
+ assertEquals(odlContrProjNameCtx, foundOdlContrProjNameCtx);
+ }
+
+ @Test
+ public void leafRefContextUtilsTest2() {
+ final QName q1 = QName.create(tst, "odl-project");
+ final QName q2 = QName.create(tst, "project");
+ final QName q3 = QName.create(tst, "name");
+
+ final LeafRefContext leafRefCtx = rootLeafRefContext
+ .getReferencedChildByName(q1).getReferencedChildByName(q2)
+ .getReferencedChildByName(q3);
+
+ final DataSchemaNode odlProjNameNode = ((DataNodeContainer) ((DataNodeContainer) tstMod
+ .getDataChildByName(q1)).getDataChildByName(q2))
+ .getDataChildByName(q3);
+
+ LeafRefContext foundOdlProjNameCtx = LeafRefContextUtils
+ .getLeafRefReferencingContext(odlProjNameNode,
+ rootLeafRefContext);
+
+ assertNull(foundOdlProjNameCtx);
+
+ foundOdlProjNameCtx = LeafRefContextUtils
+ .getLeafRefReferencedByContext(odlProjNameNode,
+ rootLeafRefContext);
+
+ assertNotNull(foundOdlProjNameCtx);
+ assertTrue(foundOdlProjNameCtx.isReferenced());
+ assertFalse(foundOdlProjNameCtx.getAllReferencedByLeafRefCtxs()
+ .isEmpty());
+ assertEquals(6, foundOdlProjNameCtx.getAllReferencedByLeafRefCtxs()
+ .size());
+ assertEquals(leafRefCtx, foundOdlProjNameCtx);
+ }
+
+ @Test
+ public void leafRefContextUtilsTest3() {
+ final QName q16 = QName.create(tst, "con1");
+ final DataSchemaNode con1 = tstMod.getDataChildByName(q16);
+ final List<LeafRefContext> allLeafRefChilds = LeafRefContextUtils
+ .findAllLeafRefChilds(con1, rootLeafRefContext);
+
+ assertNotNull(allLeafRefChilds);
+ assertFalse(allLeafRefChilds.isEmpty());
+ assertEquals(4, allLeafRefChilds.size());
+
+ final QName q17 = QName.create(tst, "odl-contributor");
+ final DataSchemaNode odlContributorNode = tstMod.getDataChildByName(q17);
+ List<LeafRefContext> allChildsReferencedByLeafRef = LeafRefContextUtils
+ .findAllChildsReferencedByLeafRef(odlContributorNode,
+ rootLeafRefContext);
+
+ assertNotNull(allChildsReferencedByLeafRef);
+ assertFalse(allChildsReferencedByLeafRef.isEmpty());
+ assertEquals(1, allChildsReferencedByLeafRef.size());
+
+ allChildsReferencedByLeafRef = LeafRefContextUtils
+ .findAllChildsReferencedByLeafRef(con1, rootLeafRefContext);
+
+ assertNotNull(allChildsReferencedByLeafRef);
+ assertTrue(allChildsReferencedByLeafRef.isEmpty());
+
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void incorrectLeafRefPathTest() throws URISyntaxException,
+ IOException, YangSyntaxErrorException,
+ LeafRefYangSyntaxErrorException {
+ final File resourceFile = new File(getClass().getResource(
+ "/leafref-context-test/incorrect-modules/leafref-test.yang")
+ .toURI());
+ final File resourceDir = resourceFile.getParentFile();
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ final SchemaContext context = parser.parseFile(resourceFile, resourceDir);
+
+ LeafRefContext.create(context);
+
+ }
+
+}
--- /dev/null
+module import-mod {
+ namespace "pk.import";
+ prefix imp;
+
+ revision 2014-10-07 {
+ description
+ "Yang initial revision";
+ }
+
+}
--- /dev/null
+module leafref-test {
+ namespace "pk.test";
+ prefix tst;
+
+ import import-mod { prefix imp; revision-date 2014-10-07; }
+
+ revision 1999-09-09 {
+ description
+ "Yang initial revision";
+ }
+
+ container odl-contributor {
+ list contributor {
+ key "login";
+ leaf login {
+ type string;
+ }
+ leaf contributor-name {
+ type string;
+ }
+ leaf odl-project-name {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ }
+ list noleafref-contributor {
+ leaf foo {
+ type string;
+ }
+ }
+ }
+
+ container odl-project {
+ list project {
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf project-lead {
+ type leafref {
+ path "../../../tst:odl-contributor[imp:foo=current()/bar]/contributor[tst:odl-project-name
+ = current()/../imp:name][odl-project-name2 = current()/../../imp:name/tst:name2][imp:odl-project-name3
+ = current()/../../imp:name/imp:name2]/tst:login";
+ }
+ }
+ leaf project-lead2 {
+ type leafref {
+ path "/odl-contributor[foo=current()/bar]/contributor[odl-project-name
+ = current()/../name][odl-project-name2 = current()/../../name/name2][odl-project-name3
+ = current()/../../name/name2]/login";
+ }
+ }
+
+ choice ch1 {
+ case c1 {
+ choice ch2 {
+ case c1 {
+ leaf l1 {
+ type leafref {
+ path "../../con1/l1";
+ }
+ }
+ }
+ case c2 {
+ }
+ }
+ }
+ case c2 {
+ }
+ }
+ }
+ list noleafref-project {
+ leaf foo {
+ type string;
+ }
+ }
+ container con1 {
+ leaf l1 {
+ type empty;
+ }
+ }
+ }
+
+ container con1 {
+ container con2 {
+ container con3 {
+ leaf l1 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l2 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l3-noleafref {
+ type int16;
+ }
+ }
+ leaf l4 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l5-noleafref {
+ type int16;
+ }
+ }
+ leaf l6 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l7-noleafref {
+ type int16;
+ }
+ }
+
+ leaf l8 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+
+ container no-leafrefcontainer {
+ list no-leafreflist {
+ leaf bar {
+ type string;
+ }
+ }
+ container no-leafrefcontainer2 {
+ leaf baz {
+ type string;
+ }
+ }
+ }
+
+ container no-leafrefcontainer2 {
+ list no-leafreflist {
+ leaf bar {
+ type string;
+ }
+ }
+ container no-leafrefcontainer2 {
+ leaf baz {
+ type string;
+ }
+ }
+ }
+}
--- /dev/null
+module leafref-test2 {
+ namespace "gz.test";
+ prefix "main";
+
+ revision 2015-02-13 {
+ description "Initial revision";
+ }
+
+ leaf leaf1 {
+ type int16;
+ }
+
+ leaf ref1 {
+ type leafref {
+ path "../leaf1";
+ }
+ }
+
+ typedef low_int {
+ type int8 {
+ range 1..100;
+ }
+ }
+
+ container cont1 {
+
+ list list1 {
+ leaf name {
+ type string;
+ }
+ leaf id {
+ type int32;
+ }
+ leaf value {
+ type low_int;
+ }
+ leaf external {
+ type leafref {
+ path "../../../cont2/value";
+ }
+ }
+ }
+ }
+
+ container cont2 {
+ leaf value {
+ type decimal64 {
+ fraction-digits 4;
+ }
+ }
+ }
+
+ container cont3 {
+ container cont4 {
+ leaf l1 {
+ type leafref {
+ path "/cont1/list1/name";
+ }
+ }
+ leaf l2 {
+ type leafref {
+ path "../../../cont1/list1/name";
+ }
+ }
+ }
+ leaf l3 {
+ type leafref {
+ path "/cont1/list1/name";
+ }
+ }
+ leaf l4 {
+ type int32;
+ }
+ }
+
+ container cont5 {
+ leaf l5 {
+ type leafref {
+ path "/cont1/list1/name";
+ }
+ }
+ }
+}
--- /dev/null
+module leafref-test {
+ namespace "test";
+ prefix test;
+
+ container odl-contributor {
+ list contributor {
+ key "login";
+ leaf login {
+ type string;
+ }
+ leaf contributor-name {
+ type string;
+ }
+ leaf odl-project-name {
+ type leafref {
+ path ".../odl-project/project/name";
+ }
+ }
+ }
+ list noleafref-contributor {
+ leaf foo {
+ type string;
+ }
+ }
+ }
+
+ container odl-project {
+ list project {
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf project-lead {
+ type leafref {
+ path "/odl-contributor/contributor/login";
+ }
+ }
+ }
+ list noleafref-project {
+ leaf foo {
+ type string;
+ }
+ }
+ }
+
+ container con1 {
+ container con2 {
+ container con3 {
+ leaf l1 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l2 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l3-noleafref {
+ type int16;
+ }
+ }
+ leaf l4 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l5-noleafref {
+ type int16;
+ }
+ }
+ leaf l6 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+ leaf l7-noleafref {
+ type int16;
+ }
+ }
+
+ leaf l8 {
+ type leafref {
+ path "/odl-project/project/name";
+ }
+ }
+
+ container no-leafrefcontainer {
+ list no-leafreflist {
+ leaf bar {
+ type string;
+ }
+ }
+ container no-leafrefcontainer2 {
+ leaf baz {
+ type string;
+ }
+ }
+ }
+
+ container no-leafrefcontainer2 {
+ list no-leafreflist {
+ leaf bar {
+ type string;
+ }
+ }
+ container no-leafrefcontainer2 {
+ leaf baz {
+ type string;
+ }
+ }
+ }
+
+}
--- /dev/null
+module leafref-validation {
+ namespace "leafref.validation";
+ prefix val;
+
+ leaf l1 {
+ type leafref {
+ path "../l2";
+ }
+ }
+
+ leaf l2 {
+ type string;
+ }
+
+ container odl-contributor {
+ list contributor {
+ key "login";
+ leaf login {
+ type string;
+ }
+ leaf contributor-name {
+ type string;
+ }
+ leaf odl-group-id {
+ type string;
+ }
+ leaf odl-project-name {
+ type leafref {
+ path "../../../odl-project/project/name";
+ }
+ }
+ leaf odl-project-desc {
+ type leafref {
+ path "/odl-project/project[name = current()/../odl-project-name]/desc";
+ }
+ // type string;
+ }
+ }
+ list noleafref-contributor {
+ leaf foo {
+ type string;
+ }
+ }
+ }
+
+ container odl-project {
+ list project {
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf desc {
+ type string;
+ }
+ leaf project-lead {
+ type leafref {
+ path "../../../odl-contributor/contributor/login";
+ }
+ }
+ leaf project-owner {
+ type leafref {
+ path "/odl-contributor/contributor/login";
+ }
+ }
+ }
+
+ choice ch1 {
+ case c1 {
+ choice ch2 {
+ case c1 {
+ list list-in-choice {
+ key "list-in-choice-key";
+ leaf list-in-choice-key {
+ type string;
+ }
+ leaf leafref-in-choice {
+ type leafref {
+ path "../../con1/l1";
+ }
+ }
+ leaf leafref-in-choice-to-choice {
+ type leafref {
+ path "../../con3/list3-in-choice/l3";
+ }
+ }
+ }
+ }
+ case c2 {
+ }
+ }
+ }
+ case c2 {
+ }
+ }
+
+ list noleafref-project {
+ leaf foo {
+ type string;
+ }
+ }
+ container con1 {
+ leaf l1 {
+ type string;
+ }
+ }
+
+ container con3 {
+ choice choice-in-con3 {
+ case one {
+ list list3-in-choice {
+ key "k";
+ leaf k {
+ type string;
+ }
+ leaf-list l3 {
+ type string;
+ }
+ }
+ }
+ case two {
+ list list3-in-choice-2 {
+ key "l3-2";
+ leaf l3-2 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ leaf-list leafref-leaf-list {
+ type leafref {
+ path "../con3/list3-in-choice/k";
+ }
+ }
+ }
+
+ container no-leafrefcontainer {
+ list no-leafreflist {
+ leaf bar {
+ type string;
+ }
+ }
+ container no-leafrefcontainer2 {
+ leaf baz {
+ type string;
+ }
+ }
+ }
+}
--- /dev/null
+module leafref-validation2 {
+ namespace "leafref.validation2";
+ prefix val2;
+
+ container device_types {
+ list device_type {
+ key "type";
+ leaf type {
+ type string;
+ }
+ leaf desc {
+ type string;
+ }
+ }
+ }
+
+ container devices {
+ list device {
+ key "type_text sn";
+ leaf type_text {
+ type leafref {
+ path "/device_types/device_type/type";
+ }
+ }
+ leaf dev_desc {
+ type leafref {
+ path "/device_types/device_type[type = current()/../type_text]/desc";
+ }
+ }
+ leaf sn {
+ type int32;
+ }
+ leaf default_ip {
+ type string;
+ }
+ }
+ }
+
+ container chips {
+ list chip {
+ key "dev_type";
+ leaf dev_type {
+ type leafref {
+ path "/devices/device/type_text";
+ }
+ }
+ leaf chip_desc {
+ type string;
+ }
+ }
+ }
+}
--- /dev/null
+module leafref-validation3 {
+ namespace "leafref.validation3";
+ prefix val3;
+
+ container device_types {
+ list device_type {
+ key "type1 type2 type3";
+ leaf type1 {
+ type string;
+ }
+ leaf type2 {
+ type string;
+ }
+ leaf type3 {
+ type string;
+ }
+ leaf desc {
+ type string;
+ }
+ }
+ }
+
+ container devices {
+ list device {
+ key "type_text1 sn";
+ unique "sn";
+ leaf type_text1 {
+ type leafref {
+ path "/device_types/device_type/type1";
+ }
+ }
+ leaf type_text2 {
+ type leafref {
+ path "/device_types/device_type/type2";
+ }
+ }
+ leaf type_text3 {
+ type leafref {
+ path "/device_types/device_type/type3";
+ }
+ }
+ leaf dev_desc {
+ type leafref {
+ path "/device_types/device_type[type1 = current()/../type_text1][type2
+ = current()/../type_text2][type3 = current()/../type_text3]/desc";
+ }
+ }
+ leaf sn {
+ type int32;
+ }
+ leaf default_ip {
+ type string;
+ }
+ }
+ }
+
+ container chips {
+ list chip {
+ key "dev_type";
+ leaf dev_type {
+ type leafref {
+ path "/devices/device/type_text";
+ }
+ }
+ leaf chip_desc {
+ type string;
+ }
+ }
+ }
+}