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