Refactored parsing of YANG uses statement.
[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 6940e91e382247b384157f715d02fe4f948411fb..0a9b6ddf373355736e4da8247c828ef155fc37b8 100644 (file)
@@ -32,6 +32,7 @@ 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;
@@ -51,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;
@@ -71,7 +72,6 @@ public class ModuleBuilder implements Builder {
     private final Map<List<String>, GroupingBuilder> addedGroupings = new HashMap<List<String>, GroupingBuilder>();
     private final List<AugmentationSchemaBuilder> addedAugments = new ArrayList<AugmentationSchemaBuilder>();
     private final Map<List<String>, UsesNodeBuilder> addedUsesNodes = new HashMap<List<String>, UsesNodeBuilder>();
-    //private final Map<List<String>, RefineHolder> addedRefines = new HashMap<List<String>, RefineHolder>();
     private final Map<List<String>, RpcDefinitionBuilder> addedRpcs = new HashMap<List<String>, RpcDefinitionBuilder>();
     private final Set<NotificationBuilder> addedNotifications = new HashSet<NotificationBuilder>();
     private final Set<IdentitySchemaNodeBuilder> addedIdentities = new HashSet<IdentitySchemaNodeBuilder>();
@@ -80,7 +80,7 @@ public class ModuleBuilder implements Builder {
     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>();
 
@@ -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<List<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,6 +172,30 @@ public class ModuleBuilder implements Builder {
         return 0;
     }
 
+    @Override
+    public QName getQName() {
+        return new QName(namespace, revision, prefix, name);
+    }
+
+    @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);
     }
@@ -177,6 +204,22 @@ public class ModuleBuilder implements Builder {
         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);
     }
@@ -185,14 +228,34 @@ public class ModuleBuilder implements Builder {
         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);
     }
 
-    public Set<DataSchemaNodeBuilder> getChildNodes() {
+    @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()) {
+        for (Map.Entry<List<String>, DataSchemaNodeBuilder> entry : childNodes.entrySet()) {
             final List<String> path = entry.getKey();
             final DataSchemaNodeBuilder child = entry.getValue();
             if (path.size() == 2) {
@@ -218,14 +281,17 @@ public class ModuleBuilder implements Builder {
         return addedUsesNodes;
     }
 
-    public Set<UnknownSchemaNodeBuilder> getUnknownNodes() {
-        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() {
         final Set<TypeDefinitionBuilder> typedefs = new HashSet<TypeDefinitionBuilder>();
-        for (Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs
-                .entrySet()) {
+        for (Map.Entry<List<String>, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) {
             if (entry.getKey().size() == 2) {
                 typedefs.add(entry.getValue());
             }
@@ -233,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;
     }
@@ -263,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) actualPath
-                .getFirst();
+        final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) actualPath.getFirst();
         dirtyNodes.put(dirtyNodePath, nodeBuilder);
     }
 
@@ -296,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);
     }
 
@@ -313,12 +386,23 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public ContainerSchemaNodeBuilder addContainerNode(
-            final QName containerName, final List<String> parentPath,
-            final int line) {
+    @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, line);
+        final ContainerSchemaNodeBuilder containerBuilder = new ContainerSchemaNodeBuilder(containerName, schemaPath, line);
         updateParent(containerBuilder, line, "container");
 
         pathToNode.add(containerName.getLocalName());
@@ -327,11 +411,9 @@ public class ModuleBuilder implements Builder {
         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 ListSchemaNodeBuilder listBuilder = new ListSchemaNodeBuilder(listName, schemaPath, line);
         updateParent(listBuilder, line, "list");
 
         pathToNode.add(listName.getLocalName());
@@ -340,11 +422,9 @@ public class ModuleBuilder implements Builder {
         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 LeafSchemaNodeBuilder leafBuilder = new LeafSchemaNodeBuilder(leafName, schemaPath, line);
         updateParent(leafBuilder, line, "leaf");
 
         pathToNode.add(leafName.getLocalName());
@@ -353,11 +433,9 @@ public class ModuleBuilder implements Builder {
         return leafBuilder;
     }
 
-    public LeafListSchemaNodeBuilder addLeafListNode(final QName qname,
-            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(
-                qname, line);
+        final LeafListSchemaNodeBuilder leafListBuilder = new LeafListSchemaNodeBuilder(qname, schemaPath, line);
         updateParent(leafListBuilder, line, "leaf-list");
 
         pathToNode.add(qname.getLocalName());
@@ -366,8 +444,20 @@ public class ModuleBuilder implements Builder {
         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);
 
@@ -376,8 +466,7 @@ public class ModuleBuilder implements Builder {
             if (parent instanceof DataNodeContainerBuilder) {
                 ((DataNodeContainerBuilder) parent).addGrouping(builder);
             } else {
-                throw new YangParseException(name, line,
-                        "Unresolved parent of grouping " + qname.getLocalName());
+                throw new YangParseException(name, line, "Unresolved parent of grouping " + qname.getLocalName());
             }
         }
 
@@ -387,20 +476,20 @@ public class ModuleBuilder implements 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
-        if (!(actualPath.isEmpty())) {
-            final Builder parent = actualPath.getFirst();
+        if (parent != null) {
             if (parent instanceof UsesNodeBuilder) {
                 ((UsesNodeBuilder) parent).addAugment(builder);
             } else {
-                throw new YangParseException(this.name, line,
-                        "Unresolved parent of augment " + name);
+                throw new YangParseException(this.name, line, "Unresolved parent of augment " + name);
             }
         }
 
@@ -410,23 +499,37 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    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);
+    @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);
+    }
 
-        if (!(actualPath.isEmpty())) {
-            final Builder parent = actualPath.getFirst();
-            if (parent instanceof DataNodeContainerBuilder) {
-                if (parent instanceof AugmentationSchemaBuilder) {
-                    usesBuilder.setAugmenting(true);
-                }
-                ((DataNodeContainerBuilder) parent).addUsesNode(usesBuilder);
-            } else {
-                throw new YangParseException(name, line,
-                        "Unresolved parent of uses " + groupingPathStr);
+    public UsesNodeBuilder addUsesNode(final String groupingPathStr, final List<String> parentPath, final int line) {
+        final List<String> pathToUses = new ArrayList<String>(parentPath);
+        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);
@@ -434,37 +537,31 @@ public class ModuleBuilder implements Builder {
         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);
 
         if (actualPath.isEmpty()) {
-            throw new YangParseException(name, refine.getLine(),
-                    "refine can be defined only in uses statement");
+            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");
+                throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
             }
         }
 
         path.add(refine.getName());
     }
 
-    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");
+            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);
@@ -472,45 +569,36 @@ public class ModuleBuilder implements Builder {
         return rpcBuilder;
     }
 
-    public ContainerSchemaNodeBuilder addRpcInput(final QName inputQName,
-            final int line) {
+    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");
+            throw new YangParseException(name, line, "input can be defined only in rpc statement");
         }
         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
 
-        final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(
-                inputQName, line);
+        final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(inputQName, schemaPath, line);
         rpc.setInput(inputBuilder);
         return inputBuilder;
     }
 
-    public ContainerSchemaNodeBuilder addRpcOutput(final QName outputQName,
-            final int line) {
+    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");
+            throw new YangParseException(name, line, "output can be defined only in rpc statement");
         }
         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
 
-        final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(
-                outputQName, line);
+        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) {
+    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");
+            throw new YangParseException(name, line, "notification can be defined only in module or submodule");
         }
-
-        final NotificationBuilder builder = new NotificationBuilder(
-                notificationName, line);
+        final NotificationBuilder builder = new NotificationBuilder(notificationName, line);
 
         final List<String> notificationPath = new ArrayList<String>(parentPath);
         notificationPath.add(notificationName.getLocalName());
@@ -519,11 +607,9 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public FeatureBuilder addFeature(final QName featureName,
-            final List<String> parentPath, final int line) {
+    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");
+            throw new YangParseException(name, line, "feature can be defined only in module or submodule");
         }
 
         final List<String> pathToFeature = new ArrayList<String>(parentPath);
@@ -534,22 +620,19 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public ChoiceBuilder addChoice(final QName choiceName,
-            final List<String> parentPath, final int 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);
 
         if (!(actualPath.isEmpty())) {
-            Builder parent = actualPath.getFirst();
+            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());
+                throw new YangParseException(name, line, "Unresolved parent of choice " + choiceName.getLocalName());
             }
         }
 
@@ -559,24 +642,27 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public ChoiceCaseBuilder addCase(final QName caseName,
-            final List<String> parentPath, final int line) {
+    public ChoiceCaseBuilder addCase(final QName caseName, final List<String> parentPath, final int line) {
+        Builder parent = getActualNode();
+
         final List<String> pathToCase = new ArrayList<String>(parentPath);
-        final ChoiceCaseBuilder builder = new ChoiceCaseBuilder(caseName, line);
+        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 {
-            final Builder parent = actualPath.getFirst();
             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());
+                throw new YangParseException(name, line, "Unresolved parent of 'case' " + caseName.getLocalName());
             }
         }
 
@@ -586,10 +672,9 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public AnyXmlBuilder addAnyXml(final QName anyXmlName,
-            final List<String> parentPath, final int line) {
+    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, line);
+        final AnyXmlBuilder builder = new AnyXmlBuilder(anyXmlName, schemaPath, line);
         updateParent(builder, line, "anyxml");
 
         pathToAnyXml.add(anyXmlName.getLocalName());
@@ -598,20 +683,29 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public TypeDefinitionBuilderImpl addTypedef(final QName typeDefName,
-            final List<String> parentPath, final int line) {
+    @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);
+        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());
+                throw new YangParseException(name, line, "Unresolved parent of typedef " + typeDefName.getLocalName());
             }
         }
 
@@ -620,23 +714,20 @@ public class ModuleBuilder implements Builder {
         return builder;
     }
 
-    public void setType(final TypeDefinition<?> type,
-            final List<String> parentPath) {
-
+    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()
+                throw new YangParseException("Failed to set type '" + type.getQName().getLocalName()
                         + "'. Unknown parent node: " + parent);
             }
         }
     }
 
-    public UnionTypeBuilder addUnionType(final List<String> currentPath,
-            final URI namespace, final Date revision, final int line) {
+    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);
 
@@ -654,18 +745,15 @@ public class ModuleBuilder implements Builder {
                 addedUnionTypes.put(path, union);
                 return union;
             } else {
-                throw new YangParseException(name, line,
-                        "Unresolved parent of union type.");
+                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) {
         final List<String> pathToIdentityref = new ArrayList<String>(parentPath);
-        final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(
-                baseString, schemaPath, line);
+        final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(baseString, schemaPath, line);
 
         if (actualPath.isEmpty()) {
             throw new YangParseException(line, "identityref error");
@@ -676,17 +764,14 @@ public class ModuleBuilder implements Builder {
                 typeParent.setTypedef(identityref);
                 dirtyNodes.put(pathToIdentityref, typeParent);
             } else {
-                throw new YangParseException(name, line,
-                        "Unresolved parent of identityref type.");
+                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");
+            throw new YangParseException(name, line, "deviation can be defined only in module or submodule");
         }
 
         final List<String> pathToDeviation = new ArrayList<String>(parentPath);
@@ -696,48 +781,37 @@ public class ModuleBuilder implements 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");
+            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());
         addedIdentities.add(builder);
         return builder;
     }
 
-    public void addConfiguration(final boolean configuration,
-            final List<String> parentPath, final int line) {
-        if (actualPath.isEmpty()) {
-            throw new YangParseException(name, line,
-                    "Parent node of config statement not found.");
+    @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 {
-            final Builder parent = actualPath.getFirst();
-            if (parent instanceof DataSchemaNodeBuilder) {
-                ((DataSchemaNodeBuilder) parent)
-                        .setConfiguration(configuration);
-            } else if (parent instanceof RefineHolder) {
-                ((RefineHolder) parent).setConfig(configuration);
-            } else if (parent instanceof DeviationBuilder) {
-                // skip: set config to deviation (deviate stmt) not supported by
-                // current api
-                return;
-            } else {
-                throw new YangParseException(name, line,
-                        "Unresolved parent of config statement.");
-            }
+            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);
+    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();
@@ -746,16 +820,28 @@ public class ModuleBuilder implements Builder {
             } else if (parent instanceof RefineHolder) {
                 ((RefineHolder) parent).addUnknownSchemaNode(builder);
             } else {
-                throw new YangParseException(name, line,
-                        "Unresolved parent of unknown node '"
-                                + qname.getLocalName() + "'");
+                throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
+                        + "'");
             }
         }
+        final List<String> unPath = new ArrayList<String>(parentPath);
+        unPath.add(qname.getLocalName());
 
-        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;
@@ -769,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;
@@ -977,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;
             }
@@ -989,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);
@@ -1016,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;
         }
 
@@ -1080,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);
@@ -1093,29 +1183,25 @@ public class ModuleBuilder implements Builder {
         }
     }
 
-    private void updateParent(DataSchemaNodeBuilder nodeBuilder, int line,
-            String nodeTypeName) {
+    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);
+                ((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());
+                throw new YangParseException(name, line, "Unresolved parent of " + nodeTypeName + " "
+                        + nodeBuilder.getQName().getLocalName());
             }
         }
     }
 
-    private ModuleImport createModuleImport(final String moduleName,
-            final Date revision, final String prefix) {
-        ModuleImport moduleImport = new ModuleImport() {
+    private ModuleImport createModuleImport(final String moduleName, final Date revision, final String prefix) {
+        final ModuleImport moduleImport = new ModuleImport() {
             @Override
             public String getModuleName() {
                 return moduleName;
@@ -1135,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;
             }
 
@@ -1182,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;
@@ -1197,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) {
@@ -1221,11 +1301,9 @@ 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()) {
+        for (Map.Entry<List<String>, GroupingBuilder> entry : addedGroupings.entrySet()) {
             if (entry.getKey().size() == 2) {
                 groupings.add(entry.getValue().build());
             }
@@ -1239,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);
@@ -1260,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);
             }
         }
@@ -1284,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());
             }
@@ -1303,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());
             }
@@ -1315,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;
+    }
+
 }