4ee7b80595496c55a3ae15a74e22e2e73bb89960
[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.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
22 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
25 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.Module;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
30 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
31 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
33 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
34 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
40 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
48
49 public final class GroupingUtils {
50
51     private GroupingUtils() {
52     }
53
54     /**
55      * Search given modules for grouping by name defined in uses node.
56      *
57      * @param usesBuilder
58      *            builder of uses statement
59      * @param modules
60      *            all loaded modules
61      * @param module
62      *            current module
63      * @return grouping with given name if found, null otherwise
64      */
65     public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
66             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
67         final int line = usesBuilder.getLine();
68         final String groupingString = usesBuilder.getGroupingPathAsString();
69         String groupingPrefix;
70         String groupingName;
71
72         if (groupingString.contains(":")) {
73             String[] splitted = groupingString.split(":");
74             if (splitted.length != 2 || groupingString.contains("/")) {
75                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
76             }
77             groupingPrefix = splitted[0];
78             groupingName = splitted[1];
79         } else {
80             groupingPrefix = module.getPrefix();
81             groupingName = groupingString;
82         }
83
84         ModuleBuilder dependentModule;
85         if (groupingPrefix.equals(module.getPrefix())) {
86             dependentModule = module;
87         } else {
88             dependentModule = ParserUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
89         }
90
91         if (dependentModule == null) {
92             return null;
93         }
94
95         GroupingBuilder result;
96         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
97         result = findGroupingBuilder(groupings, groupingName);
98         if (result != null) {
99             return result;
100         }
101
102         Builder parent = usesBuilder.getParent();
103
104         while (parent != null) {
105             if (parent instanceof DataNodeContainerBuilder) {
106                 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
107             } else if (parent instanceof RpcDefinitionBuilder) {
108                 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
109             }
110             result = findGroupingBuilder(groupings, groupingName);
111             if (result == null) {
112                 parent = parent.getParent();
113             } else {
114                 break;
115             }
116         }
117
118         if (result == null) {
119             throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
120                     + "' not found.");
121         }
122         return result;
123     }
124
125     /**
126      * Search context for grouping by name defined in uses node.
127      *
128      * @param usesBuilder
129      *            builder of uses statement
130      * @param module
131      *            current module
132      * @param context
133      *            SchemaContext containing already resolved modules
134      * @return grouping with given name if found, null otherwise
135      */
136     public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
137             final ModuleBuilder module, final SchemaContext context) {
138         final int line = usesBuilder.getLine();
139         String groupingString = usesBuilder.getGroupingPathAsString();
140         String groupingPrefix;
141         String groupingName;
142
143         if (groupingString.contains(":")) {
144             String[] splitted = groupingString.split(":");
145             if (splitted.length != 2 || groupingString.contains("/")) {
146                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
147             }
148             groupingPrefix = splitted[0];
149             groupingName = splitted[1];
150         } else {
151             groupingPrefix = module.getPrefix();
152             groupingName = groupingString;
153         }
154
155         Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line);
156         return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
157     }
158
159     /**
160      * Find grouping by name.
161      *
162      * @param groupings
163      *            collection of grouping builders 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 GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
169         for (GroupingBuilder grouping : groupings) {
170             if (grouping.getQName().getLocalName().equals(name)) {
171                 return grouping;
172             }
173         }
174         return null;
175     }
176
177     /**
178      * Find grouping by name.
179      *
180      * @param groupings
181      *            collection of grouping definitions to search
182      * @param name
183      *            name of grouping
184      * @return grouping with given name if present in collection, null otherwise
185      */
186     public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
187         for (GroupingDefinition grouping : groupings) {
188             if (grouping.getQName().getLocalName().equals(name)) {
189                 return grouping;
190             }
191         }
192         return null;
193     }
194
195     private static void setNodeAugmenting(DataSchemaNodeBuilder node) {
196         node.setAugmenting(true);
197         if (node instanceof DataNodeContainerBuilder) {
198             for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder)node).getChildNodeBuilders()) {
199                 setNodeAugmenting(child);
200             }
201         }
202         if (node instanceof ChoiceBuilder) {
203             for (ChoiceCaseBuilder child : ((ChoiceBuilder)node).getCases()) {
204                 setNodeAugmenting(child);
205             }
206         }
207     }
208
209     /**
210      * Add nodes defined in uses target grouping to uses parent.
211      *
212      * @param usesNode
213      *            yang uses node which will be instantiated in current location
214      */
215     public static void updateUsesParent(UsesNodeBuilder usesNode) {
216         DataNodeContainerBuilder parent = usesNode.getParent();
217         ModuleBuilder module = ParserUtils.getParentModule(parent);
218         URI ns = module.getNamespace();
219         Date rev = module.getRevision();
220         String prefix = module.getPrefix();
221
222         SchemaPath parentPath = parent.getPath();
223         if (parent instanceof AugmentationSchemaBuilder) {
224             parentPath = ((AugmentationSchemaBuilder) parent).getTargetNodeSchemaPath();
225         }
226
227         // child nodes
228         for (DataSchemaNodeBuilder child : usesNode.getTargetChildren()) {
229             setAddedByUsesToNode(child);
230
231             if (usesNode.isAugmenting()) {
232                 //child.setAugmenting(true);
233                 setNodeAugmenting(child);
234             }
235             if (usesNode.isAugmenting() && !(usesNode.getParentAugment().getParent() instanceof UsesNodeBuilder)) {
236                 AugmentationSchemaBuilder parentAugment = usesNode.getParentAugment();
237                 ModuleBuilder m = ParserUtils.getParentModule(parentAugment);
238                 correctNodePathForUsesNodes(child, parentPath, m);
239             } else {
240                 child.setQName(new QName(ns, rev, prefix, child.getQName().getLocalName()));
241                 correctNodePathForUsesNodes(child, parentPath, module);
242             }
243
244             parent.addChildNode(child);
245         }
246
247         // groupings
248         for (GroupingBuilder gb : usesNode.getTargetGroupings()) {
249             setAddedByUsesToNode(gb);
250             gb.setQName(new QName(ns, rev, prefix, gb.getQName().getLocalName()));
251             correctNodePathForUsesNodes(gb, parentPath, module);
252             parent.addGrouping(gb);
253         }
254
255         // typedefs
256         for (TypeDefinitionBuilder tdb : usesNode.getTargetTypedefs()) {
257             setAddedByUsesToNode(tdb);
258             tdb.setQName(new QName(ns, rev, prefix, tdb.getQName().getLocalName()));
259             correctNodePathForUsesNodes(tdb, parentPath, module);
260             parent.addTypedef(tdb);
261         }
262
263         // unknown nodes
264         for (UnknownSchemaNodeBuilder un : usesNode.getTargetUnknownNodes()) {
265             un.setAddedByUses(true);
266             un.setQName(new QName(ns, rev, prefix, un.getQName().getLocalName()));
267             correctNodePathForUsesNodes(un, parentPath, module);
268             parent.addUnknownNodeBuilder(un);
269         }
270     }
271
272     private static void setAddedByUsesToNode(GroupingMember node) {
273         node.setAddedByUses(true);
274         if (node instanceof DataNodeContainerBuilder) {
275             for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) {
276                 setAddedByUsesToNode(child);
277
278             }
279         } else if (node instanceof ChoiceBuilder) {
280             for (ChoiceCaseBuilder caseNode : ((ChoiceBuilder) node).getCases()) {
281                 setAddedByUsesToNode((caseNode));
282             }
283         }
284     }
285
286     /**
287      * Read data defined in target grouping builder, make a copy and add them to
288      * uses node builder.
289      *
290      * @param usesNode
291      *            uses node builder
292      */
293     public static void collectUsesData(UsesNodeBuilder usesNode) {
294         collectTargetChildNodes(usesNode);
295         collectTargetTypedefs(usesNode);
296         collectTargetGroupings(usesNode);
297         collectTargetUnknownNodes(usesNode);
298         usesNode.setDataCollected(true);
299     }
300
301     /**
302      * Read child nodes defined in target grouping and make a copy of them.
303      *
304      * @param usesNode
305      *            uses node for which data will be collected
306      */
307     private static void collectTargetChildNodes(UsesNodeBuilder usesNode) {
308         final GroupingBuilder target = usesNode.getGroupingBuilder();
309         final Set<DataSchemaNodeBuilder> collection = new HashSet<>();
310         addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders(), usesNode.getParent());
311
312         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
313             Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses,
314                     usesNode.getParent());
315             addChildNodeToCollection(usesNode, collection, targetUsesChildNodes, usesNode.getParent());
316         }
317         usesNode.getTargetChildren().addAll(collection);
318     }
319
320     private static Set<DataSchemaNodeBuilder> collectTargetUsesChildNodes(UsesNodeBuilder usesNode,
321             DataNodeContainerBuilder parent) {
322         final GroupingBuilder target = usesNode.getGroupingBuilder();
323         final Set<DataSchemaNodeBuilder> collection = new HashSet<>(usesNode.getTargetChildren());
324         addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders(), parent);
325
326         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
327             Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses, parent);
328             addChildNodeToCollection(usesNode, collection, targetUsesChildNodes, parent);
329         }
330         return collection;
331     }
332
333     private static void addChildNodeToCollection(UsesNodeBuilder usesNode, Set<DataSchemaNodeBuilder> collection,
334             Set<DataSchemaNodeBuilder> allNodes, Builder parent) {
335         for (DataSchemaNodeBuilder childNode : allNodes) {
336             boolean exists = false;
337             for (DataSchemaNodeBuilder usesChildNode : usesNode.getTargetChildren()) {
338                 if (usesChildNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
339                     exists = true;
340                     break;
341                 }
342             }
343             if (!exists) {
344                 DataSchemaNodeBuilder copy = CopyUtils.copy(childNode, parent, true);
345                 setAddedByUsesToNode(copy);
346                 collection.add(copy);
347             }
348         }
349     }
350
351     /**
352      * Read typedefs defined in target grouping and make a copy of them.
353      *
354      * @param usesNode
355      *            uses node for which data will be collected
356      */
357     private static void collectTargetTypedefs(UsesNodeBuilder usesNode) {
358         final GroupingBuilder target = usesNode.getGroupingBuilder();
359         Set<TypeDefinitionBuilder> collection = new HashSet<>();
360         addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders(), usesNode.getParent());
361
362         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
363             Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, usesNode.getParent());
364             addTypedefToCollection(usesNode, collection, targetUsesTypedefs, usesNode.getParent());
365         }
366         usesNode.getTargetTypedefs().addAll(collection);
367     }
368
369     private static Set<TypeDefinitionBuilder> collectTargetUsesTypedefs(UsesNodeBuilder usesNode,
370             DataNodeContainerBuilder parent) {
371         final GroupingBuilder target = usesNode.getGroupingBuilder();
372         Set<TypeDefinitionBuilder> collection = new HashSet<>(usesNode.getTargetTypedefs());
373         addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders(), parent);
374
375         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
376             Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, parent);
377             addTypedefToCollection(usesNode, collection, targetUsesTypedefs, parent);
378         }
379         return collection;
380     }
381
382     private static void addTypedefToCollection(UsesNodeBuilder usesNode, Set<TypeDefinitionBuilder> collection,
383             Set<TypeDefinitionBuilder> allTypedefs, Builder parent) {
384         for (TypeDefinitionBuilder childNode : allTypedefs) {
385             boolean exists = false;
386             for (TypeDefinitionBuilder usesTypedef : usesNode.getTargetTypedefs()) {
387                 if (usesTypedef.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
388                     exists = true;
389                     break;
390                 }
391             }
392             if (!exists) {
393                 TypeDefinitionBuilder copy = CopyUtils.copy(childNode, parent, true);
394                 collection.add(copy);
395             }
396         }
397     }
398
399     /**
400      * Read groupings defined in target grouping and make a copy of them.
401      *
402      * @param usesNode
403      *            uses node for which data will be collected
404      */
405     private static void collectTargetGroupings(UsesNodeBuilder usesNode) {
406         final GroupingBuilder target = usesNode.getGroupingBuilder();
407         Set<GroupingBuilder> collection = new HashSet<>();
408         addGroupingToCollection(usesNode, collection, target.getGroupingBuilders(), usesNode.getParent());
409
410         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
411             Set<GroupingBuilder> targetUsesGrouping = collectTargetGroupings(targetUses, usesNode.getParent());
412             addGroupingToCollection(usesNode, collection, targetUsesGrouping, usesNode.getParent());
413         }
414         usesNode.getTargetGroupings().addAll(collection);
415     }
416
417     private static Set<GroupingBuilder> collectTargetGroupings(UsesNodeBuilder usesNode, DataNodeContainerBuilder parent) {
418         final GroupingBuilder target = usesNode.getGroupingBuilder();
419         Set<GroupingBuilder> collection = new HashSet<>(usesNode.getTargetGroupings());
420         addGroupingToCollection(usesNode, collection, target.getGroupingBuilders(), parent);
421
422         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
423             Set<GroupingBuilder> targetUsesGroupings = collectTargetGroupings(targetUses, parent);
424             addGroupingToCollection(usesNode, collection, targetUsesGroupings, parent);
425         }
426         return collection;
427     }
428
429     private static void addGroupingToCollection(UsesNodeBuilder usesNode, Set<GroupingBuilder> collection,
430             Set<GroupingBuilder> allGroupings, Builder parent) {
431         for (GroupingBuilder childNode : allGroupings) {
432             boolean exists = false;
433             for (GroupingBuilder usesGrouping : usesNode.getTargetGroupings()) {
434                 if (usesGrouping.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
435                     exists = true;
436                     break;
437                 }
438             }
439             if (!exists) {
440                 GroupingBuilder copy = CopyUtils.copy(childNode, parent, true);
441                 collection.add(copy);
442             }
443         }
444     }
445
446     /**
447      * Read unknown nodes defined in target grouping and make a copy of them.
448      *
449      * @param usesNode
450      *            uses node for which data will be collected
451      */
452     private static void collectTargetUnknownNodes(UsesNodeBuilder usesNode) {
453         final GroupingBuilder target = usesNode.getGroupingBuilder();
454         final List<UnknownSchemaNodeBuilder> collection = new ArrayList<>();
455         addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders(), usesNode.getParent());
456
457         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
458             List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses,
459                     usesNode.getParent());
460             addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes, usesNode.getParent());
461         }
462         usesNode.getTargetUnknownNodes().addAll(collection);
463     }
464
465     private static List<UnknownSchemaNodeBuilder> collectTargetUnknownNodes(UsesNodeBuilder usesNode,
466             DataNodeContainerBuilder parent) {
467         final GroupingBuilder target = usesNode.getGroupingBuilder();
468         List<UnknownSchemaNodeBuilder> collection = new ArrayList<>(usesNode.getTargetUnknownNodes());
469         addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders(), parent);
470
471         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
472             List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses, parent);
473             addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes, parent);
474         }
475         return collection;
476     }
477
478     private static void addUnknownNodeToCollection(UsesNodeBuilder usesNode, List<UnknownSchemaNodeBuilder> collection,
479             List<UnknownSchemaNodeBuilder> allUnknownNodes, Builder parent) {
480         for (UnknownSchemaNodeBuilder childNode : allUnknownNodes) {
481             boolean exists = false;
482             for (UnknownSchemaNodeBuilder usesUnknownNode : usesNode.getTargetUnknownNodes()) {
483                 if (usesUnknownNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
484                     exists = true;
485                     break;
486                 }
487             }
488             if (!exists) {
489                 UnknownSchemaNodeBuilder copy = CopyUtils.copy(childNode, parent, true);
490                 collection.add(copy);
491             }
492         }
493     }
494
495     /**
496      * Read data defined in target grouping definition, make a copy and add them
497      * to uses node builder.
498      *
499      * @param usesNode
500      *            uses node builder
501      */
502     public static void collectUsesDataFromContext(UsesNodeBuilder usesNode) {
503         DataNodeContainerBuilder parent = usesNode.getParent();
504         URI namespace = parent.getQName().getNamespace();
505         Date revision = parent.getQName().getRevision();
506         String prefix = parent.getQName().getPrefix();
507         String moduleName = parent.getModuleName();
508         int line = parent.getLine();
509
510         // child nodes
511         copyGroupingNodesToUsesNode(usesNode, namespace, revision, prefix, moduleName, line);
512
513         // groupings
514         final Set<GroupingBuilder> newGroupings = new HashSet<>();
515         for (GroupingDefinition g : usesNode.getGroupingDefinition().getGroupings()) {
516             QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
517             GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line);
518             newGrouping.setAddedByUses(true);
519             newGroupings.add(newGrouping);
520         }
521         usesNode.getTargetGroupings().addAll(newGroupings);
522
523         // typedefs
524         final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
525         for (TypeDefinition<?> td : usesNode.getGroupingDefinition().getTypeDefinitions()) {
526             QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
527             TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line);
528             newType.setAddedByUses(true);
529             newTypedefs.add(newType);
530         }
531         usesNode.getTargetTypedefs().addAll(newTypedefs);
532
533         // unknown nodes
534         final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
535         for (UnknownSchemaNode un : usesNode.getGroupingDefinition().getUnknownSchemaNodes()) {
536             QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
537             UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line);
538             newNode.setAddedByUses(true);
539             newUnknownNodes.add(newNode);
540         }
541         usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
542
543         usesNode.setDataCollected(true);
544     }
545
546     /**
547      * Read data defined in target grouping definition, make a copy and add them
548      * to uses node builder.
549      *
550      * @param usesNode
551      *            used node builder to which are copied nodes from its
552      *            <code>GroupingDefinition</code>
553      * @param namespace
554      *            URI with parent namespace
555      * @param revision
556      *            date with parent revision date
557      * @param prefix
558      *            string with parent prefix
559      * @param moduleName
560      *            string with parent module name
561      * @param lineNumber
562      *            number with YANG file row where is the parent defined
563      */
564     private static void copyGroupingNodesToUsesNode(final UsesNodeBuilder usesNode, final URI namespace,
565             final Date revision, final String prefix, final String moduleName, final int lineNumber) {
566         final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
567         for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
568             if (child != null) {
569                 DataSchemaNodeBuilder newChild = null;
570                 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
571                 if (child instanceof AnyXmlSchemaNode) {
572                     newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, lineNumber);
573                 } else if (child instanceof ChoiceNode) {
574                     newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, lineNumber);
575                 } else if (child instanceof ContainerSchemaNode) {
576                     newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, lineNumber);
577                 } else if (child instanceof LeafListSchemaNode) {
578                     newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, lineNumber);
579                 } else if (child instanceof LeafSchemaNode) {
580                     newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, lineNumber);
581                 } else if (child instanceof ListSchemaNode) {
582                     newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, lineNumber);
583                 }
584
585                 if (newChild == null) {
586                     throw new YangParseException(moduleName, lineNumber,
587                             "Unknown member of target grouping while resolving uses node.");
588                 }
589
590                 ((GroupingMember) newChild).setAddedByUses(true);
591                 newChildren.add(newChild);
592             }
593         }
594         usesNode.getTargetChildren().addAll(newChildren);
595
596     }
597
598     /**
599      * Correct schema path of nodes added by uses statement.
600      *
601      * @param node
602      *            node added by uses statement
603      * @param parentSchemaPath
604      *            schema path of parent node
605      * @param parentModule
606      *            current parent node module
607      */
608     private static void correctNodePathForUsesNodes(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath,
609             final ModuleBuilder parentModule) {
610         // set correct path
611         List<QName> targetNodePath = new ArrayList<>(parentSchemaPath.getPath());
612         QName qname = new QName(parentModule.getNamespace(), parentModule.getRevision(), parentModule.getPrefix(),
613                 node.getQName().getLocalName());
614         targetNodePath.add(qname);
615         if (node instanceof DataSchemaNodeBuilder) {
616             ((DataSchemaNodeBuilder)node).setQName(qname);
617         }
618         node.setPath(new SchemaPath(targetNodePath, true));
619
620
621         // set correct path for all child nodes
622         if (node instanceof DataNodeContainerBuilder) {
623             DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
624             for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
625                 correctNodePathForUsesNodes(child, node.getPath(), parentModule);
626             }
627         }
628
629         // set correct path for all cases
630         if (node instanceof ChoiceBuilder) {
631             ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
632             for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
633                 correctNodePathForUsesNodes(choiceCaseBuilder, node.getPath(), parentModule);
634             }
635         }
636     }
637
638     /**
639      * Perform refinement of uses target grouping nodes. Uses process has to be
640      * already performed.
641      *
642      * @param usesNode
643      *            uses node containing refine statements
644      */
645     public static void performRefine(UsesNodeBuilder usesNode) {
646         for (RefineHolder refine : usesNode.getRefines()) {
647             String refineTargetPath = refine.getName();
648
649             String[] splitted = refineTargetPath.split("/");
650             Builder currentNode = usesNode.getParent();
651             for (String pathElement : splitted) {
652                 if (currentNode instanceof DataNodeContainerBuilder) {
653                     currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
654                 } else if (currentNode instanceof ChoiceBuilder) {
655                     currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
656                 }
657             }
658
659             DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
660             if (nodeToRefine == null) {
661                 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
662                         + refine.getName() + "' not found");
663             }
664             RefineUtils.performRefine(nodeToRefine, refine);
665             usesNode.addRefineNode(nodeToRefine);
666         }
667     }
668
669 }