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.util.Collection;
11 import java.util.LinkedList;
12 import java.util.List;
14 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
15 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
16 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
17 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
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.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
27 final class LeafRefContextTreeBuilder {
28 private final List<LeafRefContext> leafRefs = new LinkedList<>();
29 private final SchemaContext schemaContext;
31 LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
32 this.schemaContext = schemaContext;
35 LeafRefContext buildLeafRefContextTree() throws LeafRefYangSyntaxErrorException {
36 final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
37 schemaContext.getPath(), schemaContext);
39 final Set<Module> modules = schemaContext.getModules();
40 for (final Module module : modules) {
41 for (final DataSchemaNode childNode : module.getChildNodes()) {
42 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, module);
43 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
44 rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
49 for (final Module module : modules) {
50 final Collection<DataSchemaNode> childNodes = module.getChildNodes();
51 for (final DataSchemaNode childNode : childNodes) {
52 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode, module);
54 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
55 rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
60 // FIXME: it might be useful to merge these subtrees (i.e. referencing
61 // and referencedBy subtree)
63 return rootBuilder.build();
66 private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node, final Module currentModule) {
67 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
68 node.getPath(), schemaContext);
70 if (node instanceof DataNodeContainer) {
71 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
72 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, currentModule);
73 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
74 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
75 childLeafRefContext.getNodeName());
78 } else if (node instanceof ChoiceSchemaNode) {
79 // :FIXME choice without case
80 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
81 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(caseNode, currentModule);
82 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
83 currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
84 childLeafRefContext.getNodeName());
88 } else if (node instanceof TypedDataSchemaNode) {
89 final TypedDataSchemaNode typedNode = (TypedDataSchemaNode) node;
90 final TypeDefinition<?> type = typedNode.getType();
92 // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
93 if (type instanceof LeafrefTypeDefinition) {
94 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
95 final PathExpression path = leafrefType.getPathStatement();
96 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(leafrefType, typedNode);
97 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPath(path);
99 currentLeafRefContextBuilder.setLeafRefTargetPathString(path.getOriginalString());
100 currentLeafRefContextBuilder.setReferencing(true);
101 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
103 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
104 leafRefs.add(currentLeafRefContext);
105 return currentLeafRefContext;
109 return currentLeafRefContextBuilder.build();
112 private LeafRefContext buildLeafRefContextReferencedByTree(final DataSchemaNode node, final Module currentModule)
113 throws LeafRefYangSyntaxErrorException {
114 final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
115 node.getPath(), schemaContext);
116 if (node instanceof DataNodeContainer) {
117 for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
118 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode,
120 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
121 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
122 childLeafRefContext.getNodeName());
125 } else if (node instanceof ChoiceSchemaNode) {
126 for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
127 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(caseNode, currentModule);
128 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
129 currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
130 childLeafRefContext.getNodeName());
133 } else if (node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode) {
134 final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node, currentModule);
135 if (!foundLeafRefs.isEmpty()) {
136 currentLeafRefContextBuilder.setReferencedBy(true);
137 for (final LeafRefContext leafRef : foundLeafRefs) {
138 currentLeafRefContextBuilder.addReferencedByLeafRefCtx(leafRef.getNodeName(), leafRef);
143 return currentLeafRefContextBuilder.build();
146 private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node, final Module module) {
147 final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(node.getPath(), module);
148 final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
149 for (final LeafRefContext leafref : leafRefs) {
150 final LeafRefPath leafRefTargetPath = leafref.getAbsoluteLeafRefTargetPath();
151 if (leafRefTargetPath.equals(nodeXPath)) {
152 foundLeafRefs.add(leafref);
156 return foundLeafRefs;