Yang validation moved to validator package and validation listener refactored.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / model / parser / impl / YangModelParserListenerImpl.java
index 510bec8cb20eb9942429f2a6b84fe93ffb92a67f..eacc5460b3743c7a4f9c62a9215a2cf7daa9bc3e 100644 (file)
@@ -13,15 +13,18 @@ import java.net.URI;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Stack;
 
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Contact_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
@@ -44,18 +47,24 @@ import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtCont
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;
-import org.opendaylight.controller.model.util.YangTypesConverter;
 import org.opendaylight.controller.yang.common.QName;
 import org.opendaylight.controller.yang.model.api.Status;
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.AnyXmlBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.ChoiceCaseBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.ContainerSchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.DeviationBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.ExtensionBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.FeatureBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafListSchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafSchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.ListSchemaNodeBuilder;
@@ -64,11 +73,13 @@ import org.opendaylight.controller.yang.model.parser.builder.impl.NotificationBu
 import org.opendaylight.controller.yang.model.parser.builder.impl.RpcDefinitionBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
+import org.opendaylight.controller.yang.model.util.YangTypesConverter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-final class YangModelParserListenerImpl extends YangParserBaseListener {
-
+public final class YangModelParserListenerImpl extends YangParserBaseListener {\r
+\r
     private static final Logger logger = LoggerFactory
             .getLogger(YangModelParserListenerImpl.class);
 
@@ -77,13 +88,12 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
     private String moduleName;
     private URI namespace;
     private String yangModelPrefix;
-    private Date revision;
+    private Date revision = new Date(0L);
 
-    private final DateFormat simpleDateFormat = new SimpleDateFormat(
-            "yyyy-mm-dd");
+    public final static DateFormat simpleDateFormat = new SimpleDateFormat(\r
+            "yyyy-MM-dd");
     private final Stack<String> actualPath = new Stack<String>();
 
-
     @Override
     public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
         moduleName = stringFromNode(ctx);
@@ -119,6 +129,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
     public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {
         super.enterModule_header_stmts(ctx);
 
+        String yangVersion = null;
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             final ParseTree treeNode = ctx.getChild(i);
             if (treeNode instanceof Namespace_stmtContext) {
@@ -129,10 +140,14 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
                 yangModelPrefix = stringFromNode(treeNode);
                 moduleBuilder.setPrefix(yangModelPrefix);
             } else if (treeNode instanceof Yang_version_stmtContext) {
-                final String yangVersion = stringFromNode(treeNode);
-                moduleBuilder.setYangVersion(yangVersion);
+                yangVersion = stringFromNode(treeNode);
             }
         }
+
+        if (yangVersion == null) {
+            yangVersion = "1";
+        }
+        moduleBuilder.setYangVersion(yangVersion);
     }
 
     @Override
@@ -164,25 +179,39 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void enterRevision_stmts(Revision_stmtsContext ctx) {
-        for (int i = 0; i < ctx.getChildCount(); ++i) {
-            final ParseTree treeNode = ctx.getChild(i);
-            if (treeNode instanceof Revision_stmtContext) {
-                final String revisionDateStr = stringFromNode(treeNode);
-                try {
-                    revision = simpleDateFormat.parse(revisionDateStr);
-                    moduleBuilder.setRevision(revision);
-                } catch (ParseException e) {
-                    final String message = "Failed to parse revision string: "+ revisionDateStr;
-                    logger.warn(message);
+        if (ctx != null) {
+            for (int i = 0; i < ctx.getChildCount(); ++i) {
+                final ParseTree treeNode = ctx.getChild(i);
+                if (treeNode instanceof Revision_stmtContext) {
+                    updateRevisionForRevisionStatement(treeNode);
                 }
             }
         }
     }
 
+    private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
+        final String revisionDateStr = stringFromNode(treeNode);
+        try {
+            final Date revision = simpleDateFormat.parse(revisionDateStr);
+            if ((revision != null) && (this.revision.compareTo(revision) < 0)) {
+                this.revision = revision;
+                moduleBuilder.setRevision(this.revision);
+                for (int i = 0; i < treeNode.getChildCount(); ++i) {
+                    ParseTree child = treeNode.getChild(i);
+                    if (child instanceof Reference_stmtContext) {
+                        moduleBuilder.setReference(stringFromNode(child));
+                    }
+                }
+            }
+        } catch (ParseException e) {
+            final String message = "Failed to parse revision string: "
+                    + revisionDateStr;
+            logger.warn(message);
+        }
+    }
+
     @Override
     public void enterImport_stmt(Import_stmtContext ctx) {
-        super.enterImport_stmt(ctx);
-
         final String importName = stringFromNode(ctx);
         String importPrefix = null;
         Date importRevision = null;
@@ -196,8 +225,9 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
                 String importRevisionStr = stringFromNode(treeNode);
                 try {
                     importRevision = simpleDateFormat.parse(importRevisionStr);
-                } catch(ParseException e) {
-                    logger.warn("Failed to parse import revision-date: "+ importRevisionStr);
+                } catch (ParseException e) {
+                    logger.warn("Failed to parse import revision-date: "
+                            + importRevisionStr);
                 }
             }
         }
@@ -208,7 +238,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
     public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {
         final String augmentPath = stringFromNode(ctx);
         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(
-                augmentPath, getActualPath());
+                augmentPath, actualPath);
         updatePath(augmentPath);
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
@@ -222,6 +252,9 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
             } else if (child instanceof Status_stmtContext) {
                 Status status = parseStatus((Status_stmtContext) child);
                 builder.setStatus(status);
+            } else if (child instanceof When_stmtContext) {
+                String when = stringFromNode(child);
+                builder.addWhenCondition(when);
             }
         }
     }
@@ -234,19 +267,32 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) {
-        String argument = stringFromNode(ctx);
-        QName qname = new QName(namespace, revision, yangModelPrefix, argument);
+        final String extName = stringFromNode(ctx);
+        QName qname = new QName(namespace, revision, yangModelPrefix, extName);
         ExtensionBuilder builder = moduleBuilder.addExtension(qname);
         parseSchemaNodeArgs(ctx, builder);
+
+        String argument = null;
+        boolean yin = false;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Argument_stmtContext) {
+                argument = stringFromNode(child);
+                yin = parseYinValue((Argument_stmtContext) child);
+                break;
+            }
+        }
+        builder.setArgument(argument);
+        builder.setYinElement(yin);
     }
 
     @Override
     public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
-        String typedefName = stringFromNode(ctx);
+        final String typedefName = stringFromNode(ctx);
         QName typedefQName = new QName(namespace, revision, yangModelPrefix,
                 typedefName);
         TypedefBuilder builder = moduleBuilder.addTypedef(typedefQName,
-                getActualPath());
+                actualPath);
         updatePath(typedefName);
 
         builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
@@ -263,21 +309,8 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void enterType_stmt(YangParser.Type_stmtContext ctx) {
-        String typeName = stringFromNode(ctx);
-        QName typeQName;
-        if (typeName.contains(":")) {
-            String[] splittedName = typeName.split(":");
-            String prefix = splittedName[0];
-            String name = splittedName[1];
-            if (prefix.equals(yangModelPrefix)) {
-                typeQName = new QName(namespace, revision, prefix, name);
-            } else {
-                typeQName = new QName(null, null, prefix, name);
-            }
-        } else {
-            typeQName = new QName(namespace, revision, yangModelPrefix,
-                    typeName);
-        }
+        final String typeName = stringFromNode(ctx);
+        QName typeQName = parseQName(typeName);
 
         TypeDefinition<?> type = null;
         Type_body_stmtsContext typeBody = null;
@@ -289,23 +322,52 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         }
 
         // if this is base yang type...
-        if(YangTypesConverter.isBaseYangType(typeName)) {
+        if (YangTypesConverter.isBaseYangType(typeName)) {
             if (typeBody == null) {
                 // if there are no constraints, just grab default base yang type
                 type = YangTypesConverter.javaTypeForBaseYangType(typeName);
+                moduleBuilder.setType(type, actualPath);
             } else {
-                type = parseTypeBody(typeName, typeBody, actualPath, namespace, revision, yangModelPrefix);
+                if ("union".equals(typeName)) {
+                    moduleBuilder.addUnionType(actualPath);
+                } else if("identityref".equals(typeName)) {
+                    moduleBuilder.addIdentityrefType(getIdentityrefBase(typeBody), actualPath);
+                } else {
+                    List<String> typePath = new ArrayList<String>(actualPath);
+                    typePath.remove(0);
+                    type = parseTypeBody(typeName, typeBody, typePath,
+                            namespace, revision, yangModelPrefix);
+                    moduleBuilder.setType(type, actualPath);
+                }
             }
         } else {
             type = parseUnknownTypeBody(typeQName, typeBody);
             // mark parent node of this type statement as dirty
             moduleBuilder.addDirtyNode(actualPath);
+            moduleBuilder.setType(type, actualPath);
         }
 
-        moduleBuilder.setType(type, actualPath);
         updatePath(typeName);
     }
 
+    private QName parseQName(String typeName) {
+        QName typeQName;
+        if (typeName.contains(":")) {
+            String[] splittedName = typeName.split(":");
+            String prefix = splittedName[0];
+            String name = splittedName[1];
+            if (prefix.equals(yangModelPrefix)) {
+                typeQName = new QName(namespace, revision, prefix, name);
+            } else {
+                typeQName = new QName(null, null, prefix, name);
+            }
+        } else {
+            typeQName = new QName(namespace, revision, yangModelPrefix,
+                    typeName);
+        }
+        return typeQName;
+    }
+
     @Override
     public void exitType_stmt(YangParser.Type_stmtContext ctx) {
         final String actContainer = actualPath.pop();
@@ -333,22 +395,22 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void enterContainer_stmt(Container_stmtContext ctx) {
-        super.enterContainer_stmt(ctx);
-        String containerName = stringFromNode(ctx);
+        final String containerName = stringFromNode(ctx);
         QName containerQName = new QName(namespace, revision, yangModelPrefix,
                 containerName);
         ContainerSchemaNodeBuilder containerBuilder = moduleBuilder
                 .addContainerNode(containerQName, actualPath);
         updatePath(containerName);
 
-        containerBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        containerBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
         parseSchemaNodeArgs(ctx, containerBuilder);
-        parseConstraints(ctx, containerBuilder.getConstraintsBuilder());
+        parseConstraints(ctx, containerBuilder.getConstraints());
 
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             final ParseTree childNode = ctx.getChild(i);
             if (childNode instanceof Presence_stmtContext) {
-                containerBuilder.setPresenceContainer(true);
+                containerBuilder.setPresence(true);
                 break;
             }
         }
@@ -356,15 +418,12 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void exitContainer_stmt(Container_stmtContext ctx) {
-        super.exitContainer_stmt(ctx);
         final String actContainer = actualPath.pop();
         logger.debug("exiting " + actContainer);
     }
 
     @Override
     public void enterLeaf_stmt(Leaf_stmtContext ctx) {
-        super.enterLeaf_stmt(ctx);
-
         final String leafName = stringFromNode(ctx);
         QName leafQName = new QName(namespace, revision, yangModelPrefix,
                 leafName);
@@ -372,9 +431,23 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
                 leafQName, actualPath);
         updatePath(leafName);
 
-        leafBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        leafBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
         parseSchemaNodeArgs(ctx, leafBuilder);
-        parseConstraints(ctx, leafBuilder.getConstraintsBuilder());
+        parseConstraints(ctx, leafBuilder.getConstraints());
+
+        String defaultStr = null;
+        String unitsStr = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Default_stmtContext) {
+                defaultStr = stringFromNode(child);
+            } else if (child instanceof Units_stmtContext) {
+                unitsStr = stringFromNode(child);
+            }
+        }
+        leafBuilder.setDefaultStr(defaultStr);
+        leafBuilder.setUnits(unitsStr);
     }
 
     @Override
@@ -386,8 +459,12 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
     @Override
     public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
         final String groupingPathStr = stringFromNode(ctx);
-        moduleBuilder.addUsesNode(groupingPathStr, actualPath);
+        UsesNodeBuilder builder = moduleBuilder.addUsesNode(groupingPathStr,
+                actualPath);
         updatePath(groupingPathStr);
+
+        final List<RefineHolder> refines = parseRefines(ctx);
+        builder.setRefines(refines);
     }
 
     @Override
@@ -398,8 +475,6 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
-        super.enterLeaf_list_stmt(ctx);
-
         final String leafListName = stringFromNode(ctx);
         QName leafListQName = new QName(namespace, revision, yangModelPrefix,
                 leafListName);
@@ -408,7 +483,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         updatePath(leafListName);
 
         parseSchemaNodeArgs(ctx, leafListBuilder);
-        parseConstraints(ctx, leafListBuilder.getConstraintsBuilder());
+        parseConstraints(ctx, leafListBuilder.getConstraints());
 
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             final ParseTree childNode = ctx.getChild(i);
@@ -429,8 +504,6 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void enterList_stmt(List_stmtContext ctx) {
-        super.enterList_stmt(ctx);
-
         final String containerName = stringFromNode(ctx);
         QName containerQName = new QName(namespace, revision, yangModelPrefix,
                 containerName);
@@ -438,9 +511,10 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
                 containerQName, actualPath);
         updatePath(containerName);
 
-        listBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        listBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
         parseSchemaNodeArgs(ctx, listBuilder);
-        parseConstraints(ctx, listBuilder.getConstraintsBuilder());
+        parseConstraints(ctx, listBuilder.getConstraints());
 
         String keyDefinition = "";
         for (int i = 0; i < ctx.getChildCount(); ++i) {
@@ -464,6 +538,79 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         logger.debug("exiting " + actContainer);
     }
 
+    @Override
+    public void enterAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
+        final String anyXmlName = stringFromNode(ctx);
+        QName anyXmlQName = new QName(namespace, revision, yangModelPrefix,
+                anyXmlName);
+        AnyXmlBuilder anyXmlBuilder = moduleBuilder.addAnyXml(anyXmlQName,
+                actualPath);
+        updatePath(anyXmlName);
+
+        anyXmlBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, anyXmlBuilder);
+        parseConstraints(ctx, anyXmlBuilder.getConstraints());
+    }
+
+    @Override
+    public void exitAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
+        final String actContainer = actualPath.pop();
+        logger.debug("exiting " + actContainer);
+    }
+
+    @Override
+    public void enterChoice_stmt(YangParser.Choice_stmtContext ctx) {
+        final String choiceName = stringFromNode(ctx);
+        QName choiceQName = new QName(namespace, revision, yangModelPrefix,
+                choiceName);
+        ChoiceBuilder choiceBuilder = moduleBuilder.addChoice(choiceQName,
+                actualPath);
+
+        updatePath(choiceName);
+        choiceBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, choiceBuilder);
+        parseConstraints(ctx, choiceBuilder.getConstraints());
+
+        // set 'default' case
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Default_stmtContext) {
+                String defaultCase = stringFromNode(child);
+                choiceBuilder.setDefaultCase(defaultCase);
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void exitChoice_stmt(YangParser.Choice_stmtContext ctx) {
+        final String actContainer = actualPath.pop();
+        logger.debug("exiting " + actContainer);
+    }
+
+    @Override
+    public void enterCase_stmt(YangParser.Case_stmtContext ctx) {
+        final String caseName = stringFromNode(ctx);
+        QName choiceQName = new QName(namespace, revision, yangModelPrefix,
+                caseName);
+        ChoiceCaseBuilder caseBuilder = moduleBuilder.addCase(choiceQName,
+                actualPath);
+
+        updatePath(caseName);
+        caseBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, caseBuilder);
+        parseConstraints(ctx, caseBuilder.getConstraints());
+    }
+
+    @Override
+    public void exitCase_stmt(YangParser.Case_stmtContext ctx) {
+        final String actContainer = actualPath.pop();
+        logger.debug("exiting " + actContainer);
+    }
+
     @Override
     public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
         final String notificationName = stringFromNode(ctx);
@@ -473,8 +620,8 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
                 .addNotification(notificationQName, actualPath);
         updatePath(notificationName);
 
-        notificationBuilder.setPath(createActualSchemaPath(actualPath, namespace,
-                revision, yangModelPrefix));
+        notificationBuilder.setPath(createActualSchemaPath(actualPath,
+                namespace, revision, yangModelPrefix));
         parseSchemaNodeArgs(ctx, notificationBuilder);
     }
 
@@ -487,24 +634,26 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
     // Unknown types
     @Override
     public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
-        String name = stringFromNode(ctx);
+        final String name = stringFromNode(ctx);
 
         QName qname;
-        if(name != null) {
+        if (name != null) {
             String[] splittedName = name.split(":");
-            if(splittedName.length == 2) {
+            if (splittedName.length == 2) {
                 qname = new QName(null, null, splittedName[0], splittedName[1]);
             } else {
-                qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
+                qname = new QName(namespace, revision, yangModelPrefix,
+                        splittedName[0]);
             }
         } else {
             qname = new QName(namespace, revision, yangModelPrefix, name);
         }
 
-        UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(qname, getActualPath());
+        UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(
+                qname, actualPath);
         updatePath(name);
-
-        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
+                yangModelPrefix));
         parseSchemaNodeArgs(ctx, builder);
     }
 
@@ -523,8 +672,8 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
                 actualPath);
         updatePath(rpcName);
 
-        rpcBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision,
-                yangModelPrefix));
+        rpcBuilder.setPath(createActualSchemaPath(actualPath, namespace,
+                revision, yangModelPrefix));
         parseSchemaNodeArgs(ctx, rpcBuilder);
     }
 
@@ -581,7 +730,8 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         final String targetPath = stringFromNode(ctx);
         String reference = null;
         String deviate = null;
-        DeviationBuilder builder = moduleBuilder.addDeviation(targetPath);
+        DeviationBuilder builder = moduleBuilder.addDeviation(targetPath,
+                actualPath);
         updatePath(targetPath);
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
@@ -614,6 +764,34 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         moduleBuilder.addConfiguration(configuration, actualPath);
     }
 
+    @Override
+    public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
+        final String identityName = stringFromNode(ctx);
+        final QName identityQName = new QName(namespace, revision,
+                yangModelPrefix, identityName);
+        IdentitySchemaNodeBuilder builder = moduleBuilder
+                .addIdentity(identityQName);
+        updatePath(identityName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision,
+                yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Base_stmtContext) {
+                String baseIdentityName = stringFromNode(child);
+                builder.setBaseIdentityName(baseIdentityName);
+            }
+        }
+    }
+
+    @Override
+    public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
+        final String actContainer = actualPath.pop();
+        logger.debug("exiting " + actContainer);
+    }
+
     public ModuleBuilder getModuleBuilder() {
         return moduleBuilder;
     }
@@ -622,8 +800,4 @@ final class YangModelParserListenerImpl extends YangParserBaseListener {
         actualPath.push(containerName);
     }
 
-    private List<String> getActualPath() {
-        return Collections.unmodifiableList(actualPath);
-    }
-
 }