2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.impl.leafref;
10 import static com.google.common.base.Preconditions.checkNotNull;
12 import java.util.Collection;
13 import java.util.LinkedList;
14 import java.util.List;
16 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
17 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
19 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.Module;
23 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
24 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
28 final class LeafRefContextTreeBuilder {
29 private final List<LeafRefContext> leafRefs = new LinkedList<>();
30 private final SchemaContext schemaContext;
32 LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
33 this.schemaContext = schemaContext;
36 LeafRefContext buildLeafRefContextTree() throws LeafRefYangSyntaxErrorException {
37 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
38 schemaContext.getPath(), schemaContext);
40 final Set<Module> modules = schemaContext.getModules();
41 for (final Module module : modules) {
42 for (final DataSchemaNode childNode : module.getChildNodes()) {
43 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, module);
44 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
45 rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
50 for (final Module module : modules) {
51 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
52 for (final DataSchemaNode childNode : childNodes) {
53 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode, module);
55 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
56 rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
61 // FIXME: it might be useful to merge these subtrees (i.e. referencing
62 // and referencedBy subtree)
64 return rootBuilder.build();
67 private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node, final Module currentModule)
68 throws LeafRefYangSyntaxErrorException {
69 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
70 node.getPath(), schemaContext);
72 if (node instanceof DataNodeContainer) {
73 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
74 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, currentModule);
75 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
76 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
77 childLeafRefContext.getNodeName());
80 } else if (node instanceof ChoiceSchemaNode) {
81 // :FIXME choice without case
82 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
83 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(caseNode, currentModule);
84 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
85 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
86 childLeafRefContext.getNodeName());
90 } else if (node instanceof TypedDataSchemaNode) {
91 final TypeDefinition<?> type = ((TypedDataSchemaNode) node).getType();
93 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
94 if (type instanceof LeafrefTypeDefinition) {
95 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
96 final String leafRefPathString = leafrefType.getPathStatement().getOriginalString();
97 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(schemaContext,
98 checkNotNull(getBaseTypeModule(leafrefType), "Unable to find base module for leafref %s", node),
100 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPath(leafRefPathString);
102 currentLeafRefContextBuilder.setLeafRefTargetPathString(leafRefPathString);
103 currentLeafRefContextBuilder.setReferencing(true);
104 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
106 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
107 leafRefs.add(currentLeafRefContext);
108 return currentLeafRefContext;
112 return currentLeafRefContextBuilder.build();
115 private Module getBaseTypeModule(final LeafrefTypeDefinition leafrefType) {
117 * Find the first definition of supplied leafref type and return the
118 * module which contains this definition.
120 LeafrefTypeDefinition baseLeafRefType = leafrefType;
121 while (baseLeafRefType.getBaseType() != null) {
122 baseLeafRefType = baseLeafRefType.getBaseType();
124 return schemaContext.findModule(baseLeafRefType.getQName().getModule()).orElse(null);
127 private LeafRefContext buildLeafRefContextReferencedByTree(final DataSchemaNode node, final Module currentModule)
128 throws LeafRefYangSyntaxErrorException {
129 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
130 node.getPath(), schemaContext);
131 if (node instanceof DataNodeContainer) {
132 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
133 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode,
135 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
136 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
137 childLeafRefContext.getNodeName());
140 } else if (node instanceof ChoiceSchemaNode) {
141 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
142 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(caseNode, currentModule);
143 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
144 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
145 childLeafRefContext.getNodeName());
148 } else if (node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode) {
149 final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node, currentModule);
150 if (!foundLeafRefs.isEmpty()) {
151 currentLeafRefContextBuilder.setReferencedBy(true);
152 for (final LeafRefContext leafRef : foundLeafRefs) {
153 currentLeafRefContextBuilder.addReferencedByLeafRefCtx(leafRef.getNodeName(), leafRef);
158 return currentLeafRefContextBuilder.build();
161 private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node, final Module module) {
162 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(node.getPath(), module);
163 final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
164 for (final LeafRefContext leafref : leafRefs) {
165 final LeafRefPath leafRefTargetPath = leafref.getAbsoluteLeafRefTargetPath();
166 if (leafRefTargetPath.equals(nodeXPath)) {
167 foundLeafRefs.add(leafref);
171 return foundLeafRefs;