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