Fixed bug in resolving groupings.
[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     /**
196      * Add nodes defined in uses target grouping to uses parent.
197      *
198      * @param usesNode
199      *            yang uses node which will be instantiated in current location
200      */
201     public static void updateUsesParent(UsesNodeBuilder usesNode) {
202         DataNodeContainerBuilder parent = usesNode.getParent();
203         ModuleBuilder module = ParserUtils.getParentModule(parent);
204         URI ns = module.getNamespace();
205         Date rev = module.getRevision();
206         String prefix = module.getPrefix();
207
208         SchemaPath parentPath = parent.getPath();
209         if (parent instanceof AugmentationSchemaBuilder) {
210             parentPath = ((AugmentationSchemaBuilder) parent).getTargetNodeSchemaPath();
211         }
212
213         // child nodes
214         for (DataSchemaNodeBuilder child : usesNode.getTargetChildren()) {
215             if (child instanceof GroupingMember) {
216                 setAddedByUsesToNode((GroupingMember)child);
217             }
218
219             if (child instanceof GroupingMember) {
220                 GroupingMember gm = (GroupingMember) child;
221                 if (gm.isAddedByUses()) {
222                     if (usesNode.isAugmenting()) {
223                         child.setAugmenting(true);
224                     }
225                     if (usesNode.isAugmenting()
226                             && !(usesNode.getParentAugment().getParent() instanceof UsesNodeBuilder)) {
227                         AugmentationSchemaBuilder parentAugment = usesNode.getParentAugment();
228                         ModuleBuilder m = ParserUtils.getParentModule(parentAugment);
229                         correctNodePathForUsesNodes(child, parentPath, m);
230                     } else {
231                         child.setQName(new QName(ns, rev, prefix, child.getQName().getLocalName()));
232                         correctNodePathForUsesNodes(child, parentPath, module);
233                     }
234                 }
235             } else {
236                 throw new YangParseException(module.getName(), usesNode.getLine(),
237                         "Failed to process uses node: unresolved child node");
238             }
239
240             parent.addChildNode(child);
241         }
242
243         // groupings
244         for (GroupingBuilder gb : usesNode.getTargetGroupings()) {
245             gb.setAddedByUses(true);
246             gb.setQName(new QName(ns, rev, prefix, gb.getQName().getLocalName()));
247             correctNodePathForUsesNodes(gb, parentPath, module);
248             parent.addGrouping(gb);
249         }
250
251         // typedefs
252         for (TypeDefinitionBuilder tdb : usesNode.getTargetTypedefs()) {
253             tdb.setAddedByUses(true);
254             tdb.setQName(new QName(ns, rev, prefix, tdb.getQName().getLocalName()));
255             correctNodePathForUsesNodes(tdb, parentPath, module);
256             parent.addTypedef(tdb);
257         }
258
259         // unknown nodes
260         for (UnknownSchemaNodeBuilder un : usesNode.getTargetUnknownNodes()) {
261             un.setAddedByUses(true);
262             un.setQName(new QName(ns, rev, prefix, un.getQName().getLocalName()));
263             correctNodePathForUsesNodes(un, parentPath, module);
264             parent.addUnknownNodeBuilder(un);
265         }
266     }
267
268     private static void setAddedByUsesToNode(GroupingMember node) {
269         node.setAddedByUses(true);
270         if (node instanceof DataNodeContainerBuilder) {
271             for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder)node).getChildNodeBuilders()) {
272                 if (child instanceof GroupingMember) {
273                     setAddedByUsesToNode((GroupingMember)child);
274                 }
275             }
276         }
277     }
278
279     /**
280      * Read data defined in target grouping builder, make a copy and add them to
281      * uses node builder.
282      *
283      * @param usesNode
284      *            uses node builder
285      */
286     public static void collectUsesData(UsesNodeBuilder usesNode) {
287         collectTargetChildNodes(usesNode);
288         collectTargetTypedefs(usesNode);
289         collectTargetGroupings(usesNode);
290         collectTargetUnknownNodes(usesNode);
291         usesNode.setDataCollected(true);
292     }
293
294     /**
295      * Read child nodes defined in target grouping and make a copy of them.
296      *
297      * @param usesNode
298      *            uses node for which data will be collected
299      */
300     private static void collectTargetChildNodes(UsesNodeBuilder usesNode) {
301         final GroupingBuilder target = usesNode.getGroupingBuilder();
302         final Set<DataSchemaNodeBuilder> collection = new HashSet<>();
303         addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders(), usesNode.getParent());
304
305         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
306             Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses,
307                     usesNode.getParent());
308             addChildNodeToCollection(usesNode, collection, targetUsesChildNodes, usesNode.getParent());
309         }
310         usesNode.getTargetChildren().addAll(collection);
311     }
312
313     private static Set<DataSchemaNodeBuilder> collectTargetUsesChildNodes(UsesNodeBuilder usesNode,
314             DataNodeContainerBuilder parent) {
315         final GroupingBuilder target = usesNode.getGroupingBuilder();
316         final Set<DataSchemaNodeBuilder> collection = new HashSet<>(usesNode.getTargetChildren());
317         addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders(), parent);
318
319         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
320             Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses, parent);
321             addChildNodeToCollection(usesNode, collection, targetUsesChildNodes, parent);
322         }
323         return collection;
324     }
325
326     private static void addChildNodeToCollection(UsesNodeBuilder usesNode, Set<DataSchemaNodeBuilder> collection,
327             Set<DataSchemaNodeBuilder> allNodes, Builder parent) {
328         for (DataSchemaNodeBuilder childNode : allNodes) {
329             boolean exists = false;
330             for (DataSchemaNodeBuilder usesChildNode : usesNode.getTargetChildren()) {
331                 if (usesChildNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
332                     exists = true;
333                     break;
334                 }
335             }
336             if (!exists) {
337                 DataSchemaNodeBuilder copy = CopyUtils.copy(childNode, parent, true);
338                 if (copy instanceof GroupingMember) {
339                     setAddedByUsesToNode((GroupingMember)copy);
340                 }
341                 collection.add(copy);
342             }
343         }
344     }
345
346     /**
347      * Read typedefs defined in target grouping and make a copy of them.
348      *
349      * @param usesNode
350      *            uses node for which data will be collected
351      */
352     private static void collectTargetTypedefs(UsesNodeBuilder usesNode) {
353         final GroupingBuilder target = usesNode.getGroupingBuilder();
354         Set<TypeDefinitionBuilder> collection = new HashSet<>();
355         addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders(), usesNode.getParent());
356
357         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
358             Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, usesNode.getParent());
359             addTypedefToCollection(usesNode, collection, targetUsesTypedefs, usesNode.getParent());
360         }
361         usesNode.getTargetTypedefs().addAll(collection);
362     }
363
364     private static Set<TypeDefinitionBuilder> collectTargetUsesTypedefs(UsesNodeBuilder usesNode,
365             DataNodeContainerBuilder parent) {
366         final GroupingBuilder target = usesNode.getGroupingBuilder();
367         Set<TypeDefinitionBuilder> collection = new HashSet<>(usesNode.getTargetTypedefs());
368         addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders(), parent);
369
370         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
371             Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, parent);
372             addTypedefToCollection(usesNode, collection, targetUsesTypedefs, parent);
373         }
374         return collection;
375     }
376
377     private static void addTypedefToCollection(UsesNodeBuilder usesNode, Set<TypeDefinitionBuilder> collection,
378             Set<TypeDefinitionBuilder> allTypedefs, Builder parent) {
379         for (TypeDefinitionBuilder childNode : allTypedefs) {
380             boolean exists = false;
381             for (TypeDefinitionBuilder usesTypedef : usesNode.getTargetTypedefs()) {
382                 if (usesTypedef.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
383                     exists = true;
384                     break;
385                 }
386             }
387             if (!exists) {
388                 TypeDefinitionBuilder copy = CopyUtils.copy(childNode, parent, true);
389                 collection.add(copy);
390             }
391         }
392     }
393
394     /**
395      * Read groupings defined in target grouping and make a copy of them.
396      *
397      * @param usesNode
398      *            uses node for which data will be collected
399      */
400     private static void collectTargetGroupings(UsesNodeBuilder usesNode) {
401         final GroupingBuilder target = usesNode.getGroupingBuilder();
402         Set<GroupingBuilder> collection = new HashSet<>();
403         addGroupingToCollection(usesNode, collection, target.getGroupingBuilders(), usesNode.getParent());
404
405         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
406             Set<GroupingBuilder> targetUsesGrouping = collectTargetGroupings(targetUses, usesNode.getParent());
407             addGroupingToCollection(usesNode, collection, targetUsesGrouping, usesNode.getParent());
408         }
409         usesNode.getTargetGroupings().addAll(collection);
410     }
411
412     private static Set<GroupingBuilder> collectTargetGroupings(UsesNodeBuilder usesNode, DataNodeContainerBuilder parent) {
413         final GroupingBuilder target = usesNode.getGroupingBuilder();
414         Set<GroupingBuilder> collection = new HashSet<>(usesNode.getTargetGroupings());
415         addGroupingToCollection(usesNode, collection, target.getGroupingBuilders(), parent);
416
417         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
418             Set<GroupingBuilder> targetUsesGroupings = collectTargetGroupings(targetUses, parent);
419             addGroupingToCollection(usesNode, collection, targetUsesGroupings, parent);
420         }
421         return collection;
422     }
423
424     private static void addGroupingToCollection(UsesNodeBuilder usesNode, Set<GroupingBuilder> collection,
425             Set<GroupingBuilder> allGroupings, Builder parent) {
426         for (GroupingBuilder childNode : allGroupings) {
427             boolean exists = false;
428             for (GroupingBuilder usesGrouping : usesNode.getTargetGroupings()) {
429                 if (usesGrouping.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
430                     exists = true;
431                     break;
432                 }
433             }
434             if (!exists) {
435                 GroupingBuilder copy = CopyUtils.copy(childNode, parent, true);
436                 collection.add(copy);
437             }
438         }
439     }
440
441     /**
442      * Read unknown nodes defined in target grouping and make a copy of them.
443      *
444      * @param usesNode
445      *            uses node for which data will be collected
446      */
447     private static void collectTargetUnknownNodes(UsesNodeBuilder usesNode) {
448         final GroupingBuilder target = usesNode.getGroupingBuilder();
449         final List<UnknownSchemaNodeBuilder> collection = new ArrayList<>();
450         addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders(), usesNode.getParent());
451
452         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
453             List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses,
454                     usesNode.getParent());
455             addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes, usesNode.getParent());
456         }
457         usesNode.getTargetUnknownNodes().addAll(collection);
458     }
459
460     private static List<UnknownSchemaNodeBuilder> collectTargetUnknownNodes(UsesNodeBuilder usesNode,
461             DataNodeContainerBuilder parent) {
462         final GroupingBuilder target = usesNode.getGroupingBuilder();
463         List<UnknownSchemaNodeBuilder> collection = new ArrayList<>(usesNode.getTargetUnknownNodes());
464         addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders(), parent);
465
466         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
467             List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses, parent);
468             addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes, parent);
469         }
470         return collection;
471     }
472
473     private static void addUnknownNodeToCollection(UsesNodeBuilder usesNode, List<UnknownSchemaNodeBuilder> collection,
474             List<UnknownSchemaNodeBuilder> allUnknownNodes, Builder parent) {
475         for (UnknownSchemaNodeBuilder childNode : allUnknownNodes) {
476             boolean exists = false;
477             for (UnknownSchemaNodeBuilder usesUnknownNode : usesNode.getTargetUnknownNodes()) {
478                 if (usesUnknownNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
479                     exists = true;
480                     break;
481                 }
482             }
483             if (!exists) {
484                 UnknownSchemaNodeBuilder copy = CopyUtils.copy(childNode, parent, true);
485                 collection.add(copy);
486             }
487         }
488     }
489
490     /**
491      * Read data defined in target grouping definition, make a copy and add them
492      * to uses node builder.
493      *
494      * @param usesNode
495      *            uses node builder
496      */
497     public static void collectUsesDataFromContext(UsesNodeBuilder usesNode) {
498         DataNodeContainerBuilder parent = usesNode.getParent();
499         URI namespace = parent.getQName().getNamespace();
500         Date revision = parent.getQName().getRevision();
501         String prefix = parent.getQName().getPrefix();
502         String moduleName = parent.getModuleName();
503         int line = parent.getLine();
504
505         // child nodes
506         copyGroupingNodesToUsesNode(usesNode, namespace, revision, prefix, moduleName, line);
507
508         // groupings
509         final Set<GroupingBuilder> newGroupings = new HashSet<>();
510         for (GroupingDefinition g : usesNode.getGroupingDefinition().getGroupings()) {
511             QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
512             GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line);
513             newGrouping.setAddedByUses(true);
514             newGroupings.add(newGrouping);
515         }
516         usesNode.getTargetGroupings().addAll(newGroupings);
517
518         // typedefs
519         final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
520         for (TypeDefinition<?> td : usesNode.getGroupingDefinition().getTypeDefinitions()) {
521             QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
522             TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line);
523             newType.setAddedByUses(true);
524             newTypedefs.add(newType);
525         }
526         usesNode.getTargetTypedefs().addAll(newTypedefs);
527
528         // unknown nodes
529         final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
530         for (UnknownSchemaNode un : usesNode.getGroupingDefinition().getUnknownSchemaNodes()) {
531             QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
532             UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line);
533             newNode.setAddedByUses(true);
534             newUnknownNodes.add(newNode);
535         }
536         usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
537
538         usesNode.setDataCollected(true);
539     }
540
541     /**
542      * Read data defined in target grouping definition, make a copy and add them
543      * to uses node builder.
544      *
545      * @param usesNode
546      *            used node builder to which are copied nodes from its
547      *            <code>GroupingDefinition</code>
548      * @param namespace
549      *            URI with parent namespace
550      * @param revision
551      *            date with parent revision date
552      * @param prefix
553      *            string with parent prefix
554      * @param moduleName
555      *            string with parent module name
556      * @param lineNumber
557      *            number with YANG file row where is the parent defined
558      */
559     private static void copyGroupingNodesToUsesNode(final UsesNodeBuilder usesNode, final URI namespace,
560             final Date revision, final String prefix, final String moduleName, final int lineNumber) {
561         final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
562         for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
563             if (child != null) {
564                 DataSchemaNodeBuilder newChild = null;
565                 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
566                 if (child instanceof AnyXmlSchemaNode) {
567                     newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, lineNumber);
568                 } else if (child instanceof ChoiceNode) {
569                     newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, lineNumber);
570                 } else if (child instanceof ContainerSchemaNode) {
571                     newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, lineNumber);
572                 } else if (child instanceof LeafListSchemaNode) {
573                     newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, lineNumber);
574                 } else if (child instanceof LeafSchemaNode) {
575                     newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, lineNumber);
576                 } else if (child instanceof ListSchemaNode) {
577                     newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, lineNumber);
578                 }
579
580                 if (newChild == null) {
581                     throw new YangParseException(moduleName, lineNumber,
582                             "Unknown member of target grouping while resolving uses node.");
583                 }
584
585                 ((GroupingMember) newChild).setAddedByUses(true);
586                 newChildren.add(newChild);
587             }
588         }
589         usesNode.getTargetChildren().addAll(newChildren);
590
591     }
592
593     /**
594      * Correct schema path of nodes added by uses statement.
595      *
596      * @param node
597      *            node added by uses statement
598      * @param parentSchemaPath
599      *            schema path of parent node
600      * @param parentModule
601      *            current parent node module
602      */
603     private static void correctNodePathForUsesNodes(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath,
604             final ModuleBuilder parentModule) {
605         // set correct path
606         List<QName> targetNodePath = new ArrayList<>(parentSchemaPath.getPath());
607         targetNodePath.add(new QName(parentModule.getNamespace(), parentModule.getRevision(), parentModule.getPrefix(),
608                 node.getQName().getLocalName()));
609         node.setPath(new SchemaPath(targetNodePath, true));
610
611         // set correct path for all child nodes
612         if (node instanceof DataNodeContainerBuilder) {
613             DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
614             for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
615                 correctNodePathForUsesNodes(child, node.getPath(), parentModule);
616             }
617         }
618
619         // set correct path for all cases
620         if (node instanceof ChoiceBuilder) {
621             ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
622             for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
623                 correctNodePathForUsesNodes(choiceCaseBuilder, node.getPath(), parentModule);
624             }
625         }
626     }
627
628     /**
629      * Perform refinement of uses target grouping nodes. Uses process has to be
630      * already performed.
631      *
632      * @param usesNode
633      *            uses node containing refine statements
634      */
635     public static void performRefine(UsesNodeBuilder usesNode) {
636         for (RefineHolder refine : usesNode.getRefines()) {
637             String refineTargetPath = refine.getName();
638
639             String[] splitted = refineTargetPath.split("/");
640             Builder currentNode = usesNode.getParent();
641             for (String pathElement : splitted) {
642                 if (currentNode instanceof DataNodeContainerBuilder) {
643                     currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
644                 } else if (currentNode instanceof ChoiceBuilder) {
645                     currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
646                 }
647             }
648
649             DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
650             if (nodeToRefine == null) {
651                 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
652                         + refine.getName() + "' not found");
653             }
654             RefineUtils.performRefine(nodeToRefine, refine);
655             usesNode.addRefineNode(nodeToRefine);
656         }
657     }
658
659 }