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