Refactored parsing of uses and augment statements.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / GroupingUtils.java
1 /*
2  * Copyright (c) 2013 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.parser.util;
9
10 import java.net.URI;
11 import java.util.ArrayList;
12 import java.util.Date;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.TreeMap;
18
19 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
22 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
23 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
24 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
25 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
28 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
29 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
30 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
32 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
33
34 public class GroupingUtils {
35
36     /**
37      * Search given modules for grouping by name defined in uses node.
38      *
39      * @param usesBuilder
40      *            builder of uses statement
41      * @param modules
42      *            all loaded modules
43      * @param module
44      *            current module
45      * @return grouping with given name if found, null otherwise
46      */
47     public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
48             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
49         final int line = usesBuilder.getLine();
50         final String groupingString = usesBuilder.getGroupingName();
51         String groupingPrefix;
52         String groupingName;
53
54         if (groupingString.contains(":")) {
55             String[] splitted = groupingString.split(":");
56             if (splitted.length != 2 || groupingString.contains("/")) {
57                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
58             }
59             groupingPrefix = splitted[0];
60             groupingName = splitted[1];
61         } else {
62             groupingPrefix = module.getPrefix();
63             groupingName = groupingString;
64         }
65
66         ModuleBuilder dependentModule = null;
67         if (groupingPrefix.equals(module.getPrefix())) {
68             dependentModule = module;
69         } else {
70             dependentModule = ParserUtils.findDependentModuleBuilder(modules, module, groupingPrefix, line);
71         }
72
73         if (dependentModule == null) {
74             return null;
75         }
76
77         GroupingBuilder result = null;
78         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
79         result = findGroupingBuilder(groupings, groupingName);
80         if (result != null) {
81             return result;
82         }
83
84         Builder parent = usesBuilder.getParent();
85
86         while (parent != null) {
87             if (parent instanceof DataNodeContainerBuilder) {
88                 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
89             } else if (parent instanceof RpcDefinitionBuilder) {
90                 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
91             }
92             result = findGroupingBuilder(groupings, groupingName);
93             if (result == null) {
94                 parent = parent.getParent();
95             } else {
96                 break;
97             }
98         }
99
100         if (result == null) {
101             throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
102                     + "' not found.");
103         }
104         return result;
105     }
106
107     /**
108      * Search context for grouping by name defined in uses node.
109      *
110      * @param usesBuilder
111      *            builder of uses statement
112      * @param module
113      *            current module
114      * @param context
115      *            SchemaContext containing already resolved modules
116      * @return grouping with given name if found, null otherwise
117      */
118     public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
119             final ModuleBuilder module, final SchemaContext context) {
120         final int line = usesBuilder.getLine();
121         String groupingString = usesBuilder.getGroupingName();
122         String groupingPrefix;
123         String groupingName;
124
125         if (groupingString.contains(":")) {
126             String[] splitted = groupingString.split(":");
127             if (splitted.length != 2 || groupingString.contains("/")) {
128                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
129             }
130             groupingPrefix = splitted[0];
131             groupingName = splitted[1];
132         } else {
133             groupingPrefix = module.getPrefix();
134             groupingName = groupingString;
135         }
136
137         Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line);
138         return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
139     }
140
141     /**
142      * Find grouping by name.
143      *
144      * @param groupings
145      *            collection of grouping builders to search
146      * @param name
147      *            name of grouping
148      * @return grouping with given name if present in collection, null otherwise
149      */
150     public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
151         for (GroupingBuilder grouping : groupings) {
152             if (grouping.getQName().getLocalName().equals(name)) {
153                 return grouping;
154             }
155         }
156         return null;
157     }
158
159     /**
160      * Find grouping by name.
161      *
162      * @param groupings
163      *            collection of grouping definitions to search
164      * @param name
165      *            name of grouping
166      * @return grouping with given name if present in collection, null otherwise
167      */
168     public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
169         for (GroupingDefinition grouping : groupings) {
170             if (grouping.getQName().getLocalName().equals(name)) {
171                 return grouping;
172             }
173         }
174         return null;
175     }
176
177     /**
178      * Copy target grouping data to given uses node.
179      * <p>
180      * Copy all data-schema-nodes, groupings, typedefs and unknown nodes from
181      * target grouping to uses node.
182      * </p>
183      *
184      * @param usesNode
185      * @param targetGrouping
186      */
187     public static void loadTargetGroupingData(final UsesNodeBuilder usesNode, final GroupingBuilder targetGrouping) {
188         // child nodes
189         Set<DataSchemaNodeBuilder> targetChildren = new HashSet<>();
190         for (DataSchemaNodeBuilder targetChild : targetGrouping.getChildNodeBuilders()) {
191             targetChildren.add(CopyUtils.copy(targetChild, usesNode.getParent(), true));
192         }
193         usesNode.setTargetChildren(targetChildren);
194
195         // groupings
196         Set<GroupingBuilder> targetGroupingGroupings = new HashSet<>();
197         for (GroupingBuilder targetGroupingGrouping : targetGrouping.getGroupingBuilders()) {
198             targetGroupingGroupings.add(CopyUtils.copy(targetGroupingGrouping, usesNode.getParent(), true));
199         }
200         usesNode.setTargetGroupings(targetGroupingGroupings);
201
202         // typedefs
203         Set<TypeDefinitionBuilder> targetGroupingTypedefs = new HashSet<>();
204         for(TypeDefinitionBuilder targetGroupingTypedef : targetGrouping.getTypeDefinitionBuilders()) {
205             targetGroupingTypedefs.add(CopyUtils.copy(targetGroupingTypedef, usesNode.getParent(), true));
206         }
207         usesNode.setTargetTypedefs(targetGroupingTypedefs);
208
209         // unknown nodes
210         List<UnknownSchemaNodeBuilder> targetGroupingUNs = new ArrayList<>();
211         for(UnknownSchemaNodeBuilder targetGroupingUN : targetGrouping.getUnknownNodeBuilders()) {
212             targetGroupingUNs.add(CopyUtils.copy(targetGroupingUN, usesNode.getParent(), true));
213         }
214         usesNode.setTargetUnknownNodes(targetGroupingUNs);
215
216         usesNode.setLoadDone(true);
217     }
218
219     /**
220      * Copy all data from target grouping which were added by uses.
221      * <p>
222      * Traverse uses statements in target grouping and copy all
223      * data-schema-nodes, groupings, typedefs and unknown nodes to current uses
224      * node.
225      * </p>
226      *
227      * @param usesNode
228      * @param targetGrouping
229      */
230     public static void loadTargetGroupingUses(final UsesNodeBuilder usesNode, final GroupingBuilder targetGrouping) {
231         usesNode.getTargetGroupingUses().addAll(targetGrouping.getUsesNodes());
232     }
233
234     /**
235      * Create copy of collection of given nodes with new schema path.
236      *
237      * @param nodes
238      *            nodes to copy
239      * @param parentPath
240      *            schema path of parent node
241      * @param namespace
242      *            new namespace of node qname
243      * @param revision
244      *            new revision of node qname
245      * @param prefix
246      *            new prefix of node qname
247      * @param moduleName
248      *            current yang module name
249      * @param line
250      *            current line in yang module
251      * @return collection of new nodes with corrected path
252      */
253     public static Set<DataSchemaNodeBuilder> copyUsesTargetNodesWithNewPath(UsesNodeBuilder usesNode, Builder parent) {
254         Set<DataSchemaNodeBuilder> newNodes = new HashSet<>();
255
256         for (DataSchemaNodeBuilder node : usesNode.getTargetChildren()) {
257             if (node != null) {
258                 if (node instanceof GroupingMember) {
259                     ((GroupingMember) node).setAddedByUses(true);
260                 }
261                 newNodes.add(node);
262             }
263         }
264
265         return newNodes;
266     }
267
268     /**
269      * Create copy of collection of given groupings with new schema path.
270      *
271      * @param groupings
272      *            groupings to copy
273      * @param parentPath
274      *            schema path of parent node
275      * @param namespace
276      *            new namespace of node qname
277      * @param revision
278      *            new revision of node qname
279      * @param prefix
280      *            new prefix of node qname
281      * @return collection of new groupings with corrected path
282      */
283     public static Set<GroupingBuilder> copyUsesTargetGroupingsWithNewPath(UsesNodeBuilder usesNode,
284             SchemaPath parentPath, URI namespace, Date revision, String prefix) {
285         Set<GroupingBuilder> newGroupings = new HashSet<>();
286         for (GroupingBuilder node : usesNode.getTargetGroupings()) {
287             if (node != null) {
288                 if (node instanceof GroupingMember) {
289                     ((GroupingMember) node).setAddedByUses(true);
290                 }
291                 newGroupings.add(node);
292             }
293         }
294
295         return newGroupings;
296     }
297
298     /**
299      * Create copy of collection of given typedefs with new schema path.
300      *
301      * @param typedefs
302      *            typedefs to copy
303      * @param parentPath
304      *            schema path of parent node
305      * @param namespace
306      *            new namespace of node qname
307      * @param revision
308      *            new revision of node qname
309      * @param prefix
310      *            new prefix of node qname
311      * @return collection of new typedefs with corrected path
312      */
313     public static Set<TypeDefinitionBuilder> copyUsesTargetTypedefsWithNewPath(UsesNodeBuilder usesNode,
314             SchemaPath parentPath, URI namespace, Date revision, String prefix) {
315         Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
316
317         for (TypeDefinitionBuilder node : usesNode.getTargetTypedefs()) {
318             if (node != null) {
319                 if (node instanceof GroupingMember) {
320                     ((GroupingMember) node).setAddedByUses(true);
321                 }
322                 newTypedefs.add(node);
323             }
324         }
325
326         return newTypedefs;
327     }
328
329     /**
330      * Create copy of collection of given unknown nodes with new schema path.
331      *
332      * @param usesNode
333      * @param parentPath
334      *            schema path of parent node
335      * @param namespace
336      *            new namespace of node qname
337      * @param revision
338      *            new revision of node qname
339      * @param prefix
340      *            new prefix of node qname
341      * @return collection of new unknownNodes with corrected path
342      */
343     public static List<UnknownSchemaNodeBuilder> copyUsesTargetUnknownNodesWithNewPath(UsesNodeBuilder usesNode,
344             SchemaPath parentPath, URI namespace, Date revision, String prefix) {
345         List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
346
347         for (UnknownSchemaNodeBuilder node : usesNode.getTargetUnknownNodes()) {
348             if (node != null) {
349                 node.setAddedByUses(true);
350                 newUnknownNodes.add(node);
351             }
352         }
353
354         return newUnknownNodes;
355     }
356
357 }