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.CaseSchemaNode;
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.TypedDataSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
31 final 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 LeafRefContext buildLeafRefContextTree() throws IOException, LeafRefYangSyntaxErrorException {
40 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
41 schemaContext.getPath(), schemaContext);
43 final Set<Module> modules = schemaContext.getModules();
44 for (final Module module : modules) {
45 for (final DataSchemaNode childNode : module.getChildNodes()) {
46 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, module);
47 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
48 rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
53 for (final Module module : modules) {
54 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
55 for (final DataSchemaNode childNode : childNodes) {
56 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode, module);
58 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
59 rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
64 // FIXME: it might be useful to merge these subtrees (i.e. referencing
65 // and referencedBy subtree)
67 return rootBuilder.build();
70 private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node, final Module currentModule)
71 throws IOException, LeafRefYangSyntaxErrorException {
72 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
73 node.getPath(), schemaContext);
75 if (node instanceof DataNodeContainer) {
76 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
77 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, currentModule);
78 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
79 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
80 childLeafRefContext.getNodeName());
83 } else if (node instanceof ChoiceSchemaNode) {
84 // :FIXME choice without case
85 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
86 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(caseNode, currentModule);
87 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
88 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
89 childLeafRefContext.getNodeName());
93 } else if (node instanceof TypedDataSchemaNode) {
94 final TypeDefinition<?> type = ((TypedDataSchemaNode) node).getType();
96 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
97 if (type instanceof LeafrefTypeDefinition) {
98 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
99 final String leafRefPathString = leafrefType.getPathStatement().toString();
101 currentLeafRefContextBuilder.setLeafRefTargetPathString(leafRefPathString);
102 currentLeafRefContextBuilder.setReferencing(true);
104 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(schemaContext,
105 checkNotNull(getBaseTypeModule(leafrefType), "Unable to find base module for leafref %s", node),
108 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPathSourceToSchemaPath(
109 new ByteArrayInputStream(leafRefPathString.getBytes(StandardCharsets.UTF_8)));
111 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
113 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
114 leafRefs.add(currentLeafRefContext);
115 return currentLeafRefContext;
119 return currentLeafRefContextBuilder.build();
122 private Module getBaseTypeModule(final LeafrefTypeDefinition leafrefType) {
124 * Find the first definition of supplied leafref type and return the
125 * module which contains this definition.
127 LeafrefTypeDefinition baseLeafRefType = leafrefType;
128 while (baseLeafRefType.getBaseType() != null) {
129 baseLeafRefType = baseLeafRefType.getBaseType();
131 return schemaContext.findModule(baseLeafRefType.getQName().getModule()).orElse(null);
134 private LeafRefContext buildLeafRefContextReferencedByTree(final DataSchemaNode node, final Module currentModule)
135 throws IOException,LeafRefYangSyntaxErrorException {
136 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
137 node.getPath(), schemaContext);
138 if (node instanceof DataNodeContainer) {
139 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
140 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode,
142 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
143 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
144 childLeafRefContext.getNodeName());
147 } else if (node instanceof ChoiceSchemaNode) {
148 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
149 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(caseNode, currentModule);
150 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
151 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
152 childLeafRefContext.getNodeName());
155 } else if (node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode) {
156 final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node, currentModule);
157 if (!foundLeafRefs.isEmpty()) {
158 currentLeafRefContextBuilder.setReferencedBy(true);
159 for (final LeafRefContext leafRef : foundLeafRefs) {
160 currentLeafRefContextBuilder.addReferencedByLeafRefCtx(leafRef.getNodeName(), leafRef);
165 return currentLeafRefContextBuilder.build();
168 private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node, final Module module) {
169 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(node.getPath(), module);
170 final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
171 for (final LeafRefContext leafref : leafRefs) {
172 final LeafRefPath leafRefTargetPath = leafref.getAbsoluteLeafRefTargetPath();
173 if (leafRefTargetPath.equals(nodeXPath)) {
174 foundLeafRefs.add(leafref);
178 return foundLeafRefs;