61be82a6c3c420a8ef3de2b74f16d6afc9d00ff9
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / leafref / LeafRefContextTreeBuilder.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.impl.leafref;
9
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.LeafListSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
19 import org.opendaylight.yangtools.yang.model.api.Module;
20 import org.opendaylight.yangtools.yang.model.api.PathExpression;
21 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
22 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
25
26 final class LeafRefContextTreeBuilder {
27     private final List<LeafRefContext> leafRefs = new LinkedList<>();
28     private final SchemaContext schemaContext;
29
30     LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
31         this.schemaContext = schemaContext;
32     }
33
34     LeafRefContext buildLeafRefContextTree() throws LeafRefYangSyntaxErrorException {
35         final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
36             schemaContext.getPath(), schemaContext);
37
38         final Collection<? extends Module> modules = schemaContext.getModules();
39         for (final Module module : modules) {
40             for (final DataSchemaNode childNode : module.getChildNodes()) {
41                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, module);
42                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
43                     rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
44                 }
45             }
46         }
47
48         for (final Module module : modules) {
49             for (final DataSchemaNode childNode : module.getChildNodes()) {
50                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode, module);
51
52                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
53                     rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
54                 }
55             }
56         }
57
58         // FIXME: it might be useful to merge these subtrees (i.e. referencing
59         // and referencedBy subtree)
60
61         return rootBuilder.build();
62     }
63
64     private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node, final Module currentModule) {
65         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
66             node.getPath(), schemaContext);
67
68         if (node instanceof DataNodeContainer) {
69             for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
70                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, currentModule);
71                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
72                     currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
73                         childLeafRefContext.getNodeName());
74                 }
75             }
76         } else if (node instanceof ChoiceSchemaNode) {
77             // :FIXME choice without case
78             for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases()) {
79                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(caseNode, currentModule);
80                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
81                     currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
82                         childLeafRefContext.getNodeName());
83                 }
84             }
85
86         } else if (node instanceof TypedDataSchemaNode) {
87             final TypedDataSchemaNode typedNode = (TypedDataSchemaNode) node;
88             final TypeDefinition<?> type = typedNode.getType();
89
90             // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
91             if (type instanceof LeafrefTypeDefinition) {
92                 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
93                 final PathExpression path = leafrefType.getPathStatement();
94                 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(leafrefType, typedNode);
95                 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPath(path);
96
97                 currentLeafRefContextBuilder.setLeafRefTargetPathString(path.getOriginalString());
98                 currentLeafRefContextBuilder.setReferencing(true);
99                 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
100
101                 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
102                 leafRefs.add(currentLeafRefContext);
103                 return currentLeafRefContext;
104             }
105         }
106
107         return currentLeafRefContextBuilder.build();
108     }
109
110     private LeafRefContext buildLeafRefContextReferencedByTree(final DataSchemaNode node, final Module currentModule)
111             throws LeafRefYangSyntaxErrorException {
112         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
113             node.getPath(), schemaContext);
114         if (node instanceof DataNodeContainer) {
115             for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
116                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode,
117                     currentModule);
118                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
119                     currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
120                         childLeafRefContext.getNodeName());
121                 }
122             }
123         } else if (node instanceof ChoiceSchemaNode) {
124             for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases()) {
125                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(caseNode, currentModule);
126                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
127                     currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
128                         childLeafRefContext.getNodeName());
129                 }
130             }
131         } else if (node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode) {
132             final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node, currentModule);
133             if (!foundLeafRefs.isEmpty()) {
134                 currentLeafRefContextBuilder.setReferencedBy(true);
135                 for (final LeafRefContext leafRef : foundLeafRefs) {
136                     currentLeafRefContextBuilder.addReferencedByLeafRefCtx(leafRef.getNodeName(), leafRef);
137                 }
138             }
139         }
140
141         return currentLeafRefContextBuilder.build();
142     }
143
144     private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node, final Module module) {
145         final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(node.getPath(), module);
146         final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
147         for (final LeafRefContext leafref : leafRefs) {
148             final LeafRefPath leafRefTargetPath = leafref.getAbsoluteLeafRefTargetPath();
149             if (leafRefTargetPath.equals(nodeXPath)) {
150                 foundLeafRefs.add(leafref);
151             }
152         }
153
154         return foundLeafRefs;
155     }
156 }