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.tree.leafref;
10 import java.util.Collection;
11 import java.util.LinkedList;
12 import java.util.List;
13 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
14 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
15 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
16 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
17 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
18 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
19 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.PathExpression;
22 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
23 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
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;
27 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
29 final class LeafRefContextTreeBuilder {
30 private final List<LeafRefContext> leafRefs = new LinkedList<>();
31 private final EffectiveModelContext schemaContext;
33 LeafRefContextTreeBuilder(final EffectiveModelContext schemaContext) {
34 this.schemaContext = schemaContext;
37 LeafRefContext buildLeafRefContextTree() throws LeafRefYangSyntaxErrorException {
38 final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
39 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(SchemaContext.NAME, SchemaPath.ROOT,
42 final Collection<? extends Module> modules = schemaContext.getModules();
43 for (final Module module : modules) {
44 for (final DataSchemaNode childNode : module.getChildNodes()) {
45 stack.enterSchemaTree(childNode.getQName());
46 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, stack);
48 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
49 rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
53 for (final Module module : modules) {
54 for (final DataSchemaNode childNode : module.getChildNodes()) {
55 stack.enterSchemaTree(childNode.getQName());
56 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode, module,
59 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
60 rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
65 // FIXME: it might be useful to merge these subtrees (i.e. referencing
66 // and referencedBy subtree)
68 return rootBuilder.build();
71 private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node,
72 final SchemaInferenceStack stack) {
73 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
74 stack.toSchemaPath(), schemaContext);
76 if (node instanceof DataNodeContainer) {
77 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
78 stack.enterSchemaTree(childNode.getQName());
79 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, stack);
81 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
82 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
83 childLeafRefContext.getNodeName());
86 } else if (node instanceof ChoiceSchemaNode) {
87 // :FIXME choice without case
88 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases()) {
89 stack.enterSchemaTree(caseNode.getQName());
90 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(caseNode, stack);
92 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
93 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
94 childLeafRefContext.getNodeName());
98 } else if (node instanceof TypedDataSchemaNode) {
99 final TypedDataSchemaNode typedNode = (TypedDataSchemaNode) node;
100 final TypeDefinition<?> type = typedNode.getType();
102 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
103 if (type instanceof LeafrefTypeDefinition) {
104 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
105 final PathExpression path = leafrefType.getPathStatement();
106 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(leafrefType, typedNode);
107 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPath(path);
109 currentLeafRefContextBuilder.setLeafRefTargetPathString(path.getOriginalString());
110 currentLeafRefContextBuilder.setReferencing(true);
111 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
113 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
114 leafRefs.add(currentLeafRefContext);
115 return currentLeafRefContext;
119 return currentLeafRefContextBuilder.build();
122 private LeafRefContext buildLeafRefContextReferencedByTree(final DataSchemaNode node, final Module currentModule,
123 final SchemaInferenceStack stack) {
124 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
125 stack.toSchemaPath(), schemaContext);
126 if (node instanceof DataNodeContainer) {
127 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
128 stack.enterSchemaTree(childNode.getQName());
129 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode,
130 currentModule, stack);
132 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
133 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
134 childLeafRefContext.getNodeName());
137 } else if (node instanceof ChoiceSchemaNode) {
138 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases()) {
139 stack.enterSchemaTree(caseNode.getQName());
140 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(currentModule, stack);
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 Module module, final SchemaInferenceStack stack) {
162 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(stack.toSchemaPath(), 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;