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