Added support to generate interfaces from Choices and Cases.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / parser / builder / impl / ModuleBuilder.java
index 0d47d7a5fc5dbd391be57e032dd387b490c8da93..0a9b6ddf373355736e4da8247c828ef155fc37b8 100644 (file)
@@ -13,6 +13,7 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -31,10 +32,11 @@ import org.opendaylight.controller.yang.model.api.NotificationDefinition;
 import org.opendaylight.controller.yang.model.api.RpcDefinition;
 import org.opendaylight.controller.yang.model.api.SchemaPath;
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.controller.yang.model.api.UsesNode;
 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.Builder;
-import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
@@ -50,7 +52,7 @@ import org.opendaylight.controller.yang.parser.util.YangParseException;
  * module/modules, these dependencies must be resolved before module is built,
  * otherwise result may not be valid.
  */
-public class ModuleBuilder implements Builder {
+public class ModuleBuilder implements DataNodeContainerBuilder {
     private final ModuleImpl instance;
     private final String name;
     private URI namespace;
@@ -61,16 +63,11 @@ public class ModuleBuilder implements Builder {
 
     private final Set<ModuleImport> imports = new HashSet<ModuleImport>();
 
-    /**
-     * All nodes, that can contain other nodes
-     */
-    private final Map<List<String>, Builder> moduleNodes = new HashMap<List<String>, Builder>();
-
     /**
      * Holds all child (DataSchemaNode) nodes: anyxml, choice, case, container,
      * list, leaf, leaf-list.
      */
-    private final Map<List<String>, DataSchemaNodeBuilder> addedChilds = new HashMap<List<String>, DataSchemaNodeBuilder>();
+    private final Map<List<String>, DataSchemaNodeBuilder> childNodes = new HashMap<List<String>, DataSchemaNodeBuilder>();
 
     private final Map<List<String>, GroupingBuilder> addedGroupings = new HashMap<List<String>, GroupingBuilder>();
     private final List<AugmentationSchemaBuilder> addedAugments = new ArrayList<AugmentationSchemaBuilder>();
@@ -79,13 +76,16 @@ public class ModuleBuilder implements Builder {
     private final Set<NotificationBuilder> addedNotifications = new HashSet<NotificationBuilder>();
     private final Set<IdentitySchemaNodeBuilder> addedIdentities = new HashSet<IdentitySchemaNodeBuilder>();
     private final Map<List<String>, FeatureBuilder> addedFeatures = new HashMap<List<String>, FeatureBuilder>();
-    private final Map<String, DeviationBuilder> addedDeviations = new HashMap<String, DeviationBuilder>();
+    private final Map<List<String>, DeviationBuilder> addedDeviations = new HashMap<List<String>, DeviationBuilder>();
     private final Map<List<String>, TypeDefinitionBuilder> addedTypedefs = new HashMap<List<String>, TypeDefinitionBuilder>();
+    private final Map<List<String>, UnionTypeBuilder> addedUnionTypes = new HashMap<List<String>, UnionTypeBuilder>();
     private final List<ExtensionBuilder> addedExtensions = new ArrayList<ExtensionBuilder>();
-    private final Set<UnknownSchemaNodeBuilder> addedUnknownNodes = new HashSet<UnknownSchemaNodeBuilder>();
+    private final Map<List<String>, List<UnknownSchemaNodeBuilder>> addedUnknownNodes = new HashMap<List<String>, List<UnknownSchemaNodeBuilder>>();
 
     private final Map<List<String>, TypeAwareBuilder> dirtyNodes = new HashMap<List<String>, TypeAwareBuilder>();
 
+    private final LinkedList<Builder> actualPath = new LinkedList<Builder>();
+
     public ModuleBuilder(final String name) {
         this.name = name;
         instance = new ModuleImpl(name);
@@ -106,8 +106,8 @@ public class ModuleBuilder implements Builder {
         instance.setTypeDefinitions(typedefs);
 
         // CHILD NODES
-        final Map<QName, DataSchemaNode> childNodes = buildModuleChildNodes(addedChilds);
-        instance.setChildNodes(childNodes);
+        final Map<QName, DataSchemaNode> children = buildModuleChildNodes(childNodes);
+        instance.setChildNodes(children);
 
         // GROUPINGS
         final Set<GroupingDefinition> groupings = buildModuleGroupings(addedGroupings);
@@ -124,7 +124,7 @@ public class ModuleBuilder implements Builder {
         // NOTIFICATIONS
         final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
         for (NotificationBuilder entry : addedNotifications) {
-            notifications.add((NotificationDefinition) entry.build());
+            notifications.add(entry.build());
         }
         instance.setNotifications(notifications);
 
@@ -141,8 +141,7 @@ public class ModuleBuilder implements Builder {
 
         // DEVIATIONS
         final Set<Deviation> deviations = new HashSet<Deviation>();
-        for (Map.Entry<String, DeviationBuilder> entry : addedDeviations
-                .entrySet()) {
+        for (Map.Entry<List<String>, DeviationBuilder> entry : addedDeviations.entrySet()) {
             deviations.add(entry.getValue().build());
         }
         instance.setDeviations(deviations);
@@ -161,6 +160,10 @@ public class ModuleBuilder implements Builder {
         }
         instance.setIdentities(identities);
 
+        // UNKNOWN NODES
+        final List<UnknownSchemaNode> unknownNodes = buildModuleUnknownNodes(addedUnknownNodes);
+        instance.setUnknownSchemaNodes(unknownNodes);
+
         return instance;
     }
 
@@ -169,47 +172,126 @@ public class ModuleBuilder implements Builder {
         return 0;
     }
 
-    public Builder getNode(final List<String> path) {
-        return moduleNodes.get(path);
+    @Override
+    public QName getQName() {
+        return new QName(namespace, revision, prefix, name);
     }
 
-    public Set<DataSchemaNodeBuilder> getChildNodes() {
-        final Set<DataSchemaNodeBuilder> childNodes = new HashSet<DataSchemaNodeBuilder>();
-        for (Map.Entry<List<String>, DataSchemaNodeBuilder> entry : addedChilds
-                .entrySet()) {
-            List<String> path = entry.getKey();
-            DataSchemaNodeBuilder child = entry.getValue();
+    @Override
+    public SchemaPath getPath() {
+        return null;
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        final Set<TypeDefinitionBuilder> typeDefinitions = new HashSet<TypeDefinitionBuilder>();
+        for (final Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) {
+            final List<String> key = entry.getKey();
+            final TypeDefinitionBuilder typedefBuilder = entry.getValue();
+            if (key.size() == 2) {
+                typeDefinitions.add(typedefBuilder);
+
+            }
+        }
+        return typeDefinitions;
+    }
+
+    public void enterNode(final Builder node) {
+        actualPath.push(node);
+    }
+
+    public void exitNode() {
+        actualPath.pop();
+    }
+
+    public Builder getActualNode() {
+        if (actualPath.isEmpty()) {
+            return null;
+        } else {
+            return actualPath.get(0);
+        }
+    }
+
+    public Builder getActualParent() {
+        if (actualPath.size() < 2) {
+            return null;
+        } else {
+            return actualPath.get(1);
+        }
+    }
+
+    public Builder getModuleNode(final List<String> path) {
+        return childNodes.get(path);
+    }
+
+    public GroupingBuilder getGrouping(final List<String> path) {
+        return addedGroupings.get(path);
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<GroupingBuilder> getGroupingBuilders() {
+        final Set<GroupingBuilder> result = new HashSet<GroupingBuilder>();
+        for (Map.Entry<List<String>, GroupingBuilder> entry : addedGroupings.entrySet()) {
+            if (entry.getKey().size() == 2) {
+                result.add(entry.getValue());
+            }
+        }
+        return result;
+    }
+
+    public Builder getModuleTypedef(final List<String> path) {
+        return addedTypedefs.get(path);
+    }
+
+    @Override
+    public Set<DataSchemaNode> getChildNodes() {
+        return Collections.emptySet();
+    }
+
+    public Set<DataSchemaNodeBuilder> getChildNodeBuilders() {
+        final Set<DataSchemaNodeBuilder> children = new HashSet<DataSchemaNodeBuilder>();
+        for (Map.Entry<List<String>, DataSchemaNodeBuilder> entry : childNodes.entrySet()) {
+            final List<String> path = entry.getKey();
+            final DataSchemaNodeBuilder child = entry.getValue();
             if (path.size() == 2) {
-                childNodes.add(child);
+                children.add(child);
             }
         }
-        return childNodes;
+        return children;
     }
 
     public Map<List<String>, TypeAwareBuilder> getDirtyNodes() {
         return dirtyNodes;
     }
 
-    public List<AugmentationSchemaBuilder> getAddedAugments() {
+    public List<AugmentationSchemaBuilder> getAugments() {
         return addedAugments;
     }
 
-    public Set<IdentitySchemaNodeBuilder> getAddedIdentities() {
+    public Set<IdentitySchemaNodeBuilder> getIdentities() {
         return addedIdentities;
     }
 
-    public Map<List<String>, UsesNodeBuilder> getAddedUsesNodes() {
+    public Map<List<String>, UsesNodeBuilder> getUsesNodes() {
         return addedUsesNodes;
     }
 
-    public Set<UnknownSchemaNodeBuilder> getAddedUnknownNodes() {
-        return addedUnknownNodes;
+    public List<UnknownSchemaNodeBuilder> getUnknownNodes() {
+        List<UnknownSchemaNodeBuilder> result = new ArrayList<UnknownSchemaNodeBuilder>();
+        for (List<UnknownSchemaNodeBuilder> entry : addedUnknownNodes.values()) {
+            result.addAll(entry);
+        }
+        return result;
     }
 
     public Set<TypeDefinitionBuilder> getModuleTypedefs() {
-        Set<TypeDefinitionBuilder> typedefs = new HashSet<TypeDefinitionBuilder>();
-        for (Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs
-                .entrySet()) {
+        final Set<TypeDefinitionBuilder> typedefs = new HashSet<TypeDefinitionBuilder>();
+        for (Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) {
             if (entry.getKey().size() == 2) {
                 typedefs.add(entry.getValue());
             }
@@ -217,6 +299,16 @@ public class ModuleBuilder implements Builder {
         return typedefs;
     }
 
+    public Set<GroupingBuilder> getModuleGroupings() {
+        final Set<GroupingBuilder> groupings = new HashSet<GroupingBuilder>();
+        for (Map.Entry<List<String>, GroupingBuilder> entry : addedGroupings.entrySet()) {
+            if (entry.getKey().size() == 2) {
+                groupings.add(entry.getValue());
+            }
+        }
+        return groupings;
+    }
+
     public String getName() {
         return name;
     }
@@ -247,8 +339,7 @@ public class ModuleBuilder implements Builder {
 
     public void addDirtyNode(final List<String> path) {
         final List<String> dirtyNodePath = new ArrayList<String>(path);
-        final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) moduleNodes
-                .get(dirtyNodePath);
+        final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) actualPath.getFirst();
         dirtyNodes.put(dirtyNodePath, nodeBuilder);
     }
 
@@ -280,10 +371,8 @@ public class ModuleBuilder implements Builder {
         instance.setContact(contact);
     }
 
-    public boolean addModuleImport(final String moduleName,
-            final Date revision, final String prefix) {
-        final ModuleImport moduleImport = createModuleImport(moduleName,
-                revision, prefix);
+    public boolean addModuleImport(final String moduleName, final Date revision, final String prefix) {
+        final ModuleImport moduleImport = createModuleImport(moduleName, revision, prefix);
         return imports.add(moduleImport);
     }
 
@@ -297,378 +386,462 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public ContainerSchemaNodeBuilder addContainerNode(
-            final QName containerName, final List<String> parentPath,
-            final int line) {
-        final List<String> pathToNode = new ArrayList<String>(parentPath);
-        final ContainerSchemaNodeBuilder containerBuilder = new ContainerSchemaNodeBuilder(
-                containerName, line);
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToNode);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
-                containerBuilder.setAugmenting(true);
-            }
-            parent.addChildNode(containerBuilder);
+    @Override
+    public void addChildNode(DataSchemaNodeBuilder child) {
+        final List<String> pathToChild = new ArrayList<String>();
+        for (QName qname : child.getPath().getPath()) {
+            pathToChild.add(qname.getLocalName());
+        }
+        if (childNodes.containsKey(pathToChild)) {
+            throw new YangParseException(this.name, child.getLine(), "Failed to add child node "
+                    + child.getQName().getLocalName() + ": node already exists in context.");
         }
+        childNodes.put(pathToChild, child);
+    }
+
+    public ContainerSchemaNodeBuilder addContainerNode(final SchemaPath schemaPath, final QName containerName,
+            final List<String> parentPath, final int line) {
+        final List<String> pathToNode = new ArrayList<String>(parentPath);
+        final ContainerSchemaNodeBuilder containerBuilder = new ContainerSchemaNodeBuilder(containerName, schemaPath, line);
+        updateParent(containerBuilder, line, "container");
 
         pathToNode.add(containerName.getLocalName());
-        moduleNodes.put(pathToNode, containerBuilder);
-        addedChilds.put(pathToNode, containerBuilder);
+        childNodes.put(pathToNode, containerBuilder);
 
         return containerBuilder;
     }
 
-    public ListSchemaNodeBuilder addListNode(final QName listName,
-            final List<String> parentPath, final int line) {
+    public ListSchemaNodeBuilder addListNode(final SchemaPath schemaPath, final QName listName, final List<String> parentPath, final int line) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-        final ListSchemaNodeBuilder listBuilder = new ListSchemaNodeBuilder(
-                listName, line);
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToNode);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
-                listBuilder.setAugmenting(true);
-            }
-            parent.addChildNode(listBuilder);
-        }
+        final ListSchemaNodeBuilder listBuilder = new ListSchemaNodeBuilder(listName, schemaPath, line);
+        updateParent(listBuilder, line, "list");
 
         pathToNode.add(listName.getLocalName());
-        moduleNodes.put(pathToNode, listBuilder);
-        addedChilds.put(pathToNode, listBuilder);
+        childNodes.put(pathToNode, listBuilder);
 
         return listBuilder;
     }
 
-    public LeafSchemaNodeBuilder addLeafNode(final QName leafName,
-            final List<String> parentPath, final int line) {
+    public LeafSchemaNodeBuilder addLeafNode(final SchemaPath schemaPath, final QName leafName, final List<String> parentPath, final int line) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-        final LeafSchemaNodeBuilder leafBuilder = new LeafSchemaNodeBuilder(
-                leafName, line);
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToNode);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
-                leafBuilder.setAugmenting(true);
-            }
-            parent.addChildNode(leafBuilder);
-        }
+        final LeafSchemaNodeBuilder leafBuilder = new LeafSchemaNodeBuilder(leafName, schemaPath, line);
+        updateParent(leafBuilder, line, "leaf");
 
         pathToNode.add(leafName.getLocalName());
-        addedChilds.put(pathToNode, leafBuilder);
-        moduleNodes.put(pathToNode, leafBuilder);
+        childNodes.put(pathToNode, leafBuilder);
 
         return leafBuilder;
     }
 
-    public LeafListSchemaNodeBuilder addLeafListNode(final QName leafListName,
-            final List<String> parentPath, final int line) {
+    public LeafListSchemaNodeBuilder addLeafListNode(final SchemaPath schemaPath, final QName qname, final List<String> parentPath, final int line) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-        final LeafListSchemaNodeBuilder leafListBuilder = new LeafListSchemaNodeBuilder(
-                leafListName, line);
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToNode);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
-                leafListBuilder.setAugmenting(true);
-            }
-            parent.addChildNode(leafListBuilder);
-        }
+        final LeafListSchemaNodeBuilder leafListBuilder = new LeafListSchemaNodeBuilder(qname, schemaPath, line);
+        updateParent(leafListBuilder, line, "leaf-list");
 
-        pathToNode.add(leafListName.getLocalName());
-        addedChilds.put(pathToNode, leafListBuilder);
-        moduleNodes.put(pathToNode, leafListBuilder);
+        pathToNode.add(qname.getLocalName());
+        childNodes.put(pathToNode, leafListBuilder);
 
         return leafListBuilder;
     }
 
-    public GroupingBuilder addGrouping(final QName qname,
-            final List<String> parentPath, final int line) {
+    @Override
+    public void addGrouping(GroupingBuilder groupingBuilder) {
+        final List<String> pathToGroup = new ArrayList<String>();
+        for (QName qname : groupingBuilder.getPath().getPath()) {
+            pathToGroup.add(qname.getLocalName());
+        }
+        if (addedGroupings.containsKey(pathToGroup)) {
+            throw new YangParseException(this.name, groupingBuilder.getLine(), "Failed to add grouping "
+                    + groupingBuilder.getQName().getLocalName() + ": grouping already exists in context.");
+        }
+        addedGroupings.put(pathToGroup, groupingBuilder);
+    }
+
+    public GroupingBuilder addGrouping(final QName qname, final List<String> parentPath, final int line) {
         final List<String> pathToGroup = new ArrayList<String>(parentPath);
         final GroupingBuilder builder = new GroupingBuilderImpl(qname, line);
-        final ChildNodeBuilder parentNodeBuilder = (ChildNodeBuilder) moduleNodes
-                .get(pathToGroup);
-        if (parentNodeBuilder != null) {
-            parentNodeBuilder.addGrouping(builder);
+
+        if (!(actualPath.isEmpty())) {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof DataNodeContainerBuilder) {
+                ((DataNodeContainerBuilder) parent).addGrouping(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of grouping " + qname.getLocalName());
+            }
         }
 
-        pathToGroup.add("grouping");
         pathToGroup.add(qname.getLocalName());
-        moduleNodes.put(pathToGroup, builder);
         addedGroupings.put(pathToGroup, builder);
 
         return builder;
     }
 
-    public AugmentationSchemaBuilder addAugment(final String name,
-            final List<String> parentPath, final int line) {
+    public AugmentationSchemaBuilder addAugment(final String name, final List<String> parentPath, final int line) {
         final List<String> pathToAugment = new ArrayList<String>(parentPath);
-        final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(
-                name, line);
+        Builder parent = null;
+        if (!(actualPath.isEmpty())) {
+            parent = actualPath.getFirst();
+        }
+        final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name, line, parent);
 
         // augment can only be in 'module' or 'uses' statement
-        final UsesNodeBuilder parent = addedUsesNodes.get(pathToAugment);
         if (parent != null) {
-            parent.addAugment(builder);
+            if (parent instanceof UsesNodeBuilder) {
+                ((UsesNodeBuilder) parent).addAugment(builder);
+            } else {
+                throw new YangParseException(this.name, line, "Unresolved parent of augment " + name);
+            }
         }
 
         pathToAugment.add(name);
-        moduleNodes.put(pathToAugment, builder);
         addedAugments.add(builder);
 
         return builder;
     }
 
-    public UsesNodeBuilder addUsesNode(final String groupingPathStr,
-            final List<String> parentPath, final int line) {
+    @Override
+    public void addUsesNode(UsesNodeBuilder usesBuilder) {
+        final List<String> pathToTypedef = new ArrayList<String>();
+        for (QName qname : usesBuilder.getParent().getPath().getPath()) {
+            pathToTypedef.add(qname.getLocalName());
+        }
+        if (addedUsesNodes.containsKey(pathToTypedef)) {
+            throw new YangParseException(this.name, usesBuilder.getLine(), "Failed to add uses node "
+                    + usesBuilder.getGroupingName() + ": uses already exists in context.");
+        }
+        addedUsesNodes.put(pathToTypedef, usesBuilder);
+    }
+
+    public UsesNodeBuilder addUsesNode(final String groupingPathStr, final List<String> parentPath, final int line) {
         final List<String> pathToUses = new ArrayList<String>(parentPath);
-        final UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(
-                groupingPathStr, line);
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToUses);
-        if (parent != null) {
-            parent.addUsesNode(usesBuilder);
+        Builder parent = null;
+        if (!actualPath.isEmpty()) {
+            parent = actualPath.getFirst();
+        }
+        if (parent != null && !(parent instanceof DataNodeContainerBuilder)) {
+            throw new YangParseException(name, line, "Unresolved parent of uses " + groupingPathStr);
+        }
+        final UsesNodeBuilder usesBuilder;
+        if (parent == null) {
+            usesBuilder = new UsesNodeBuilderImpl(groupingPathStr, line, this);
+        } else {
+            usesBuilder = new UsesNodeBuilderImpl(groupingPathStr, line, (DataNodeContainerBuilder) parent);
+            if (parent instanceof AugmentationSchemaBuilder) {
+                usesBuilder.setAugmenting(true);
+            }
+            ((DataNodeContainerBuilder) parent).addUsesNode(usesBuilder);
         }
 
         pathToUses.add(groupingPathStr);
         addedUsesNodes.put(pathToUses, usesBuilder);
-        moduleNodes.put(pathToUses, usesBuilder);
         return usesBuilder;
     }
 
-    public void addRefine(final RefineHolder refine,
-            final List<String> parentPath) {
+    public void addRefine(final RefineHolder refine, final List<String> parentPath) {
         final List<String> path = new ArrayList<String>(parentPath);
-        final Builder parent = moduleNodes.get(path);
-        if (!(parent instanceof UsesNodeBuilder)) {
-            throw new YangParseException("Failed to parse refine "
-                    + refine.getName());
+
+        if (actualPath.isEmpty()) {
+            throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
+        } else {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof UsesNodeBuilder) {
+                ((UsesNodeBuilder) parent).addRefine(refine);
+            } else {
+                throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
+            }
         }
-        UsesNodeBuilder usesBuilder = (UsesNodeBuilder) parent;
-        usesBuilder.addRefine(refine);
+
         path.add(refine.getName());
-        moduleNodes.put(path, refine);
     }
 
-    public RpcDefinitionBuilder addRpc(final QName qname,
-            final List<String> parentPath, final int line) {
+    public RpcDefinitionBuilder addRpc(final QName qname, final List<String> parentPath, final int line) {
+
+        if (!(actualPath.isEmpty())) {
+            throw new YangParseException(name, line, "rpc can be defined only in module or submodule");
+        }
+
         final List<String> pathToRpc = new ArrayList<String>(parentPath);
-        final RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(qname,
-                line);
+        final RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(qname, line);
 
         pathToRpc.add(qname.getLocalName());
         addedRpcs.put(pathToRpc, rpcBuilder);
 
-        final QName inputQName = new QName(qname.getNamespace(),
-                qname.getRevision(), qname.getPrefix(), "input");
-        final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(
-                inputQName, line);
-        final List<String> pathToInput = new ArrayList<String>(pathToRpc);
-        pathToInput.add("input");
-        moduleNodes.put(pathToInput, inputBuilder);
-        rpcBuilder.setInput(inputBuilder);
-
-        final QName outputQName = new QName(qname.getNamespace(),
-                qname.getRevision(), qname.getPrefix(), "output");
-        final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(
-                outputQName, line);
-        final List<String> pathToOutput = new ArrayList<String>(pathToRpc);
-        pathToOutput.add("output");
-        moduleNodes.put(pathToOutput, outputBuilder);
-        rpcBuilder.setOutput(outputBuilder);
-
         return rpcBuilder;
     }
 
-    public NotificationBuilder addNotification(final QName notificationName,
-            final List<String> parentPath, final int line) {
-        final List<String> pathToNotification = new ArrayList<String>(
-                parentPath);
+    public ContainerSchemaNodeBuilder addRpcInput(final SchemaPath schemaPath, final QName inputQName, final int line) {
+        final Builder parent = actualPath.getFirst();
+        if (!(parent instanceof RpcDefinitionBuilder)) {
+            throw new YangParseException(name, line, "input can be defined only in rpc statement");
+        }
+        final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
 
-        NotificationBuilder builder = new NotificationBuilder(notificationName,
-                line);
+        final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(inputQName, schemaPath, line);
+        rpc.setInput(inputBuilder);
+        return inputBuilder;
+    }
+
+    public ContainerSchemaNodeBuilder addRpcOutput(final SchemaPath schemaPath, final QName outputQName, final int line) {
+        final Builder parent = actualPath.getFirst();
+        if (!(parent instanceof RpcDefinitionBuilder)) {
+            throw new YangParseException(name, line, "output can be defined only in rpc statement");
+        }
+        final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
 
-        pathToNotification.add(notificationName.getLocalName());
-        moduleNodes.put(pathToNotification, builder);
+        final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(outputQName, schemaPath, line);
+        rpc.setOutput(outputBuilder);
+        return outputBuilder;
+    }
+
+    public NotificationBuilder addNotification(final QName notificationName, final List<String> parentPath,
+            final int line) {
+        if (!(actualPath.isEmpty())) {
+            throw new YangParseException(name, line, "notification can be defined only in module or submodule");
+        }
+        final NotificationBuilder builder = new NotificationBuilder(notificationName, line);
+
+        final List<String> notificationPath = new ArrayList<String>(parentPath);
+        notificationPath.add(notificationName.getLocalName());
         addedNotifications.add(builder);
 
         return builder;
     }
 
-    public FeatureBuilder addFeature(final QName featureName,
-            final List<String> parentPath, final int line) {
-        List<String> pathToFeature = new ArrayList<String>(parentPath);
+    public FeatureBuilder addFeature(final QName featureName, final List<String> parentPath, final int line) {
+        if (!(actualPath.isEmpty())) {
+            throw new YangParseException(name, line, "feature can be defined only in module or submodule");
+        }
+
+        final List<String> pathToFeature = new ArrayList<String>(parentPath);
         pathToFeature.add(featureName.getLocalName());
 
-        FeatureBuilder builder = new FeatureBuilder(featureName, line);
+        final FeatureBuilder builder = new FeatureBuilder(featureName, line);
         addedFeatures.put(pathToFeature, builder);
         return builder;
     }
 
-    public ChoiceBuilder addChoice(final QName choiceName,
-            final List<String> parentPath, final int line) {
-        List<String> pathToChoice = new ArrayList<String>(parentPath);
-        ChoiceBuilder builder = new ChoiceBuilder(choiceName, line);
+    public ChoiceBuilder addChoice(final QName choiceName, final List<String> parentPath, final int line) {
+        final List<String> pathToChoice = new ArrayList<String>(parentPath);
+        final ChoiceBuilder builder = new ChoiceBuilder(choiceName, line);
 
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToChoice);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
-                builder.setAugmenting(true);
+        if (!(actualPath.isEmpty())) {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof DataNodeContainerBuilder) {
+                if (parent instanceof AugmentationSchemaBuilder) {
+                    builder.setAugmenting(true);
+                }
+                ((DataNodeContainerBuilder) parent).addChildNode(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of choice " + choiceName.getLocalName());
             }
-            parent.addChildNode(builder);
         }
 
         pathToChoice.add(choiceName.getLocalName());
-        addedChilds.put(pathToChoice, builder);
-        moduleNodes.put(pathToChoice, builder);
+        childNodes.put(pathToChoice, builder);
 
         return builder;
     }
 
-    public ChoiceCaseBuilder addCase(final QName caseName,
-            final List<String> parentPath, final int line) {
-        List<String> pathToCase = new ArrayList<String>(parentPath);
-        ChoiceCaseBuilder builder = new ChoiceCaseBuilder(caseName, line);
+    public ChoiceCaseBuilder addCase(final QName caseName, final List<String> parentPath, final int line) {
+        Builder parent = getActualNode();
 
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToCase);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
+        final List<String> pathToCase = new ArrayList<String>(parentPath);
+        ChoiceCaseBuilder builder = null;
+        if (parent instanceof ChoiceBuilder) {
+            builder = new ChoiceCaseBuilder((ChoiceBuilder) parent, caseName, line);
+        } else {
+            builder = new ChoiceCaseBuilder(null, caseName, line);
+        }
+
+        if (actualPath.isEmpty()) {
+            throw new YangParseException(name, line, "'case' parent not found");
+        } else {
+            if (parent instanceof ChoiceBuilder) {
+                ((ChoiceBuilder) parent).addChildNode(builder);
+            } else if (parent instanceof AugmentationSchemaBuilder) {
                 builder.setAugmenting(true);
+                ((AugmentationSchemaBuilder) parent).addChildNode(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of 'case' " + caseName.getLocalName());
             }
-            parent.addChildNode(builder);
         }
 
         pathToCase.add(caseName.getLocalName());
-        moduleNodes.put(pathToCase, builder);
+        childNodes.put(pathToCase, builder);
 
         return builder;
     }
 
-    public AnyXmlBuilder addAnyXml(final QName anyXmlName,
-            final List<String> parentPath, final int line) {
-        List<String> pathToAnyXml = new ArrayList<String>(parentPath);
-        AnyXmlBuilder builder = new AnyXmlBuilder(anyXmlName, line);
-
-        final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
-                .get(pathToAnyXml);
-        if (parent != null) {
-            if (parent instanceof AugmentationSchemaBuilder) {
-                throw new YangParseException(
-                        "An anyxml node cannot be augmented.");
-            }
-            parent.addChildNode(builder);
-        }
+    public AnyXmlBuilder addAnyXml(final SchemaPath schemaPath, final QName anyXmlName, final List<String> parentPath, final int line) {
+        final List<String> pathToAnyXml = new ArrayList<String>(parentPath);
+        final AnyXmlBuilder builder = new AnyXmlBuilder(anyXmlName, schemaPath, line);
+        updateParent(builder, line, "anyxml");
 
         pathToAnyXml.add(anyXmlName.getLocalName());
-        addedChilds.put(pathToAnyXml, builder);
-        moduleNodes.put(pathToAnyXml, builder);
+        childNodes.put(pathToAnyXml, builder);
 
         return builder;
     }
 
-    public TypedefBuilder addTypedef(final QName typeDefName,
-            final List<String> parentPath, final int line) {
-        List<String> pathToType = new ArrayList<String>(parentPath);
-        TypedefBuilder builder = new TypedefBuilder(typeDefName, line);
-        TypeDefinitionAwareBuilder parent = (TypeDefinitionAwareBuilder) moduleNodes
-                .get(pathToType);
-        if (parent != null) {
-            parent.addTypedef(builder);
+    @Override
+    public void addTypedef(TypeDefinitionBuilder typedefBuilder) {
+        final List<String> pathToTypedef = new ArrayList<String>();
+        for (QName qname : typedefBuilder.getPath().getPath()) {
+            pathToTypedef.add(qname.getLocalName());
+        }
+        if (addedTypedefs.containsKey(pathToTypedef)) {
+            throw new YangParseException(this.name, typedefBuilder.getLine(), "Failed to add typedef "
+                    + typedefBuilder.getQName().getLocalName() + ": typedef already exists in context.");
+        }
+        addedTypedefs.put(pathToTypedef, typedefBuilder);
+    }
+
+    public TypeDefinitionBuilderImpl addTypedef(final QName typeDefName, final List<String> parentPath, final int line) {
+        final List<String> pathToType = new ArrayList<String>(parentPath);
+        final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(typeDefName, line);
+
+        if (!(actualPath.isEmpty())) {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof TypeDefinitionAwareBuilder) {
+                ((TypeDefinitionAwareBuilder) parent).addTypedef(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of typedef " + typeDefName.getLocalName());
+            }
         }
+
         pathToType.add(typeDefName.getLocalName());
         addedTypedefs.put(pathToType, builder);
-        moduleNodes.put(pathToType, builder);
         return builder;
     }
 
-    public void setType(TypeDefinition<?> type, List<String> parentPath) {
-        TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes
-                .get(parentPath);
-        if (parent == null) {
-            throw new YangParseException("Failed to set type '"
-                    + type.getQName().getLocalName()
-                    + "'. Parent node not found.");
+    public void setType(final TypeDefinition<?> type, final List<String> parentPath) {
+        if (!(actualPath.isEmpty())) {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof TypeAwareBuilder) {
+                ((TypeAwareBuilder) parent).setType(type);
+            } else {
+                throw new YangParseException("Failed to set type '" + type.getQName().getLocalName()
+                        + "'. Unknown parent node: " + parent);
+            }
         }
-        parent.setType(type);
     }
 
-    public UnionTypeBuilder addUnionType(final List<String> actualPath,
-            final URI namespace, final Date revision, final int line) {
-        List<String> pathToUnion = new ArrayList<String>(actualPath);
-        TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes
-                .get(pathToUnion);
-        UnionTypeBuilder union = new UnionTypeBuilder(line);
-        parent.setType(union);
+    public UnionTypeBuilder addUnionType(final List<String> currentPath, final URI namespace, final Date revision,
+            final int line) {
+        final List<String> pathToUnion = new ArrayList<String>(currentPath);
+        final UnionTypeBuilder union = new UnionTypeBuilder(line);
+
+        if (actualPath.isEmpty()) {
+            throw new YangParseException(line, "union error");
+        } else {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof TypeAwareBuilder) {
 
-        List<String> path = new ArrayList<String>(pathToUnion);
-        path.add("union");
+                ((TypeAwareBuilder) parent).setTypedef(union);
 
-        moduleNodes.put(path, union);
-        return union;
+                final List<String> path = new ArrayList<String>(pathToUnion);
+                path.add("union");
+
+                addedUnionTypes.put(path, union);
+                return union;
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of union type.");
+            }
+        }
     }
 
-    public void addIdentityrefType(final String baseString,
-            final List<String> parentPath, final SchemaPath schemaPath,
+    public void addIdentityrefType(final String baseString, final List<String> parentPath, final SchemaPath schemaPath,
             final int line) {
-        List<String> pathToIdentityref = new ArrayList<String>(parentPath);
-        TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes
-                .get(pathToIdentityref);
-        IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(
-                baseString, schemaPath, line);
-        parent.setType(identityref);
-        dirtyNodes.put(pathToIdentityref, parent);
+        final List<String> pathToIdentityref = new ArrayList<String>(parentPath);
+        final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(baseString, schemaPath, line);
+
+        if (actualPath.isEmpty()) {
+            throw new YangParseException(line, "identityref error");
+        } else {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof TypeAwareBuilder) {
+                final TypeAwareBuilder typeParent = (TypeAwareBuilder) parent;
+                typeParent.setTypedef(identityref);
+                dirtyNodes.put(pathToIdentityref, typeParent);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of identityref type.");
+            }
+        }
     }
 
-    public DeviationBuilder addDeviation(final String targetPath,
-            final List<String> parentPath, final int line) {
+    public DeviationBuilder addDeviation(final String targetPath, final List<String> parentPath, final int line) {
+        if (!(actualPath.isEmpty())) {
+            throw new YangParseException(name, line, "deviation can be defined only in module or submodule");
+        }
+
         final List<String> pathToDeviation = new ArrayList<String>(parentPath);
         pathToDeviation.add(targetPath);
-        DeviationBuilder builder = new DeviationBuilder(targetPath, line);
-        addedDeviations.put(targetPath, builder);
-        moduleNodes.put(pathToDeviation, builder);
+        final DeviationBuilder builder = new DeviationBuilder(targetPath, line);
+        addedDeviations.put(pathToDeviation, builder);
         return builder;
     }
 
-    public IdentitySchemaNodeBuilder addIdentity(final QName qname,
-            final List<String> parentPath, final int line) {
+    public IdentitySchemaNodeBuilder addIdentity(final QName qname, final List<String> parentPath, final int line) {
+        if (!(actualPath.isEmpty())) {
+            throw new YangParseException(name, line, "identity can be defined only in module or submodule");
+        }
+
         final List<String> pathToIdentity = new ArrayList<String>(parentPath);
-        final IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(
-                qname, line);
+        final IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(qname, line);
         pathToIdentity.add(qname.getLocalName());
-        moduleNodes.put(pathToIdentity, builder);
         addedIdentities.add(builder);
         return builder;
     }
 
-    public void addConfiguration(boolean configuration, List<String> parentPath) {
-        Builder builder = moduleNodes.get(parentPath);
-        // current api did not support adding config to deviate
-        if (!(builder instanceof DeviationBuilder)) {
-            if(builder instanceof RefineHolder) {
-                ((RefineHolder)builder).setConfig(configuration);
+    @Override
+    public void addUnknownSchemaNode(UnknownSchemaNodeBuilder unknownNode) {
+        final List<String> unPath = new ArrayList<String>();
+        for (QName qname : unknownNode.getPath().getPath()) {
+            unPath.add(qname.getLocalName());
+        }
+
+        if (addedUnknownNodes.containsKey(unPath)) {
+            addedUnknownNodes.get(unPath).add(unknownNode);
+        } else {
+            List<UnknownSchemaNodeBuilder> nodes = new ArrayList<UnknownSchemaNodeBuilder>();
+            nodes.add(unknownNode);
+            addedUnknownNodes.put(unPath, nodes);
+        }
+    }
+
+    public UnknownSchemaNodeBuilder addUnknownSchemaNode(final QName qname, final List<String> parentPath,
+            final int line) {
+        final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(qname, line);
+
+        if (!(actualPath.isEmpty())) {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof SchemaNodeBuilder) {
+                ((SchemaNodeBuilder) parent).addUnknownSchemaNode(builder);
+            } else if (parent instanceof RefineHolder) {
+                ((RefineHolder) parent).addUnknownSchemaNode(builder);
             } else {
-                ((DataSchemaNodeBuilder)builder).setConfiguration(configuration);
+                throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
+                        + "'");
             }
         }
-    }
+        final List<String> unPath = new ArrayList<String>(parentPath);
+        unPath.add(qname.getLocalName());
 
-    public UnknownSchemaNodeBuilder addUnknownSchemaNode(final QName qname,
-            final List<String> parentPath, final int line) {
-        final List<String> pathToUnknown = new ArrayList<String>(parentPath);
-        final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(
-                qname, line);
-        final Builder parent = moduleNodes.get(pathToUnknown);
-        if (parent instanceof RefineHolder) {
-            ((RefineHolder) parent).addUnknownSchemaNode(builder);
-        } else if (parent instanceof SchemaNodeBuilder) {
-            ((SchemaNodeBuilder) parent).addUnknownSchemaNode(builder);
-        }
-        addedUnknownNodes.add(builder);
+        if (addedUnknownNodes.containsKey(unPath)) {
+            addedUnknownNodes.get(unPath).add(builder);
+        } else {
+            List<UnknownSchemaNodeBuilder> nodes = new ArrayList<UnknownSchemaNodeBuilder>();
+            nodes.add(builder);
+            addedUnknownNodes.put(unPath, nodes);
+        }
         return builder;
     }
 
+    @Override
+    public String toString() {
+        return ModuleBuilder.class.getSimpleName() + "[" + name + "]";
+    }
+
     private final class ModuleImpl implements Module {
         private URI namespace;
         private final String name;
@@ -682,17 +855,16 @@ public class ModuleBuilder implements Builder {
         private Set<ModuleImport> imports = Collections.emptySet();
         private Set<FeatureDefinition> features = Collections.emptySet();
         private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
-        private Set<NotificationDefinition> notifications = Collections
-                .emptySet();
+        private Set<NotificationDefinition> notifications = Collections.emptySet();
         private Set<AugmentationSchema> augmentations = Collections.emptySet();
         private Set<RpcDefinition> rpcs = Collections.emptySet();
         private Set<Deviation> deviations = Collections.emptySet();
         private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
         private Set<GroupingDefinition> groupings = Collections.emptySet();
         private Set<UsesNode> uses = Collections.emptySet();
-        private List<ExtensionDefinition> extensionNodes = Collections
-                .emptyList();
+        private List<ExtensionDefinition> extensionNodes = Collections.emptyList();
         private Set<IdentitySchemaNode> identities = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
 
         private ModuleImpl(String name) {
             this.name = name;
@@ -890,8 +1062,7 @@ public class ModuleBuilder implements Builder {
             return extensionNodes;
         }
 
-        private void setExtensionSchemaNodes(
-                List<ExtensionDefinition> extensionNodes) {
+        private void setExtensionSchemaNodes(final List<ExtensionDefinition> extensionNodes) {
             if (extensionNodes != null) {
                 this.extensionNodes = extensionNodes;
             }
@@ -902,12 +1073,23 @@ public class ModuleBuilder implements Builder {
             return identities;
         }
 
-        private void setIdentities(Set<IdentitySchemaNode> identities) {
+        private void setIdentities(final Set<IdentitySchemaNode> identities) {
             if (identities != null) {
                 this.identities = identities;
             }
         }
 
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
         @Override
         public DataSchemaNode getDataChildByName(QName name) {
             return childNodes.get(name);
@@ -929,15 +1111,11 @@ public class ModuleBuilder implements Builder {
         public int hashCode() {
             final int prime = 31;
             int result = 1;
-            result = prime * result
-                    + ((namespace == null) ? 0 : namespace.hashCode());
+            result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
             result = prime * result + ((name == null) ? 0 : name.hashCode());
-            result = prime * result
-                    + ((revision == null) ? 0 : revision.hashCode());
-            result = prime * result
-                    + ((prefix == null) ? 0 : prefix.hashCode());
-            result = prime * result
-                    + ((yangVersion == null) ? 0 : yangVersion.hashCode());
+            result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+            result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
+            result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode());
             return result;
         }
 
@@ -993,8 +1171,7 @@ public class ModuleBuilder implements Builder {
 
         @Override
         public String toString() {
-            StringBuilder sb = new StringBuilder(
-                    ModuleImpl.class.getSimpleName());
+            StringBuilder sb = new StringBuilder(ModuleImpl.class.getSimpleName());
             sb.append("[");
             sb.append("name=" + name);
             sb.append(", namespace=" + namespace);
@@ -1006,9 +1183,25 @@ public class ModuleBuilder implements Builder {
         }
     }
 
-    private ModuleImport createModuleImport(final String moduleName,
-            final Date revision, final String prefix) {
-        ModuleImport moduleImport = new ModuleImport() {
+    private void updateParent(DataSchemaNodeBuilder nodeBuilder, int line, String nodeTypeName) {
+        if (!(actualPath.isEmpty())) {
+            final Builder parent = actualPath.getFirst();
+            if (parent instanceof DataNodeContainerBuilder) {
+                if (parent instanceof AugmentationSchemaBuilder) {
+                    nodeBuilder.setAugmenting(true);
+                }
+                ((DataNodeContainerBuilder) parent).addChildNode(nodeBuilder);
+            } else if (parent instanceof ChoiceBuilder) {
+                ((ChoiceBuilder) parent).addChildNode(nodeBuilder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of " + nodeTypeName + " "
+                        + nodeBuilder.getQName().getLocalName());
+            }
+        }
+    }
+
+    private ModuleImport createModuleImport(final String moduleName, final Date revision, final String prefix) {
+        final ModuleImport moduleImport = new ModuleImport() {
             @Override
             public String getModuleName() {
                 return moduleName;
@@ -1028,12 +1221,9 @@ public class ModuleBuilder implements Builder {
             public int hashCode() {
                 final int prime = 31;
                 int result = 1;
-                result = prime * result
-                        + ((moduleName == null) ? 0 : moduleName.hashCode());
-                result = prime * result
-                        + ((revision == null) ? 0 : revision.hashCode());
-                result = prime * result
-                        + ((prefix == null) ? 0 : prefix.hashCode());
+                result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode());
+                result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+                result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
                 return result;
             }
 
@@ -1075,8 +1265,7 @@ public class ModuleBuilder implements Builder {
 
             @Override
             public String toString() {
-                return "ModuleImport[moduleName=" + moduleName + ", revision="
-                        + revision + ", prefix=" + prefix + "]";
+                return "ModuleImport[moduleName=" + moduleName + ", revision=" + revision + ", prefix=" + prefix + "]";
             }
         };
         return moduleImport;
@@ -1090,11 +1279,9 @@ public class ModuleBuilder implements Builder {
      * @return map of children, where key is child QName and value is child
      *         itself
      */
-    private Map<QName, DataSchemaNode> buildModuleChildNodes(
-            Map<List<String>, DataSchemaNodeBuilder> addedChilds) {
+    private Map<QName, DataSchemaNode> buildModuleChildNodes(Map<List<String>, DataSchemaNodeBuilder> addedChilds) {
         final Map<QName, DataSchemaNode> childNodes = new HashMap<QName, DataSchemaNode>();
-        for (Map.Entry<List<String>, DataSchemaNodeBuilder> entry : addedChilds
-                .entrySet()) {
+        for (Map.Entry<List<String>, DataSchemaNodeBuilder> entry : addedChilds.entrySet()) {
             List<String> path = entry.getKey();
             DataSchemaNodeBuilder child = entry.getValue();
             if (path.size() == 2) {
@@ -1114,12 +1301,10 @@ public class ModuleBuilder implements Builder {
      * @param addedGroupings
      * @return set of built GroupingDefinition objects
      */
-    private Set<GroupingDefinition> buildModuleGroupings(
-            Map<List<String>, GroupingBuilder> addedGroupings) {
+    private Set<GroupingDefinition> buildModuleGroupings(Map<List<String>, GroupingBuilder> addedGroupings) {
         final Set<GroupingDefinition> groupings = new HashSet<GroupingDefinition>();
-        for (Map.Entry<List<String>, GroupingBuilder> entry : addedGroupings
-                .entrySet()) {
-            if (entry.getKey().size() == 3) {
+        for (Map.Entry<List<String>, GroupingBuilder> entry : addedGroupings.entrySet()) {
+            if (entry.getKey().size() == 2) {
                 groupings.add(entry.getValue().build());
             }
         }
@@ -1132,12 +1317,10 @@ public class ModuleBuilder implements Builder {
      * @param addedRpcs
      * @return set of built RpcDefinition objects
      */
-    private Set<RpcDefinition> buildModuleRpcs(
-            Map<List<String>, RpcDefinitionBuilder> addedRpcs) {
+    private Set<RpcDefinition> buildModuleRpcs(Map<List<String>, RpcDefinitionBuilder> addedRpcs) {
         final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
         RpcDefinitionBuilder builder;
-        for (Map.Entry<List<String>, RpcDefinitionBuilder> entry : addedRpcs
-                .entrySet()) {
+        for (Map.Entry<List<String>, RpcDefinitionBuilder> entry : addedRpcs.entrySet()) {
             builder = entry.getValue();
             RpcDefinition rpc = builder.build();
             rpcs.add(rpc);
@@ -1153,16 +1336,13 @@ public class ModuleBuilder implements Builder {
      * @param addedTypedefs
      * @return set of built module typedef statements
      */
-    private Set<TypeDefinition<?>> buildModuleTypedefs(
-            Map<List<String>, TypeDefinitionBuilder> addedTypedefs) {
+    private Set<TypeDefinition<?>> buildModuleTypedefs(Map<List<String>, TypeDefinitionBuilder> addedTypedefs) {
         Set<TypeDefinition<?>> typedefs = new HashSet<TypeDefinition<?>>();
-        for (Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs
-                .entrySet()) {
+        for (Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) {
             List<String> key = entry.getKey();
             TypeDefinitionBuilder typedefBuilder = entry.getValue();
             if (key.size() == 2) {
-                TypeDefinition<? extends TypeDefinition<?>> node = typedefBuilder
-                        .build();
+                TypeDefinition<? extends TypeDefinition<?>> node = typedefBuilder.build();
                 typedefs.add(node);
             }
         }
@@ -1177,11 +1357,9 @@ public class ModuleBuilder implements Builder {
      * @param addedUsesNodes
      * @return set of built module uses nodes
      */
-    private Set<UsesNode> buildUsesNodes(
-            Map<List<String>, UsesNodeBuilder> addedUsesNodes) {
+    private Set<UsesNode> buildUsesNodes(Map<List<String>, UsesNodeBuilder> addedUsesNodes) {
         final Set<UsesNode> usesNodeDefs = new HashSet<UsesNode>();
-        for (Map.Entry<List<String>, UsesNodeBuilder> entry : addedUsesNodes
-                .entrySet()) {
+        for (Map.Entry<List<String>, UsesNodeBuilder> entry : addedUsesNodes.entrySet()) {
             if (entry.getKey().size() == 2) {
                 usesNodeDefs.add(entry.getValue().build());
             }
@@ -1196,11 +1374,9 @@ public class ModuleBuilder implements Builder {
      * @param addedFeatures
      * @return set of built module features
      */
-    private Set<FeatureDefinition> buildModuleFeatures(
-            Map<List<String>, FeatureBuilder> addedFeatures) {
+    private Set<FeatureDefinition> buildModuleFeatures(Map<List<String>, FeatureBuilder> addedFeatures) {
         Set<FeatureDefinition> features = new HashSet<FeatureDefinition>();
-        for (Map.Entry<List<String>, FeatureBuilder> entry : addedFeatures
-                .entrySet()) {
+        for (Map.Entry<List<String>, FeatureBuilder> entry : addedFeatures.entrySet()) {
             if (entry.getKey().size() == 2) {
                 features.add(entry.getValue().build());
             }
@@ -1208,4 +1384,20 @@ public class ModuleBuilder implements Builder {
         return features;
     }
 
+    private List<UnknownSchemaNode> buildModuleUnknownNodes(
+            final Map<List<String>, List<UnknownSchemaNodeBuilder>> addedUnknownNodes) {
+        final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+        for (Map.Entry<List<String>, List<UnknownSchemaNodeBuilder>> entry : addedUnknownNodes.entrySet()) {
+            final List<String> path = entry.getKey();
+            final List<UnknownSchemaNodeBuilder> child = entry.getValue();
+            for (UnknownSchemaNodeBuilder un : child) {
+                if (path.size() == 2) {
+                    final UnknownSchemaNode node = un.build();
+                    unknownNodes.add(node);
+                }
+            }
+        }
+        return unknownNodes;
+    }
+
 }