Merge "Bug 2363, Bug 2205. Beta version of LeafRefContext tree computation"
[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.io.ByteArrayInputStream;
11 import java.io.IOException;
12 import java.nio.charset.Charset;
13 import java.util.Collection;
14 import java.util.LinkedList;
15 import java.util.Set;
16 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
17 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
19 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.Module;
23 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
24 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
25 import org.opendaylight.yangtools.yang.model.util.Leafref;
26
27 class LeafRefContextTreeBuilder {
28     private final SchemaContext schemaContext;
29     private final LinkedList<LeafRefContext> leafRefs;
30
31     public LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
32         this.schemaContext = schemaContext;
33         this.leafRefs = new LinkedList<LeafRefContext>();
34     }
35
36     public LeafRefContext buildLeafRefContextTree() throws IOException,
37             LeafRefYangSyntaxErrorException {
38         final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(
39                 schemaContext.getQName(), schemaContext.getPath(),
40                 schemaContext);
41
42         final Set<Module> modules = schemaContext.getModules();
43         for (final Module module : modules) {
44             final Collection<DataSchemaNode> childNodes = module.getChildNodes();
45             for (final DataSchemaNode childNode : childNodes) {
46                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
47                         childNode, module);
48
49                 if (childLeafRefContext.hasReferencingChild()
50                         || childLeafRefContext.isReferencing()) {
51                     rootBuilder.addReferencingChild(childLeafRefContext,
52                             childLeafRefContext.getNodeName());
53                 }
54             }
55         }
56
57         for (final Module module : modules) {
58             final Collection<DataSchemaNode> childNodes = module.getChildNodes();
59             for (final DataSchemaNode childNode : childNodes) {
60                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
61                         childNode, module);
62
63                 if (childLeafRefContext.hasReferencedChild()
64                         || childLeafRefContext.isReferenced()) {
65                     rootBuilder.addReferencedByChild(childLeafRefContext,
66                             childLeafRefContext.getNodeName());
67                 }
68             }
69         }
70
71         // FIXME: it might be useful to merge these subtrees (i.e. referencing
72         // and referencedBy subtree)
73
74         return rootBuilder.build();
75     }
76
77     private LeafRefContext buildLeafRefContextReferencingTree(
78             final DataSchemaNode node, final Module currentModule) throws IOException,
79             LeafRefYangSyntaxErrorException {
80
81         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
82                 node.getQName(), node.getPath(), schemaContext);
83
84         if (node instanceof DataNodeContainer) {
85             final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
86             final Collection<DataSchemaNode> childNodes = dataNodeContainer
87                     .getChildNodes();
88
89             for (final DataSchemaNode childNode : childNodes) {
90                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
91                         childNode, currentModule);
92
93                 if (childLeafRefContext.hasReferencingChild()
94                         || childLeafRefContext.isReferencing()) {
95                     currentLeafRefContextBuilder.addReferencingChild(
96                             childLeafRefContext,
97                             childLeafRefContext.getNodeName());
98                 }
99             }
100         } else if (node instanceof ChoiceSchemaNode) {
101
102             final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
103             final Set<ChoiceCaseNode> cases = choice.getCases();
104             // :FIXME choice without case
105
106             for (final ChoiceCaseNode caseNode : cases) {
107                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
108                         caseNode, currentModule);
109
110                 if (childLeafRefContext.hasReferencingChild()
111                         || childLeafRefContext.isReferencing()) {
112                     currentLeafRefContextBuilder.addReferencingChild(
113                             childLeafRefContext,
114                             childLeafRefContext.getNodeName());
115                 }
116             }
117
118         } else if (node instanceof LeafSchemaNode
119                 || node instanceof LeafListSchemaNode) {
120
121             TypeDefinition<?> type = null;
122
123             if (node instanceof LeafSchemaNode) {
124                 type = ((LeafSchemaNode) node).getType();
125             } else {
126                 type = ((LeafListSchemaNode) node).getType();
127             }
128
129             // FIXME: fix case when type is e.g. typdef -> typedef -> leafref
130             if (type instanceof Leafref) {
131                 final Leafref leafrefType = (Leafref) type;
132                 final String leafRefPathString = leafrefType.getPathStatement()
133                         .toString();
134
135                 currentLeafRefContextBuilder
136                         .setLeafRefTargetPathString(leafRefPathString);
137                 currentLeafRefContextBuilder.setReferencing(true);
138
139                 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(
140                         schemaContext, currentModule, node);
141
142                 final ByteArrayInputStream leafRefPathInputStream = new ByteArrayInputStream(
143                         leafRefPathString.getBytes(Charset.forName("UTF-8")));
144                 final LeafRefPath leafRefPath = leafRefPathParser
145                         .parseLeafRefPathSourceToSchemaPath(leafRefPathInputStream);
146
147                 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
148
149                 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder
150                         .build();
151                 leafRefs.add(currentLeafRefContext);
152                 return currentLeafRefContext;
153             }
154         }
155
156         return currentLeafRefContextBuilder.build();
157     }
158
159     private LeafRefContext buildLeafRefContextReferencedByTree(
160             final DataSchemaNode node, final Module currentModule) throws IOException,
161             LeafRefYangSyntaxErrorException {
162
163         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
164                 node.getQName(), node.getPath(), schemaContext);
165
166         if (node instanceof DataNodeContainer) {
167             final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
168             final Collection<DataSchemaNode> childNodes = dataNodeContainer
169                     .getChildNodes();
170
171             for (final DataSchemaNode childNode : childNodes) {
172                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
173                         childNode, currentModule);
174
175                 if (childLeafRefContext.hasReferencedChild()
176                         || childLeafRefContext.isReferenced()) {
177                     currentLeafRefContextBuilder.addReferencedByChild(
178                             childLeafRefContext,
179                             childLeafRefContext.getNodeName());
180                 }
181             }
182         } else if (node instanceof ChoiceSchemaNode) {
183
184             final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
185             final Set<ChoiceCaseNode> cases = choice.getCases();
186
187             for (final ChoiceCaseNode caseNode : cases) {
188                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
189                         caseNode, currentModule);
190
191                 if (childLeafRefContext.hasReferencedChild()
192                         || childLeafRefContext.isReferenced()) {
193                     currentLeafRefContextBuilder.addReferencedByChild(
194                             childLeafRefContext,
195                             childLeafRefContext.getNodeName());
196                 }
197             }
198
199         } else if (node instanceof LeafSchemaNode
200                 || node instanceof LeafListSchemaNode) {
201
202             final LinkedList<LeafRefContext> foundLeafRefs = getLeafRefsFor(node,
203                     currentModule);
204             if (!foundLeafRefs.isEmpty()) {
205                 currentLeafRefContextBuilder.setReferencedBy(true);
206                 for (final LeafRefContext leafRef : foundLeafRefs) {
207                     currentLeafRefContextBuilder.addReferencedByLeafRefCtx(
208                             leafRef.getNodeName(), leafRef);
209                 }
210             }
211         }
212
213         return currentLeafRefContextBuilder.build();
214     }
215
216     private LinkedList<LeafRefContext> getLeafRefsFor(final DataSchemaNode node,
217             final Module module) {
218         final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(
219                 node.getPath(), module);
220
221         final LinkedList<LeafRefContext> foundLeafRefs = new LinkedList<LeafRefContext>();
222
223         for (final LeafRefContext leafref : leafRefs) {
224             final LeafRefPath leafRefTargetPath = leafref
225                     .getAbsoluteLeafRefTargetPath();
226             if (leafRefTargetPath.equals(nodeXPath)) {
227                 foundLeafRefs.add(leafref);
228             }
229         }
230
231         return foundLeafRefs;
232     }
233
234     // private LeafRefContext buildLeafRefContextTreeFor(LeafRefContext parent,
235     // Module module) {
236     //
237     // Collection<DataSchemaNode> childNodes = module.getChildNodes();
238     // for (DataSchemaNode childNode : childNodes) {
239     // LeafRefContext childLeafRefContext = buildLeafRefContextTreeFor(parent,
240     // childNode);
241     //
242     // if(childLeafRefContext.hasReferencedByChild() ||
243     // childLeafRefContext.isReferencedBy()) {
244     // parent.addReferencedByChild(childLeafRefContext,
245     // childLeafRefContext.getCurrentNodeQName());
246     // }
247     // if(childLeafRefContext.hasReferencingChild() ||
248     // childLeafRefContext.isReferencing()) {
249     // parent.addReferencingChild(childLeafRefContext,
250     // childLeafRefContext.getCurrentNodeQName());
251     // }
252     // }
253     //
254     // return node;
255     // }
256
257 }