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.common.QNameModule;
20 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.Module;
27 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
28 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
32 class LeafRefContextTreeBuilder {
33 private final List<LeafRefContext> leafRefs = new LinkedList<>();
34 private final SchemaContext schemaContext;
36 LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
37 this.schemaContext = schemaContext;
40 public LeafRefContext buildLeafRefContextTree() throws IOException,
41 LeafRefYangSyntaxErrorException {
42 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
43 schemaContext.getPath(), schemaContext);
45 final Set<Module> modules = schemaContext.getModules();
46 for (final Module module : modules) {
47 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
48 for (final DataSchemaNode childNode : childNodes) {
49 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
52 if (childLeafRefContext.hasReferencingChild()
53 || childLeafRefContext.isReferencing()) {
54 rootBuilder.addReferencingChild(childLeafRefContext,
55 childLeafRefContext.getNodeName());
60 for (final Module module : modules) {
61 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
62 for (final DataSchemaNode childNode : childNodes) {
63 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
66 if (childLeafRefContext.hasReferencedChild()
67 || childLeafRefContext.isReferenced()) {
68 rootBuilder.addReferencedByChild(childLeafRefContext,
69 childLeafRefContext.getNodeName());
74 // FIXME: it might be useful to merge these subtrees (i.e. referencing
75 // and referencedBy subtree)
77 return rootBuilder.build();
80 private LeafRefContext buildLeafRefContextReferencingTree(
81 final DataSchemaNode node, final Module currentModule) throws IOException,
82 LeafRefYangSyntaxErrorException {
84 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
85 node.getQName(), node.getPath(), schemaContext);
87 if (node instanceof DataNodeContainer) {
88 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
89 final Collection<DataSchemaNode> childNodes = dataNodeContainer
92 for (final DataSchemaNode childNode : childNodes) {
93 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
94 childNode, currentModule);
96 if (childLeafRefContext.hasReferencingChild()
97 || childLeafRefContext.isReferencing()) {
98 currentLeafRefContextBuilder.addReferencingChild(
100 childLeafRefContext.getNodeName());
103 } else if (node instanceof ChoiceSchemaNode) {
105 final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
106 final Set<ChoiceCaseNode> cases = choice.getCases();
107 // :FIXME choice without case
109 for (final ChoiceCaseNode caseNode : cases) {
110 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
111 caseNode, currentModule);
113 if (childLeafRefContext.hasReferencingChild()
114 || childLeafRefContext.isReferencing()) {
115 currentLeafRefContextBuilder.addReferencingChild(
117 childLeafRefContext.getNodeName());
121 } else if (node instanceof TypedSchemaNode) {
122 final TypeDefinition<?> type = ((TypedSchemaNode) node).getType();
124 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
125 if (type instanceof LeafrefTypeDefinition) {
126 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
127 final String leafRefPathString = leafrefType.getPathStatement().toString();
129 currentLeafRefContextBuilder.setLeafRefTargetPathString(leafRefPathString);
130 currentLeafRefContextBuilder.setReferencing(true);
132 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(schemaContext,
133 checkNotNull(getBaseTypeModule(leafrefType), "Unable to find base module for leafref %s", node),
136 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPathSourceToSchemaPath(
137 new ByteArrayInputStream(leafRefPathString.getBytes(StandardCharsets.UTF_8)));
139 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
141 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
142 leafRefs.add(currentLeafRefContext);
143 return currentLeafRefContext;
147 return currentLeafRefContextBuilder.build();
150 private Module getBaseTypeModule(final LeafrefTypeDefinition leafrefType) {
152 * Find the first definition of supplied leafref type and return the
153 * module which contains this definition.
155 LeafrefTypeDefinition baseLeafRefType = leafrefType;
156 while (baseLeafRefType.getBaseType() != null) {
157 baseLeafRefType = baseLeafRefType.getBaseType();
159 final QNameModule module = baseLeafRefType.getQName().getModule();
160 return schemaContext.findModuleByNamespaceAndRevision(module.getNamespace(), module.getRevision());
163 private LeafRefContext buildLeafRefContextReferencedByTree(
164 final DataSchemaNode node, final Module currentModule) throws IOException,
165 LeafRefYangSyntaxErrorException {
167 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
168 node.getQName(), node.getPath(), schemaContext);
170 if (node instanceof DataNodeContainer) {
171 final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
172 final Collection<DataSchemaNode> childNodes = dataNodeContainer
175 for (final DataSchemaNode childNode : childNodes) {
176 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
177 childNode, currentModule);
179 if (childLeafRefContext.hasReferencedChild()
180 || childLeafRefContext.isReferenced()) {
181 currentLeafRefContextBuilder.addReferencedByChild(
183 childLeafRefContext.getNodeName());
186 } else if (node instanceof ChoiceSchemaNode) {
188 final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
189 final Set<ChoiceCaseNode> cases = choice.getCases();
191 for (final ChoiceCaseNode caseNode : cases) {
192 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
193 caseNode, currentModule);
195 if (childLeafRefContext.hasReferencedChild()
196 || childLeafRefContext.isReferenced()) {
197 currentLeafRefContextBuilder.addReferencedByChild(
199 childLeafRefContext.getNodeName());
203 } else if (node instanceof LeafSchemaNode
204 || node instanceof LeafListSchemaNode) {
206 final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node,
208 if (!foundLeafRefs.isEmpty()) {
209 currentLeafRefContextBuilder.setReferencedBy(true);
210 for (final LeafRefContext leafRef : foundLeafRefs) {
211 currentLeafRefContextBuilder.addReferencedByLeafRefCtx(
212 leafRef.getNodeName(), leafRef);
217 return currentLeafRefContextBuilder.build();
220 private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node,
221 final Module module) {
222 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(
223 node.getPath(), module);
225 final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
227 for (final LeafRefContext leafref : leafRefs) {
228 final LeafRefPath leafRefTargetPath = leafref
229 .getAbsoluteLeafRefTargetPath();
230 if (leafRefTargetPath.equals(nodeXPath)) {
231 foundLeafRefs.add(leafref);
235 return foundLeafRefs;