Populate data/ hierarchy
[yangtools.git] / data / 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.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;
28
29 final class LeafRefContextTreeBuilder {
30     private final List<LeafRefContext> leafRefs = new LinkedList<>();
31     private final EffectiveModelContext schemaContext;
32
33     LeafRefContextTreeBuilder(final EffectiveModelContext schemaContext) {
34         this.schemaContext = schemaContext;
35     }
36
37     LeafRefContext buildLeafRefContextTree() throws LeafRefYangSyntaxErrorException {
38         final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
39         final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(SchemaContext.NAME, SchemaPath.ROOT,
40             schemaContext);
41
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);
47                 stack.exit();
48                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
49                     rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
50                 }
51             }
52         }
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,
57                         stack);
58                 stack.exit();
59                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
60                     rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
61                 }
62             }
63         }
64
65         // FIXME: it might be useful to merge these subtrees (i.e. referencing
66         // and referencedBy subtree)
67
68         return rootBuilder.build();
69     }
70
71     private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node,
72             final SchemaInferenceStack stack) {
73         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
74             stack.toSchemaPath(), schemaContext);
75
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);
80                 stack.exit();
81                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
82                     currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
83                         childLeafRefContext.getNodeName());
84                 }
85             }
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);
91                 stack.exit();
92                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
93                     currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
94                         childLeafRefContext.getNodeName());
95                 }
96             }
97
98         } else if (node instanceof TypedDataSchemaNode) {
99             final TypedDataSchemaNode typedNode = (TypedDataSchemaNode) node;
100             final TypeDefinition<?> type = typedNode.getType();
101
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);
108
109                 currentLeafRefContextBuilder.setLeafRefTargetPathString(path.getOriginalString());
110                 currentLeafRefContextBuilder.setReferencing(true);
111                 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
112
113                 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
114                 leafRefs.add(currentLeafRefContext);
115                 return currentLeafRefContext;
116             }
117         }
118
119         return currentLeafRefContextBuilder.build();
120     }
121
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);
131                 stack.exit();
132                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
133                     currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
134                         childLeafRefContext.getNodeName());
135                 }
136             }
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,
141                         stack);
142                 stack.exit();
143                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
144                     currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
145                         childLeafRefContext.getNodeName());
146                 }
147             }
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);
154                 }
155             }
156         }
157
158         return currentLeafRefContextBuilder.build();
159     }
160
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);
168             }
169         }
170
171         return foundLeafRefs;
172     }
173 }