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.io.ByteArrayInputStream;
13 import java.io.IOException;
14 import java.nio.charset.StandardCharsets;
15 import java.util.Collection;
16 import java.util.LinkedList;
17 import java.util.List;
19 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
20 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
22 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.Module;
26 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
27 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
31 class LeafRefContextTreeBuilder {
32 private final List<LeafRefContext> leafRefs = new LinkedList<>();
33 private final SchemaContext schemaContext;
35 LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
36 this.schemaContext = schemaContext;
39 public LeafRefContext buildLeafRefContextTree() throws IOException,
40 LeafRefYangSyntaxErrorException {
41 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
42 schemaContext.getPath(), schemaContext);
44 final Set<Module> modules = schemaContext.getModules();
45 for (final Module module : modules) {
46 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
47 for (final DataSchemaNode childNode : childNodes) {
48 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
51 if (childLeafRefContext.hasReferencingChild()
52 || childLeafRefContext.isReferencing()) {
53 rootBuilder.addReferencingChild(childLeafRefContext,
54 childLeafRefContext.getNodeName());
59 for (final Module module : modules) {
60 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
61 for (final DataSchemaNode childNode : childNodes) {
62 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
65 if (childLeafRefContext.hasReferencedChild()
66 || childLeafRefContext.isReferenced()) {
67 rootBuilder.addReferencedByChild(childLeafRefContext,
68 childLeafRefContext.getNodeName());
73 // FIXME: it might be useful to merge these subtrees (i.e. referencing
74 // and referencedBy subtree)
76 return rootBuilder.build();
79 private LeafRefContext buildLeafRefContextReferencingTree(
80 final DataSchemaNode node, final Module currentModule) throws IOException,
81 LeafRefYangSyntaxErrorException {
83 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
84 node.getQName(), node.getPath(), schemaContext);
86 if (node instanceof DataNodeContainer) {
87 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
88 final Collection<DataSchemaNode> childNodes = dataNodeContainer
91 for (final DataSchemaNode childNode : childNodes) {
92 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
93 childNode, currentModule);
95 if (childLeafRefContext.hasReferencingChild()
96 || childLeafRefContext.isReferencing()) {
97 currentLeafRefContextBuilder.addReferencingChild(
99 childLeafRefContext.getNodeName());
102 } else if (node instanceof ChoiceSchemaNode) {
104 final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
105 final Set<ChoiceCaseNode> cases = choice.getCases();
106 // :FIXME choice without case
108 for (final ChoiceCaseNode caseNode : cases) {
109 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
110 caseNode, currentModule);
112 if (childLeafRefContext.hasReferencingChild()
113 || childLeafRefContext.isReferencing()) {
114 currentLeafRefContextBuilder.addReferencingChild(
116 childLeafRefContext.getNodeName());
120 } else if (node instanceof TypedSchemaNode) {
121 final TypeDefinition<?> type = ((TypedSchemaNode) node).getType();
123 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
124 if (type instanceof LeafrefTypeDefinition) {
125 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
126 final String leafRefPathString = leafrefType.getPathStatement().toString();
128 currentLeafRefContextBuilder.setLeafRefTargetPathString(leafRefPathString);
129 currentLeafRefContextBuilder.setReferencing(true);
131 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(schemaContext,
132 checkNotNull(getBaseTypeModule(leafrefType), "Unable to find base module for leafref %s", node),
135 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPathSourceToSchemaPath(
136 new ByteArrayInputStream(leafRefPathString.getBytes(StandardCharsets.UTF_8)));
138 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
140 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
141 leafRefs.add(currentLeafRefContext);
142 return currentLeafRefContext;
146 return currentLeafRefContextBuilder.build();
149 private Module getBaseTypeModule(final LeafrefTypeDefinition leafrefType) {
151 * Find the first definition of supplied leafref type and return the
152 * module which contains this definition.
154 LeafrefTypeDefinition baseLeafRefType = leafrefType;
155 while (baseLeafRefType.getBaseType() != null) {
156 baseLeafRefType = baseLeafRefType.getBaseType();
158 return schemaContext.findModule(baseLeafRefType.getQName().getModule()).orElse(null);
161 private LeafRefContext buildLeafRefContextReferencedByTree(
162 final DataSchemaNode node, final Module currentModule) throws IOException,
163 LeafRefYangSyntaxErrorException {
165 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
166 node.getQName(), node.getPath(), schemaContext);
168 if (node instanceof DataNodeContainer) {
169 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
170 final Collection<DataSchemaNode> childNodes = dataNodeContainer
173 for (final DataSchemaNode childNode : childNodes) {
174 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
175 childNode, currentModule);
177 if (childLeafRefContext.hasReferencedChild()
178 || childLeafRefContext.isReferenced()) {
179 currentLeafRefContextBuilder.addReferencedByChild(
181 childLeafRefContext.getNodeName());
184 } else if (node instanceof ChoiceSchemaNode) {
186 final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
187 final Set<ChoiceCaseNode> cases = choice.getCases();
189 for (final ChoiceCaseNode caseNode : cases) {
190 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
191 caseNode, currentModule);
193 if (childLeafRefContext.hasReferencedChild()
194 || childLeafRefContext.isReferenced()) {
195 currentLeafRefContextBuilder.addReferencedByChild(
197 childLeafRefContext.getNodeName());
201 } else if (node instanceof LeafSchemaNode
202 || node instanceof LeafListSchemaNode) {
204 final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node,
206 if (!foundLeafRefs.isEmpty()) {
207 currentLeafRefContextBuilder.setReferencedBy(true);
208 for (final LeafRefContext leafRef : foundLeafRefs) {
209 currentLeafRefContextBuilder.addReferencedByLeafRefCtx(
210 leafRef.getNodeName(), leafRef);
215 return currentLeafRefContextBuilder.build();
218 private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node,
219 final Module module) {
220 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(
221 node.getPath(), module);
223 final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
225 for (final LeafRefContext leafref : leafRefs) {
226 final LeafRefPath leafRefTargetPath = leafref
227 .getAbsoluteLeafRefTargetPath();
228 if (leafRefTargetPath.equals(nodeXPath)) {
229 foundLeafRefs.add(leafref);
233 return foundLeafRefs;