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