Fixed bug in resolving groupings.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / GroupingUtils.java
index 9dda792c74916f162483c2221cc9bff09a83361f..80fb2c4479176af7e49a88303dfb08b8473f1f56 100644 (file)
@@ -7,8 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.parser.util;
 
-import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.createSchemaPath;
-
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Date;
@@ -29,21 +27,29 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
 
-public class GroupingUtils {
+public final class GroupingUtils {
+
+    private GroupingUtils() {
+    }
 
     /**
      * Search given modules for grouping by name defined in uses node.
@@ -59,7 +65,7 @@ public class GroupingUtils {
     public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
         final int line = usesBuilder.getLine();
-        final String groupingString = usesBuilder.getGroupingName();
+        final String groupingString = usesBuilder.getGroupingPathAsString();
         String groupingPrefix;
         String groupingName;
 
@@ -75,18 +81,18 @@ public class GroupingUtils {
             groupingName = groupingString;
         }
 
-        ModuleBuilder dependentModule = null;
+        ModuleBuilder dependentModule;
         if (groupingPrefix.equals(module.getPrefix())) {
             dependentModule = module;
         } else {
-            dependentModule = ParserUtils.findDependentModuleBuilder(modules, module, groupingPrefix, line);
+            dependentModule = ParserUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
         }
 
         if (dependentModule == null) {
             return null;
         }
 
-        GroupingBuilder result = null;
+        GroupingBuilder result;
         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
         result = findGroupingBuilder(groupings, groupingName);
         if (result != null) {
@@ -130,7 +136,7 @@ public class GroupingUtils {
     public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
             final ModuleBuilder module, final SchemaContext context) {
         final int line = usesBuilder.getLine();
-        String groupingString = usesBuilder.getGroupingName();
+        String groupingString = usesBuilder.getGroupingPathAsString();
         String groupingPrefix;
         String groupingName;
 
@@ -190,138 +196,314 @@ public class GroupingUtils {
      * Add nodes defined in uses target grouping to uses parent.
      *
      * @param usesNode
+     *            yang uses node which will be instantiated in current location
      */
     public static void updateUsesParent(UsesNodeBuilder usesNode) {
         DataNodeContainerBuilder parent = usesNode.getParent();
+        ModuleBuilder module = ParserUtils.getParentModule(parent);
+        URI ns = module.getNamespace();
+        Date rev = module.getRevision();
+        String prefix = module.getPrefix();
+
+        SchemaPath parentPath = parent.getPath();
+        if (parent instanceof AugmentationSchemaBuilder) {
+            parentPath = ((AugmentationSchemaBuilder) parent).getTargetNodeSchemaPath();
+        }
 
         // child nodes
         for (DataSchemaNodeBuilder child : usesNode.getTargetChildren()) {
             if (child instanceof GroupingMember) {
-                ((GroupingMember) child).setAddedByUses(true);
+                setAddedByUsesToNode((GroupingMember)child);
+            }
+
+            if (child instanceof GroupingMember) {
+                GroupingMember gm = (GroupingMember) child;
+                if (gm.isAddedByUses()) {
+                    if (usesNode.isAugmenting()) {
+                        child.setAugmenting(true);
+                    }
+                    if (usesNode.isAugmenting()
+                            && !(usesNode.getParentAugment().getParent() instanceof UsesNodeBuilder)) {
+                        AugmentationSchemaBuilder parentAugment = usesNode.getParentAugment();
+                        ModuleBuilder m = ParserUtils.getParentModule(parentAugment);
+                        correctNodePathForUsesNodes(child, parentPath, m);
+                    } else {
+                        child.setQName(new QName(ns, rev, prefix, child.getQName().getLocalName()));
+                        correctNodePathForUsesNodes(child, parentPath, module);
+                    }
+                }
+            } else {
+                throw new YangParseException(module.getName(), usesNode.getLine(),
+                        "Failed to process uses node: unresolved child node");
             }
+
             parent.addChildNode(child);
         }
 
         // groupings
         for (GroupingBuilder gb : usesNode.getTargetGroupings()) {
             gb.setAddedByUses(true);
+            gb.setQName(new QName(ns, rev, prefix, gb.getQName().getLocalName()));
+            correctNodePathForUsesNodes(gb, parentPath, module);
             parent.addGrouping(gb);
         }
 
         // typedefs
         for (TypeDefinitionBuilder tdb : usesNode.getTargetTypedefs()) {
             tdb.setAddedByUses(true);
+            tdb.setQName(new QName(ns, rev, prefix, tdb.getQName().getLocalName()));
+            correctNodePathForUsesNodes(tdb, parentPath, module);
             parent.addTypedef(tdb);
         }
 
         // unknown nodes
         for (UnknownSchemaNodeBuilder un : usesNode.getTargetUnknownNodes()) {
             un.setAddedByUses(true);
+            un.setQName(new QName(ns, rev, prefix, un.getQName().getLocalName()));
+            correctNodePathForUsesNodes(un, parentPath, module);
             parent.addUnknownNodeBuilder(un);
         }
     }
 
+    private static void setAddedByUsesToNode(GroupingMember node) {
+        node.setAddedByUses(true);
+        if (node instanceof DataNodeContainerBuilder) {
+            for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder)node).getChildNodeBuilders()) {
+                if (child instanceof GroupingMember) {
+                    setAddedByUsesToNode((GroupingMember)child);
+                }
+            }
+        }
+    }
+
+    /**
+     * Read data defined in target grouping builder, make a copy and add them to
+     * uses node builder.
+     *
+     * @param usesNode
+     *            uses node builder
+     */
     public static void collectUsesData(UsesNodeBuilder usesNode) {
-        usesNode.setTargetChildren(collectUsesChildNodes(usesNode));
-        usesNode.setTargetTypedefs(collectUsesTypedefs(usesNode));
-        usesNode.setTargetGroupings(collectUsesGroupings(usesNode));
-        usesNode.setTargetUnknownNodes(collectUsesUnknownNodes(usesNode));
+        collectTargetChildNodes(usesNode);
+        collectTargetTypedefs(usesNode);
+        collectTargetGroupings(usesNode);
+        collectTargetUnknownNodes(usesNode);
         usesNode.setDataCollected(true);
     }
 
-    private static Set<DataSchemaNodeBuilder> collectUsesChildNodes(UsesNodeBuilder usesNode) {
+    /**
+     * Read child nodes defined in target grouping and make a copy of them.
+     *
+     * @param usesNode
+     *            uses node for which data will be collected
+     */
+    private static void collectTargetChildNodes(UsesNodeBuilder usesNode) {
         final GroupingBuilder target = usesNode.getGroupingBuilder();
-        Set<DataSchemaNodeBuilder> childNodes = target.getChildNodeBuilders();
-        Set<DataSchemaNodeBuilder> copies = new HashSet<>();
-        for (DataSchemaNodeBuilder childNode : childNodes) {
-            copies.add(CopyUtils.copy(childNode, usesNode.getParent(), true));
+        final Set<DataSchemaNodeBuilder> collection = new HashSet<>();
+        addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders(), usesNode.getParent());
+
+        for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
+            Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses,
+                    usesNode.getParent());
+            addChildNodeToCollection(usesNode, collection, targetUsesChildNodes, usesNode.getParent());
         }
+        usesNode.getTargetChildren().addAll(collection);
+    }
+
+    private static Set<DataSchemaNodeBuilder> collectTargetUsesChildNodes(UsesNodeBuilder usesNode,
+            DataNodeContainerBuilder parent) {
+        final GroupingBuilder target = usesNode.getGroupingBuilder();
+        final Set<DataSchemaNodeBuilder> collection = new HashSet<>(usesNode.getTargetChildren());
+        addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders(), parent);
+
         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
-            copies.addAll(collectUsesChildNodes(targetUses));
+            Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses, parent);
+            addChildNodeToCollection(usesNode, collection, targetUsesChildNodes, parent);
+        }
+        return collection;
+    }
+
+    private static void addChildNodeToCollection(UsesNodeBuilder usesNode, Set<DataSchemaNodeBuilder> collection,
+            Set<DataSchemaNodeBuilder> allNodes, Builder parent) {
+        for (DataSchemaNodeBuilder childNode : allNodes) {
+            boolean exists = false;
+            for (DataSchemaNodeBuilder usesChildNode : usesNode.getTargetChildren()) {
+                if (usesChildNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
+                    exists = true;
+                    break;
+                }
+            }
+            if (!exists) {
+                DataSchemaNodeBuilder copy = CopyUtils.copy(childNode, parent, true);
+                if (copy instanceof GroupingMember) {
+                    setAddedByUsesToNode((GroupingMember)copy);
+                }
+                collection.add(copy);
+            }
         }
-        return copies;
     }
 
-    private static Set<TypeDefinitionBuilder> collectUsesTypedefs(UsesNodeBuilder usesNode) {
+    /**
+     * Read typedefs defined in target grouping and make a copy of them.
+     *
+     * @param usesNode
+     *            uses node for which data will be collected
+     */
+    private static void collectTargetTypedefs(UsesNodeBuilder usesNode) {
         final GroupingBuilder target = usesNode.getGroupingBuilder();
-        Set<TypeDefinitionBuilder> typedefs = target.getTypeDefinitionBuilders();
-        Set<TypeDefinitionBuilder> copies = new HashSet<>();
-        for (TypeDefinitionBuilder typedef : typedefs) {
-            copies.add(CopyUtils.copy(typedef, usesNode.getParent(), true));
+        Set<TypeDefinitionBuilder> collection = new HashSet<>();
+        addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders(), usesNode.getParent());
+
+        for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
+            Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, usesNode.getParent());
+            addTypedefToCollection(usesNode, collection, targetUsesTypedefs, usesNode.getParent());
         }
+        usesNode.getTargetTypedefs().addAll(collection);
+    }
+
+    private static Set<TypeDefinitionBuilder> collectTargetUsesTypedefs(UsesNodeBuilder usesNode,
+            DataNodeContainerBuilder parent) {
+        final GroupingBuilder target = usesNode.getGroupingBuilder();
+        Set<TypeDefinitionBuilder> collection = new HashSet<>(usesNode.getTargetTypedefs());
+        addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders(), parent);
+
         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
-            copies.addAll(collectUsesTypedefs(targetUses));
+            Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, parent);
+            addTypedefToCollection(usesNode, collection, targetUsesTypedefs, parent);
         }
-        return copies;
+        return collection;
     }
 
-    private static Set<GroupingBuilder> collectUsesGroupings(UsesNodeBuilder usesNode) {
+    private static void addTypedefToCollection(UsesNodeBuilder usesNode, Set<TypeDefinitionBuilder> collection,
+            Set<TypeDefinitionBuilder> allTypedefs, Builder parent) {
+        for (TypeDefinitionBuilder childNode : allTypedefs) {
+            boolean exists = false;
+            for (TypeDefinitionBuilder usesTypedef : usesNode.getTargetTypedefs()) {
+                if (usesTypedef.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
+                    exists = true;
+                    break;
+                }
+            }
+            if (!exists) {
+                TypeDefinitionBuilder copy = CopyUtils.copy(childNode, parent, true);
+                collection.add(copy);
+            }
+        }
+    }
+
+    /**
+     * Read groupings defined in target grouping and make a copy of them.
+     *
+     * @param usesNode
+     *            uses node for which data will be collected
+     */
+    private static void collectTargetGroupings(UsesNodeBuilder usesNode) {
         final GroupingBuilder target = usesNode.getGroupingBuilder();
-        Set<GroupingBuilder> groupings = target.getGroupingBuilders();
-        Set<GroupingBuilder> copies = new HashSet<>();
-        for (GroupingBuilder grouping : groupings) {
-            copies.add(CopyUtils.copy(grouping, usesNode.getParent(), true));
+        Set<GroupingBuilder> collection = new HashSet<>();
+        addGroupingToCollection(usesNode, collection, target.getGroupingBuilders(), usesNode.getParent());
+
+        for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
+            Set<GroupingBuilder> targetUsesGrouping = collectTargetGroupings(targetUses, usesNode.getParent());
+            addGroupingToCollection(usesNode, collection, targetUsesGrouping, usesNode.getParent());
         }
+        usesNode.getTargetGroupings().addAll(collection);
+    }
+
+    private static Set<GroupingBuilder> collectTargetGroupings(UsesNodeBuilder usesNode, DataNodeContainerBuilder parent) {
+        final GroupingBuilder target = usesNode.getGroupingBuilder();
+        Set<GroupingBuilder> collection = new HashSet<>(usesNode.getTargetGroupings());
+        addGroupingToCollection(usesNode, collection, target.getGroupingBuilders(), parent);
+
         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
-            copies.addAll(collectUsesGroupings(targetUses));
+            Set<GroupingBuilder> targetUsesGroupings = collectTargetGroupings(targetUses, parent);
+            addGroupingToCollection(usesNode, collection, targetUsesGroupings, parent);
         }
-        return copies;
+        return collection;
     }
 
-    private static List<UnknownSchemaNodeBuilder> collectUsesUnknownNodes(UsesNodeBuilder usesNode) {
+    private static void addGroupingToCollection(UsesNodeBuilder usesNode, Set<GroupingBuilder> collection,
+            Set<GroupingBuilder> allGroupings, Builder parent) {
+        for (GroupingBuilder childNode : allGroupings) {
+            boolean exists = false;
+            for (GroupingBuilder usesGrouping : usesNode.getTargetGroupings()) {
+                if (usesGrouping.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
+                    exists = true;
+                    break;
+                }
+            }
+            if (!exists) {
+                GroupingBuilder copy = CopyUtils.copy(childNode, parent, true);
+                collection.add(copy);
+            }
+        }
+    }
+
+    /**
+     * Read unknown nodes defined in target grouping and make a copy of them.
+     *
+     * @param usesNode
+     *            uses node for which data will be collected
+     */
+    private static void collectTargetUnknownNodes(UsesNodeBuilder usesNode) {
         final GroupingBuilder target = usesNode.getGroupingBuilder();
-        List<UnknownSchemaNodeBuilder> unknownNodes = target.getUnknownNodeBuilders();
-        List<UnknownSchemaNodeBuilder> copies = new ArrayList<>();
-        for (UnknownSchemaNodeBuilder unknownNode : unknownNodes) {
-            copies.add(CopyUtils.copy(unknownNode, usesNode.getParent(), true));
+        final List<UnknownSchemaNodeBuilder> collection = new ArrayList<>();
+        addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders(), usesNode.getParent());
+
+        for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
+            List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses,
+                    usesNode.getParent());
+            addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes, usesNode.getParent());
         }
+        usesNode.getTargetUnknownNodes().addAll(collection);
+    }
+
+    private static List<UnknownSchemaNodeBuilder> collectTargetUnknownNodes(UsesNodeBuilder usesNode,
+            DataNodeContainerBuilder parent) {
+        final GroupingBuilder target = usesNode.getGroupingBuilder();
+        List<UnknownSchemaNodeBuilder> collection = new ArrayList<>(usesNode.getTargetUnknownNodes());
+        addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders(), parent);
+
         for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
-            copies.addAll(collectUsesUnknownNodes(targetUses));
+            List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses, parent);
+            addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes, parent);
+        }
+        return collection;
+    }
+
+    private static void addUnknownNodeToCollection(UsesNodeBuilder usesNode, List<UnknownSchemaNodeBuilder> collection,
+            List<UnknownSchemaNodeBuilder> allUnknownNodes, Builder parent) {
+        for (UnknownSchemaNodeBuilder childNode : allUnknownNodes) {
+            boolean exists = false;
+            for (UnknownSchemaNodeBuilder usesUnknownNode : usesNode.getTargetUnknownNodes()) {
+                if (usesUnknownNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
+                    exists = true;
+                    break;
+                }
+            }
+            if (!exists) {
+                UnknownSchemaNodeBuilder copy = CopyUtils.copy(childNode, parent, true);
+                collection.add(copy);
+            }
         }
-        return copies;
     }
 
+    /**
+     * Read data defined in target grouping definition, make a copy and add them
+     * to uses node builder.
+     *
+     * @param usesNode
+     *            uses node builder
+     */
     public static void collectUsesDataFromContext(UsesNodeBuilder usesNode) {
         DataNodeContainerBuilder parent = usesNode.getParent();
         URI namespace = parent.getQName().getNamespace();
         Date revision = parent.getQName().getRevision();
         String prefix = parent.getQName().getPrefix();
-        String  moduleName = parent.getModuleName();
+        String moduleName = parent.getModuleName();
         int line = parent.getLine();
 
         // child nodes
-        final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
-        for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
-            if (child != null) {
-                DataSchemaNodeBuilder newChild = null;
-                QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
-                if (child instanceof AnyXmlSchemaNode) {
-                    newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
-                } else if (child instanceof ChoiceNode) {
-                    newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, line);
-                } else if (child instanceof ContainerSchemaNode) {
-                    newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
-                } else if (child instanceof LeafListSchemaNode) {
-                    newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
-                } else if (child instanceof LeafSchemaNode) {
-                    newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
-                } else if (child instanceof ListSchemaNode) {
-                    newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, line);
-                }
-
-                if (newChild == null) {
-                    throw new YangParseException(moduleName, line,
-                            "Unknown member of target grouping while resolving uses node.");
-                }
-                if (newChild instanceof GroupingMember) {
-                    ((GroupingMember) newChild).setAddedByUses(true);
-                }
-
-                newChild.setPath(createSchemaPath(parent.getPath(), newQName));
-                newChildren.add(newChild);
-            }
-        }
-        usesNode.setTargetChildren(newChildren);
+        copyGroupingNodesToUsesNode(usesNode, namespace, revision, prefix, moduleName, line);
 
         // groupings
         final Set<GroupingBuilder> newGroupings = new HashSet<>();
@@ -329,10 +511,9 @@ public class GroupingUtils {
             QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
             GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line);
             newGrouping.setAddedByUses(true);
-            newGrouping.setPath(createSchemaPath(parent.getPath(), newQName));
             newGroupings.add(newGrouping);
         }
-        usesNode.setTargetGroupings(newGroupings);
+        usesNode.getTargetGroupings().addAll(newGroupings);
 
         // typedefs
         final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
@@ -340,10 +521,9 @@ public class GroupingUtils {
             QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
             TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line);
             newType.setAddedByUses(true);
-            newType.setPath(createSchemaPath(parent.getPath(), newQName));
             newTypedefs.add(newType);
         }
-        usesNode.setTargetTypedefs(newTypedefs);
+        usesNode.getTargetTypedefs().addAll(newTypedefs);
 
         // unknown nodes
         final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
@@ -351,81 +531,98 @@ public class GroupingUtils {
             QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
             UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line);
             newNode.setAddedByUses(true);
-            newNode.setPath(createSchemaPath(parent.getPath(), newQName));
             newUnknownNodes.add(newNode);
         }
-        usesNode.setTargetUnknownNodes(newUnknownNodes);
+        usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
 
         usesNode.setDataCollected(true);
     }
 
-    public static void fixUsesNodesPath(UsesNodeBuilder usesNode) {
-        DataNodeContainerBuilder parent = usesNode.getParent();
+    /**
+     * Read data defined in target grouping definition, make a copy and add them
+     * to uses node builder.
+     *
+     * @param usesNode
+     *            used node builder to which are copied nodes from its
+     *            <code>GroupingDefinition</code>
+     * @param namespace
+     *            URI with parent namespace
+     * @param revision
+     *            date with parent revision date
+     * @param prefix
+     *            string with parent prefix
+     * @param moduleName
+     *            string with parent module name
+     * @param lineNumber
+     *            number with YANG file row where is the parent defined
+     */
+    private static void copyGroupingNodesToUsesNode(final UsesNodeBuilder usesNode, final URI namespace,
+            final Date revision, final String prefix, final String moduleName, final int lineNumber) {
+        final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
+        for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
+            if (child != null) {
+                DataSchemaNodeBuilder newChild = null;
+                QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
+                if (child instanceof AnyXmlSchemaNode) {
+                    newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, lineNumber);
+                } else if (child instanceof ChoiceNode) {
+                    newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, lineNumber);
+                } else if (child instanceof ContainerSchemaNode) {
+                    newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, lineNumber);
+                } else if (child instanceof LeafListSchemaNode) {
+                    newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, lineNumber);
+                } else if (child instanceof LeafSchemaNode) {
+                    newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, lineNumber);
+                } else if (child instanceof ListSchemaNode) {
+                    newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, lineNumber);
+                }
 
-        // child nodes
-        Set<DataSchemaNodeBuilder> currentChildNodes = parent.getChildNodeBuilders();
-        Set<DataSchemaNodeBuilder> toRemove = new HashSet<>();
-        Set<DataSchemaNodeBuilder> toAdd = new HashSet<>();
-        for (DataSchemaNodeBuilder child : currentChildNodes) {
-            if (child instanceof GroupingMember) {
-                GroupingMember gm = (GroupingMember) child;
-                if (gm.isAddedByUses()) {
-                    toRemove.add(child);
-                    DataSchemaNodeBuilder copy = CopyUtils.copy(child, parent, true);
-                    ParserUtils.correctNodePath(copy, parent.getPath());
-                    toAdd.add(copy);
+                if (newChild == null) {
+                    throw new YangParseException(moduleName, lineNumber,
+                            "Unknown member of target grouping while resolving uses node.");
                 }
-            }
-        }
-        currentChildNodes.removeAll(toRemove);
-        currentChildNodes.addAll(toAdd);
 
-        // groupings
-        Set<GroupingBuilder> currentGroupings = parent.getGroupingBuilders();
-        Set<GroupingBuilder> toRemoveG = new HashSet<>();
-        Set<GroupingBuilder> toAddG = new HashSet<>();
-        for (GroupingBuilder child : currentGroupings) {
-            if (child.isAddedByUses()) {
-                toRemoveG.add(child);
-                GroupingBuilder copy = CopyUtils.copy(child, parent, true);
-                ParserUtils.correctNodePath(copy, parent.getPath());
-                toAddG.add(copy);
+                ((GroupingMember) newChild).setAddedByUses(true);
+                newChildren.add(newChild);
             }
-
         }
-        currentGroupings.removeAll(toRemoveG);
-        currentGroupings.addAll(toAddG);
+        usesNode.getTargetChildren().addAll(newChildren);
 
-        // typedefs
-        Set<TypeDefinitionBuilder> currentTypedefs = parent.getTypeDefinitionBuilders();
-        Set<TypeDefinitionBuilder> toRemoveTD = new HashSet<>();
-        Set<TypeDefinitionBuilder> toAddTD = new HashSet<>();
-        for (TypeDefinitionBuilder child : currentTypedefs) {
-            if (child.isAddedByUses()) {
-                toRemoveTD.add(child);
-                TypeDefinitionBuilder copy = CopyUtils.copy(child, parent, true);
-                ParserUtils.correctNodePath(copy, parent.getPath());
-                toAddTD.add(copy);
-            }
+    }
 
+    /**
+     * Correct schema path of nodes added by uses statement.
+     *
+     * @param node
+     *            node added by uses statement
+     * @param parentSchemaPath
+     *            schema path of parent node
+     * @param parentModule
+     *            current parent node module
+     */
+    private static void correctNodePathForUsesNodes(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath,
+            final ModuleBuilder parentModule) {
+        // set correct path
+        List<QName> targetNodePath = new ArrayList<>(parentSchemaPath.getPath());
+        targetNodePath.add(new QName(parentModule.getNamespace(), parentModule.getRevision(), parentModule.getPrefix(),
+                node.getQName().getLocalName()));
+        node.setPath(new SchemaPath(targetNodePath, true));
+
+        // set correct path for all child nodes
+        if (node instanceof DataNodeContainerBuilder) {
+            DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
+            for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
+                correctNodePathForUsesNodes(child, node.getPath(), parentModule);
+            }
         }
-        currentTypedefs.removeAll(toRemoveTD);
-        currentTypedefs.addAll(toAddTD);
 
-        // unknown nodes
-        List<UnknownSchemaNodeBuilder> currentUN = parent.getUnknownNodeBuilders();
-        List<UnknownSchemaNodeBuilder> toRemoveUN = new ArrayList<>();
-        List<UnknownSchemaNodeBuilder> toAddUN = new ArrayList<>();
-        for (UnknownSchemaNodeBuilder un : currentUN) {
-            if (un.isAddedByUses()) {
-                toRemoveUN.add(un);
-                UnknownSchemaNodeBuilder copy = CopyUtils.copy(un, parent, true);
-                ParserUtils.correctNodePath(copy, parent.getPath());
-                toAddUN.add(copy);
+        // set correct path for all cases
+        if (node instanceof ChoiceBuilder) {
+            ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
+            for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
+                correctNodePathForUsesNodes(choiceCaseBuilder, node.getPath(), parentModule);
             }
         }
-        currentUN.removeAll(toRemoveUN);
-        currentUN.addAll(toAddUN);
     }
 
     /**
@@ -433,16 +630,23 @@ public class GroupingUtils {
      * already performed.
      *
      * @param usesNode
+     *            uses node containing refine statements
      */
     public static void performRefine(UsesNodeBuilder usesNode) {
         for (RefineHolder refine : usesNode.getRefines()) {
-            DataSchemaNodeBuilder nodeToRefine = null;
-            for (DataSchemaNodeBuilder dataNode : usesNode.getParent().getChildNodeBuilders()) {
-                if (refine.getName().equals(dataNode.getQName().getLocalName())) {
-                    nodeToRefine = dataNode;
-                    break;
+            String refineTargetPath = refine.getName();
+
+            String[] splitted = refineTargetPath.split("/");
+            Builder currentNode = usesNode.getParent();
+            for (String pathElement : splitted) {
+                if (currentNode instanceof DataNodeContainerBuilder) {
+                    currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
+                } else if (currentNode instanceof ChoiceBuilder) {
+                    currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
                 }
             }
+
+            DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
             if (nodeToRefine == null) {
                 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
                         + refine.getName() + "' not found");