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 java.io.ByteArrayInputStream;
11 import java.io.IOException;
12 import java.nio.charset.StandardCharsets;
13 import java.util.Collection;
14 import java.util.LinkedList;
15 import java.util.List;
17 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
18 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
19 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
20 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.Module;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
28 class LeafRefContextTreeBuilder {
29 private final SchemaContext schemaContext;
30 private final List<LeafRefContext> leafRefs;
32 public LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
33 this.schemaContext = schemaContext;
34 this.leafRefs = new LinkedList<LeafRefContext>();
37 public LeafRefContext buildLeafRefContextTree() throws IOException,
38 LeafRefYangSyntaxErrorException {
39 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(
40 schemaContext.getQName(), schemaContext.getPath(),
43 final Set<Module> modules = schemaContext.getModules();
44 for (final Module module : modules) {
45 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
46 for (final DataSchemaNode childNode : childNodes) {
47 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
50 if (childLeafRefContext.hasReferencingChild()
51 || childLeafRefContext.isReferencing()) {
52 rootBuilder.addReferencingChild(childLeafRefContext,
53 childLeafRefContext.getNodeName());
58 for (final Module module : modules) {
59 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
60 for (final DataSchemaNode childNode : childNodes) {
61 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
64 if (childLeafRefContext.hasReferencedChild()
65 || childLeafRefContext.isReferenced()) {
66 rootBuilder.addReferencedByChild(childLeafRefContext,
67 childLeafRefContext.getNodeName());
72 // FIXME: it might be useful to merge these subtrees (i.e. referencing
73 // and referencedBy subtree)
75 return rootBuilder.build();
78 private LeafRefContext buildLeafRefContextReferencingTree(
79 final DataSchemaNode node, final Module currentModule) throws IOException,
80 LeafRefYangSyntaxErrorException {
82 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
83 node.getQName(), node.getPath(), schemaContext);
85 if (node instanceof DataNodeContainer) {
86 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
87 final Collection<DataSchemaNode> childNodes = dataNodeContainer
90 for (final DataSchemaNode childNode : childNodes) {
91 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
92 childNode, currentModule);
94 if (childLeafRefContext.hasReferencingChild()
95 || childLeafRefContext.isReferencing()) {
96 currentLeafRefContextBuilder.addReferencingChild(
98 childLeafRefContext.getNodeName());
101 } else if (node instanceof ChoiceSchemaNode) {
103 final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
104 final Set<ChoiceCaseNode> cases = choice.getCases();
105 // :FIXME choice without case
107 for (final ChoiceCaseNode caseNode : cases) {
108 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
109 caseNode, currentModule);
111 if (childLeafRefContext.hasReferencingChild()
112 || childLeafRefContext.isReferencing()) {
113 currentLeafRefContextBuilder.addReferencingChild(
115 childLeafRefContext.getNodeName());
119 } else if (node instanceof LeafSchemaNode
120 || node instanceof LeafListSchemaNode) {
122 TypeDefinition<?> type = null;
124 if (node instanceof LeafSchemaNode) {
125 type = ((LeafSchemaNode) node).getType();
127 type = ((LeafListSchemaNode) node).getType();
130 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
131 if (type instanceof LeafrefTypeDefinition) {
132 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
133 final String leafRefPathString = leafrefType.getPathStatement().toString();
135 currentLeafRefContextBuilder.setLeafRefTargetPathString(leafRefPathString);
136 currentLeafRefContextBuilder.setReferencing(true);
138 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(
139 schemaContext, currentModule, node);
141 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPathSourceToSchemaPath(
142 new ByteArrayInputStream(leafRefPathString.getBytes(StandardCharsets.UTF_8)));
144 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
146 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
147 leafRefs.add(currentLeafRefContext);
148 return currentLeafRefContext;
152 return currentLeafRefContextBuilder.build();
155 private LeafRefContext buildLeafRefContextReferencedByTree(
156 final DataSchemaNode node, final Module currentModule) throws IOException,
157 LeafRefYangSyntaxErrorException {
159 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
160 node.getQName(), node.getPath(), schemaContext);
162 if (node instanceof DataNodeContainer) {
163 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
164 final Collection<DataSchemaNode> childNodes = dataNodeContainer
167 for (final DataSchemaNode childNode : childNodes) {
168 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
169 childNode, currentModule);
171 if (childLeafRefContext.hasReferencedChild()
172 || childLeafRefContext.isReferenced()) {
173 currentLeafRefContextBuilder.addReferencedByChild(
175 childLeafRefContext.getNodeName());
178 } else if (node instanceof ChoiceSchemaNode) {
180 final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
181 final Set<ChoiceCaseNode> cases = choice.getCases();
183 for (final ChoiceCaseNode caseNode : cases) {
184 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
185 caseNode, currentModule);
187 if (childLeafRefContext.hasReferencedChild()
188 || childLeafRefContext.isReferenced()) {
189 currentLeafRefContextBuilder.addReferencedByChild(
191 childLeafRefContext.getNodeName());
195 } else if (node instanceof LeafSchemaNode
196 || node instanceof LeafListSchemaNode) {
198 final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node,
200 if (!foundLeafRefs.isEmpty()) {
201 currentLeafRefContextBuilder.setReferencedBy(true);
202 for (final LeafRefContext leafRef : foundLeafRefs) {
203 currentLeafRefContextBuilder.addReferencedByLeafRefCtx(
204 leafRef.getNodeName(), leafRef);
209 return currentLeafRefContextBuilder.build();
212 private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node,
213 final Module module) {
214 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(
215 node.getPath(), module);
217 final List<LeafRefContext> foundLeafRefs = new LinkedList<LeafRefContext>();
219 for (final LeafRefContext leafref : leafRefs) {
220 final LeafRefPath leafRefTargetPath = leafref
221 .getAbsoluteLeafRefTargetPath();
222 if (leafRefTargetPath.equals(nodeXPath)) {
223 foundLeafRefs.add(leafref);
227 return foundLeafRefs;