Refactored YANG types resolving.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / model / parser / impl / YangModelParserImpl.java
index d7c6711affb740de272f754e76e331561782f8ba..27a65c1168f24fa822f1c13175d4c4a5a0cef0e2 100644 (file)
@@ -9,7 +9,9 @@ package org.opendaylight.controller.yang.model.parser.impl;
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -26,22 +28,6 @@ import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
-import org.opendaylight.controller.model.api.type.BinaryTypeDefinition;
-import org.opendaylight.controller.model.api.type.BitsTypeDefinition;
-import org.opendaylight.controller.model.api.type.BitsTypeDefinition.Bit;
-import org.opendaylight.controller.model.api.type.DecimalTypeDefinition;
-import org.opendaylight.controller.model.api.type.InstanceIdentifierTypeDefinition;
-import org.opendaylight.controller.model.api.type.IntegerTypeDefinition;
-import org.opendaylight.controller.model.api.type.LengthConstraint;
-import org.opendaylight.controller.model.api.type.PatternConstraint;
-import org.opendaylight.controller.model.api.type.RangeConstraint;
-import org.opendaylight.controller.model.api.type.StringTypeDefinition;
-import org.opendaylight.controller.model.util.BaseConstraints;
-import org.opendaylight.controller.model.util.BinaryType;
-import org.opendaylight.controller.model.util.BitsType;
-import org.opendaylight.controller.model.util.StringType;
-import org.opendaylight.controller.model.util.UnknownType;
-import org.opendaylight.controller.model.util.YangTypesConverter;
 import org.opendaylight.controller.yang.common.QName;
 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
@@ -53,6 +39,13 @@ import org.opendaylight.controller.yang.model.api.RpcDefinition;
 import org.opendaylight.controller.yang.model.api.SchemaContext;
 import org.opendaylight.controller.yang.model.api.SchemaPath;
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
@@ -60,7 +53,14 @@ import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilde
 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
+import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
+import org.opendaylight.controller.yang.model.parser.util.YangParseException;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.UnknownType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -70,36 +70,58 @@ public class YangModelParserImpl implements YangModelParser {
             .getLogger(YangModelParserImpl.class);
 
     @Override
-    public Module parseYangModel(String yangFile) {
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = loadFiles(yangFile);
-        Set<Module> result = build(modules);
+    public Module parseYangModel(final String yangFile) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);
+        final Set<Module> result = build(modules);
         return result.iterator().next();
     }
 
     @Override
-    public Set<Module> parseYangModels(String... yangFiles) {
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = loadFiles(yangFiles);
-        Set<Module> result = build(modules);
-        return result;
+    public Set<Module> parseYangModels(final String... yangFiles) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);
+        return build(modules);
+    }
+
+    @Override
+    public Set<Module> parseYangModelsFromStreams(
+            final InputStream... yangModelStreams) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);
+        return build(modules);
     }
 
     @Override
-    public SchemaContext resolveSchemaContext(Set<Module> modules) {
+    public SchemaContext resolveSchemaContext(final Set<Module> modules) {
         return new SchemaContextImpl(modules);
     }
 
-    private Map<String, TreeMap<Date, ModuleBuilder>> loadFiles(
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
             String... yangFiles) {
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
+        InputStream[] streams = new InputStream[yangFiles.length];
+        FileInputStream inStream = null;
+        for (int i = 0; i < yangFiles.length; i++) {
+            final String yangFileName = yangFiles[i];
+            final File yangFile = new File(yangFileName);
+            try {
+                inStream = new FileInputStream(yangFile);
+            } catch (FileNotFoundException e) {
+                logger.warn("Exception while reading yang stream: " + inStream,
+                        e);
+            }
+            streams[i] = inStream;
+        }
+        return resolveModuleBuildersFromStreams(streams);
+    }
 
-        final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
+            InputStream... yangFiles) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
         final ParseTreeWalker walker = new ParseTreeWalker();
+        final List<ParseTree> trees = parseStreams(yangFiles);
+        final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
 
-        List<ParseTree> trees = parseFiles(yangFiles);
-
-        ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
-
+        YangModelParserListenerImpl yangModelParser = null;
         for (int i = 0; i < trees.size(); i++) {
+            yangModelParser = new YangModelParserListenerImpl();
             walker.walk(yangModelParser, trees.get(i));
             builders[i] = yangModelParser.getModuleBuilder();
         }
@@ -110,54 +132,51 @@ public class YangModelParserImpl implements YangModelParser {
             if (builderRevision == null) {
                 builderRevision = createEpochTime();
             }
-
             TreeMap<Date, ModuleBuilder> builderByRevision = modules
                     .get(builderName);
             if (builderByRevision == null) {
                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
             }
             builderByRevision.put(builderRevision, builder);
-
             modules.put(builderName, builderByRevision);
         }
         return modules;
     }
 
-    private List<ParseTree> parseFiles(String... yangFileNames) {
-        List<ParseTree> trees = new ArrayList<ParseTree>();
-        for (String fileName : yangFileNames) {
-            trees.add(parseFile(fileName));
+    private List<ParseTree> parseStreams(InputStream... yangStreams) {
+        final List<ParseTree> trees = new ArrayList<ParseTree>();
+        for (InputStream yangStream : yangStreams) {
+            trees.add(parseStream(yangStream));
         }
         return trees;
     }
 
-    private ParseTree parseFile(String yangFileName) {
+    private ParseTree parseStream(InputStream yangStream) {
         ParseTree result = null;
         try {
-            final File yangFile = new File(yangFileName);
-            final FileInputStream inStream = new FileInputStream(yangFile);
-            final ANTLRInputStream input = new ANTLRInputStream(inStream);
+            final ANTLRInputStream input = new ANTLRInputStream(yangStream);
             final YangLexer lexer = new YangLexer(input);
             final CommonTokenStream tokens = new CommonTokenStream(lexer);
             final YangParser parser = new YangParser(tokens);
             result = parser.yang();
         } catch (IOException e) {
-            logger.warn("Exception while reading yang file: " + yangFileName, e);
+            logger.warn("Exception while reading yang file: " + yangStream, e);
         }
         return result;
     }
 
     private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
-        // first validate
+        // validate
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
                 .entrySet()) {
             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
                     .entrySet()) {
                 ModuleBuilder moduleBuilder = childEntry.getValue();
-                validateBuilder(modules, moduleBuilder);
+                validateModule(modules, moduleBuilder);
             }
         }
-        // then build
+
+        // build
         final Set<Module> result = new HashSet<Module>();
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
                 .entrySet()) {
@@ -165,20 +184,20 @@ public class YangModelParserImpl implements YangModelParser {
             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
                     .entrySet()) {
                 ModuleBuilder moduleBuilder = childEntry.getValue();
-                modulesByRevision.put(childEntry.getKey(),
-                        moduleBuilder.build());
-                result.add(moduleBuilder.build());
+                Module module = moduleBuilder.build();
+                modulesByRevision.put(childEntry.getKey(), module);
+                result.add(module);
             }
         }
-
         return result;
     }
 
-    private void validateBuilder(
+    private void validateModule(
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
             ModuleBuilder builder) {
-        resolveTypedefs(modules, builder);
+        resolveDirtyNodes(modules, builder);
         resolveAugments(modules, builder);
+        resolveIdentities(modules, builder);
     }
 
     /**
@@ -187,176 +206,284 @@ public class YangModelParserImpl implements YangModelParser {
      *
      * @param modules
      *            all available modules
-     * @param builder
+     * @param module
      *            current module
      */
-    private void resolveTypedefs(
+    private void resolveDirtyNodes(
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            ModuleBuilder builder) {
-        Map<List<String>, TypeAwareBuilder> dirtyNodes = builder
+            ModuleBuilder module) {
+        final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
                 .getDirtyNodes();
-        if (dirtyNodes.size() == 0) {
-            return;
-        } else {
+        if (!dirtyNodes.isEmpty()) {
             for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
                     .entrySet()) {
+
                 TypeAwareBuilder typeToResolve = entry.getValue();
-                Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(
-                        modules, entry.getValue(), builder);
-                TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder
-                        .entrySet().iterator().next().getKey();
-                TypeConstraints constraints = foundedTypeDefinitionBuilder
-                        .entrySet().iterator().next().getValue();
-
-                UnknownType ut = (UnknownType) typeToResolve.getType();
-
-                // RANGE
-                List<RangeConstraint> ranges = ut.getRangeStatements();
-                resolveRanges(ranges, typeToResolve, targetType, modules,
-                        builder);
-
-                // LENGTH
-                List<LengthConstraint> lengths = ut.getLengthStatements();
-                resolveLengths(lengths, typeToResolve, targetType, modules,
-                        builder);
-
-                // PATTERN
-                List<PatternConstraint> patterns = ut.getPatterns();
-
-                // Fraction Digits
-                Integer fractionDigits = ut.getFractionDigits();
-
-                TypeDefinition<?> type = targetType.getBaseType();
-                String typeName = type.getQName().getLocalName();
-
-                // MERGE CONSTRAINTS (enumeration and leafref omitted because
-                // they have no restrictions)
-                if (type instanceof DecimalTypeDefinition) {
-                    List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();
-                    fullRanges.addAll(constraints.getRanges());
-                    fullRanges.addAll(ranges);
-                    Integer fd = fractionDigits == null ? constraints
-                            .getFractionDigits() : fractionDigits;
-                    type = YangTypesConverter.javaTypeForBaseYangDecimal64Type(
-                            fullRanges, fd);
-                } else if (type instanceof IntegerTypeDefinition) {
-                    List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();
-                    fullRanges.addAll(constraints.getRanges());
-                    fullRanges.addAll(ranges);
-                    if (typeName.startsWith("int")) {
-                        type = YangTypesConverter
-                                .javaTypeForBaseYangSignedIntegerType(typeName,
-                                        fullRanges);
-                    } else {
-                        type = YangTypesConverter
-                                .javaTypeForBaseYangUnsignedIntegerType(
-                                        typeName, fullRanges);
+                if (typeToResolve instanceof UnionTypeBuilder) {
+                    UnionTypeBuilder union = (UnionTypeBuilder) typeToResolve;
+                    List<TypeDefinition<?>> unionTypes = union.getTypes();
+                    List<UnknownType> toRemove = new ArrayList<UnknownType>();
+                    for (TypeDefinition<?> td : unionTypes) {
+                        if (td instanceof UnknownType) {
+                            UnknownType unknownType = (UnknownType) td;
+                            TypeDefinitionBuilder resolvedType = findTargetTypeUnion(
+                                    typeToResolve, unknownType, modules, module);
+                            union.setType(resolvedType);
+                            toRemove.add(unknownType);
+                        }
                     }
-                } else if (type instanceof StringTypeDefinition) {
-                    List<LengthConstraint> fullLengths = new ArrayList<LengthConstraint>();
-                    fullLengths.addAll(constraints.getLengths());
-                    fullLengths.addAll(lengths);
-                    List<PatternConstraint> fullPatterns = new ArrayList<PatternConstraint>();
-                    fullPatterns.addAll(constraints.getPatterns());
-                    fullPatterns.addAll(patterns);
-                    type = new StringType(fullLengths, fullPatterns);
-                } else if (type instanceof BitsTypeDefinition) {
-                    // TODO: add 'length' restriction to BitsType
-                    BitsTypeDefinition bitsType = (BitsTypeDefinition) type;
-                    List<Bit> bits = bitsType.getBits();
-                    type = new BitsType(bits);
-                } else if (type instanceof BinaryTypeDefinition) {
-                    type = new BinaryType(null, lengths, null);
-                } else if (typeName.equals("instance-identifier")) {
-                    // TODO: instance-identifier
-                    /*
-                     * boolean requireInstance = isRequireInstance(typeBody);
-                     * type = new InstanceIdentifier(null, requireInstance);
-                     */
+                    unionTypes.removeAll(toRemove);
+                } else {
+                    TypeDefinitionBuilder resolvedType = findTargetType(
+                            typeToResolve, modules, module);
+                    typeToResolve.setType(resolvedType);
                 }
-                typeToResolve.setType(type);
             }
         }
     }
 
-    private TypeDefinitionBuilder findTypeDefinitionBuilder(
+    private TypeDefinitionBuilder findTargetType(
+            TypeAwareBuilder typeToResolve,
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
-        Map<TypeDefinitionBuilder, TypeConstraints> result = findTypeDefinitionBuilderWithConstraints(
-                modules, typeBuilder, builder);
-        return result.entrySet().iterator().next().getKey();
+            ModuleBuilder builder) {
+        TypeConstraints constraints = new TypeConstraints();
+
+        TypeDefinitionBuilder targetType = findTypedef(typeToResolve, modules,
+                builder);
+        TypeConstraints tConstraints = findConstraints(typeToResolve,
+                constraints, modules, builder);
+        targetType.setRanges(tConstraints.getRange());
+        targetType.setLengths(tConstraints.getLength());
+        targetType.setPatterns(tConstraints.getPatterns());
+        targetType.setFractionDigits(tConstraints.getFractionDigits());
+
+        return targetType;
     }
 
-    private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
+    private TypeDefinitionBuilder findTargetTypeUnion(
+            TypeAwareBuilder typeToResolve, UnknownType unknownType,
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
-        return findTypeDefinitionBuilderWithConstraints(new TypeConstraints(),
-                modules, typeBuilder, builder);
+            ModuleBuilder builder) {
+        TypeConstraints constraints = new TypeConstraints();
+
+        TypeDefinitionBuilder targetType = findTypedefUnion(typeToResolve,
+                unknownType, modules, builder);
+        TypeConstraints tConstraints = findConstraints(typeToResolve,
+                constraints, modules, builder);
+        targetType.setRanges(tConstraints.getRange());
+        targetType.setLengths(tConstraints.getLength());
+        targetType.setPatterns(tConstraints.getPatterns());
+        targetType.setFractionDigits(tConstraints.getFractionDigits());
+
+        return targetType;
     }
 
-    /**
-     * Traverse through all referenced types chain until base YANG type is
-     * founded.
-     *
-     * @param constraints
-     *            current type constraints
-     * @param modules
-     *            all available modules
-     * @param typeBuilder
-     *            type builder which contains type
-     * @param builder
-     *            current module
-     * @return map, where key is type referenced and value is its constraints
-     */
-    private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
-            TypeConstraints constraints,
+    private TypeDefinitionBuilder findTypedef(TypeAwareBuilder typeToResolve,
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
-        Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();
+            ModuleBuilder builder) {
 
-        UnknownType type = (UnknownType) typeBuilder.getType();
-        QName typeQName = type.getQName();
-        String typeName = type.getQName().getLocalName();
-        String prefix = typeQName.getPrefix();
+        TypeDefinition<?> baseTypeToResolve = typeToResolve.getType();
+        if (baseTypeToResolve != null
+                && !(baseTypeToResolve instanceof UnknownType)) {
+            return (TypeDefinitionBuilder) typeToResolve;
+        }
+
+        UnknownType unknownType = (UnknownType) typeToResolve.getType();
+
+        QName unknownTypeQName = unknownType.getQName();
+        String unknownTypeName = unknownTypeQName.getLocalName();
+        String unknownTypePrefix = unknownTypeQName.getPrefix();
 
         // search for module which contains referenced typedef
-        ModuleBuilder dependentModuleBuilder;
-        if (prefix.equals(builder.getPrefix())) {
-            dependentModuleBuilder = builder;
-        } else {
-            ModuleImport dependentModuleImport = getModuleImport(builder,
-                    prefix);
-            String dependentModuleName = dependentModuleImport.getModuleName();
-            Date dependentModuleRevision = dependentModuleImport.getRevision();
-            TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
-                    .get(dependentModuleName);
-            if (dependentModuleRevision == null) {
-                dependentModuleBuilder = moduleBuildersByRevision.lastEntry()
-                        .getValue();
-            } else {
-                dependentModuleBuilder = moduleBuildersByRevision
-                        .get(dependentModuleRevision);
+        ModuleBuilder dependentModule = findDependentModule(modules, builder,
+                unknownTypePrefix);
+        TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
+                dependentModule.getModuleTypedefs(), unknownTypeName);
+
+        TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
+                lookedUpBuilder, typeToResolve instanceof TypeDefinitionBuilder);
+        TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
+                lookedUpBuilderCopy, modules, dependentModule);
+        return resolvedCopy;
+    }
+
+    private TypeDefinitionBuilder findTypedefUnion(
+            TypeAwareBuilder typeToResolve, UnknownType unknownType,
+            Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            ModuleBuilder builder) {
+
+        TypeDefinition<?> baseTypeToResolve = typeToResolve.getType();
+        if (baseTypeToResolve != null
+                && !(baseTypeToResolve instanceof UnknownType)) {
+            return (TypeDefinitionBuilder) typeToResolve;
+        }
+
+        QName unknownTypeQName = unknownType.getQName();
+        String unknownTypeName = unknownTypeQName.getLocalName();
+        String unknownTypePrefix = unknownTypeQName.getPrefix();
+
+        // search for module which contains referenced typedef
+        ModuleBuilder dependentModule = findDependentModule(modules, builder,
+                unknownTypePrefix);
+        TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
+                dependentModule.getModuleTypedefs(), unknownTypeName);
+
+        TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
+                lookedUpBuilder, typeToResolve instanceof TypeDefinitionBuilder);
+        TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
+                lookedUpBuilderCopy, modules, dependentModule);
+        return resolvedCopy;
+    }
+
+    private TypeDefinitionBuilder copyTypedefBuilder(TypeDefinitionBuilder old,
+            boolean seekByTypedefBuilder) {
+        if (old instanceof UnionTypeBuilder) {
+            UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
+            UnionTypeBuilder newUnion = new UnionTypeBuilder();
+            for (TypeDefinition<?> td : oldUnion.getTypes()) {
+                newUnion.setType(td);
             }
+            for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
+                newUnion.setType(copyTypedefBuilder(tdb, true));
+            }
+            return newUnion;
         }
 
-        // pull all typedef statements from dependent module...
-        final Set<TypeDefinitionBuilder> typedefs = dependentModuleBuilder
-                .getModuleTypedefs();
-        // and search for referenced typedef
-        TypeDefinitionBuilder lookedUpBuilder = null;
-        for (TypeDefinitionBuilder tdb : typedefs) {
-            QName qname = tdb.getQName();
-            if (qname.getLocalName().equals(typeName)) {
-                lookedUpBuilder = tdb;
-                break;
+        QName oldQName = old.getQName();
+        QName newQName = new QName(oldQName.getNamespace(),
+                oldQName.getRevision(), oldQName.getPrefix(),
+                oldQName.getLocalName());
+        TypeDefinitionBuilder tdb = new TypedefBuilder(newQName);
+
+        tdb.setRanges(old.getRanges());
+        tdb.setLengths(old.getLengths());
+        tdb.setPatterns(old.getPatterns());
+
+        TypeDefinition<?> oldType = old.getType();
+        if (oldType == null) {
+            tdb.setType(old.getTypedef());
+        } else {
+            tdb.setType(oldType);
+        }
+
+        if (!seekByTypedefBuilder) {
+            tdb.setDescription(old.getDescription());
+            tdb.setReference(old.getReference());
+            tdb.setStatus(old.getStatus());
+            tdb.setDefaultValue(old.getDefaultValue());
+            tdb.setUnits(old.getUnits());
+        }
+        return tdb;
+    }
+
+    private TypeDefinitionBuilder resolveCopiedBuilder(
+            TypeDefinitionBuilder copied,
+            Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            ModuleBuilder builder) {
+
+        if (copied instanceof UnionTypeBuilder) {
+            UnionTypeBuilder union = (UnionTypeBuilder) copied;
+            List<TypeDefinition<?>> unionTypes = union.getTypes();
+            List<UnknownType> toRemove = new ArrayList<UnknownType>();
+            for (TypeDefinition<?> td : unionTypes) {
+                if (td instanceof UnknownType) {
+                    UnknownType unknownType = (UnknownType) td;
+                    TypeDefinitionBuilder resolvedType = findTargetTypeUnion(
+                            union, unknownType, modules, builder);
+                    union.setType(resolvedType);
+                    toRemove.add(unknownType);
+                }
             }
+            unionTypes.removeAll(toRemove);
+
+            return union;
+        }
+
+        TypeDefinition<?> base = copied.getType();
+        TypeDefinitionBuilder baseTdb = copied.getTypedef();
+        if (base != null && !(base instanceof UnknownType)) {
+            return copied;
+        } else if (base instanceof UnknownType) {
+            UnknownType unknownType = (UnknownType) base;
+            QName unknownTypeQName = unknownType.getQName();
+            String unknownTypePrefix = unknownTypeQName.getPrefix();
+            ModuleBuilder dependentModule = findDependentModule(modules,
+                    builder, unknownTypePrefix);
+            TypeDefinitionBuilder unknownTypeBuilder = findTypedef(copied,
+                    modules, dependentModule);
+            copied.setType(unknownTypeBuilder);
+            return copied;
+        } else if (base == null && baseTdb != null) {
+            // make a copy of baseTypeDef and call again
+            TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(baseTdb,
+                    true);
+            TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
+                    baseTdbCopy, modules, builder);
+            copied.setType(baseTdbCopyResolved);
+            return copied;
+        } else {
+            throw new IllegalStateException(
+                    "TypeDefinitionBuilder in unexpected state");
+        }
+    }
+
+    private TypeDefinitionBuilder findTypedef(QName unknownTypeQName,
+            Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            ModuleBuilder builder) {
+
+        String unknownTypeName = unknownTypeQName.getLocalName();
+        String unknownTypePrefix = unknownTypeQName.getPrefix();
+
+        // search for module which contains referenced typedef
+        ModuleBuilder dependentModule = findDependentModule(modules, builder,
+                unknownTypePrefix);
+
+        TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
+                dependentModule.getModuleTypedefs(), unknownTypeName);
+
+        TypeDefinitionBuilder copied = copyTypedefBuilder(lookedUpBuilder, true);
+        return copied;
+    }
+
+    private TypeConstraints findConstraints(TypeAwareBuilder typeToResolve,
+            TypeConstraints constraints,
+            Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            ModuleBuilder builder) {
+
+        // union type cannot be restricted
+        if (typeToResolve instanceof UnionTypeBuilder) {
+            return constraints;
         }
 
         // if referenced type is UnknownType again, search recursively with
         // current constraints
-        TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();
-        if (referencedType instanceof UnknownType) {
-            UnknownType unknown = (UnknownType) lookedUpBuilder.getBaseType();
+        TypeDefinition<?> referencedType = typeToResolve.getType();
+        if (referencedType == null) {
+            TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) typeToResolve;
+            final List<RangeConstraint> ranges = tdb.getRanges();
+            constraints.addRanges(ranges);
+            final List<LengthConstraint> lengths = tdb.getLengths();
+            constraints.addLengths(lengths);
+            final List<PatternConstraint> patterns = tdb.getPatterns();
+            constraints.addPatterns(patterns);
+            final Integer fractionDigits = tdb.getFractionDigits();
+            constraints.setFractionDigits(fractionDigits);
+            return constraints;
+        } else if (referencedType instanceof ExtendedType) {
+            ExtendedType ext = (ExtendedType) referencedType;
+            final List<RangeConstraint> ranges = ext.getRanges();
+            constraints.addRanges(ranges);
+            final List<LengthConstraint> lengths = ext.getLengths();
+            constraints.addLengths(lengths);
+            final List<PatternConstraint> patterns = ext.getPatterns();
+            constraints.addPatterns(patterns);
+            final Integer fractionDigits = ext.getFractionDigits();
+            constraints.setFractionDigits(fractionDigits);
+            return findConstraints(
+                    findTypedef(ext.getQName(), modules, builder), constraints,
+                    modules, builder);
+        } else if (referencedType instanceof UnknownType) {
+            UnknownType unknown = (UnknownType) referencedType;
 
             final List<RangeConstraint> ranges = unknown.getRangeStatements();
             constraints.addRanges(ranges);
@@ -365,35 +492,79 @@ public class YangModelParserImpl implements YangModelParser {
             constraints.addLengths(lengths);
             final List<PatternConstraint> patterns = unknown.getPatterns();
             constraints.addPatterns(patterns);
-            return findTypeDefinitionBuilderWithConstraints(constraints,
-                    modules, (TypeAwareBuilder) lookedUpBuilder,
-                    dependentModuleBuilder);
+            final Integer fractionDigits = unknown.getFractionDigits();
+            constraints.setFractionDigits(fractionDigits);
+
+            String unknownTypePrefix = unknown.getQName().getPrefix();
+            if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
+                unknownTypePrefix = builder.getPrefix();
+            }
+            ModuleBuilder dependentModule = findDependentModule(modules,
+                    builder, unknown.getQName().getPrefix());
+            TypeDefinitionBuilder unknownTypeBuilder = findTypedef(
+                    unknown.getQName(), modules, builder);
+            return findConstraints(unknownTypeBuilder, constraints, modules,
+                    dependentModule);
         } else {
-            // pull restriction from this base type and add them to
-            // 'constraints'
-            if (referencedType instanceof DecimalTypeDefinition) {
-                constraints.addRanges(((DecimalTypeDefinition) referencedType)
-                        .getRangeStatements());
-                constraints
-                        .setFractionDigits(((DecimalTypeDefinition) referencedType)
-                                .getFractionDigits());
-            } else if (referencedType instanceof IntegerTypeDefinition) {
-                constraints.addRanges(((IntegerTypeDefinition) referencedType)
-                        .getRangeStatements());
-            } else if (referencedType instanceof StringTypeDefinition) {
-                constraints.addPatterns(((StringTypeDefinition) referencedType)
-                        .getPatterns());
-            } else if (referencedType instanceof BitsTypeDefinition) {
-                // TODO: add 'length' restriction to BitsType
-            } else if (referencedType instanceof BinaryTypeDefinition) {
-                // TODO
-            } else if (referencedType instanceof InstanceIdentifierTypeDefinition) {
-                // TODO: instance-identifier
+            // HANDLE BASE YANG TYPE
+            mergeConstraints(referencedType, constraints);
+            return constraints;
+        }
+
+    }
+
+    /**
+     * Go through all typedef statements from given module and search for one
+     * with given name
+     *
+     * @param typedefs
+     *            typedef statements to search
+     * @param name
+     *            name of searched typedef
+     * @return typedef with name equals to given name
+     */
+    private TypeDefinitionBuilder findTypedefBuilder(
+            Set<TypeDefinitionBuilder> typedefs, String name) {
+        TypeDefinitionBuilder result = null;
+        for (TypeDefinitionBuilder td : typedefs) {
+            if (td.getQName().getLocalName().equals(name)) {
+                result = td;
+                break;
             }
+        }
+        if (result == null) {
+            throw new YangParseException(
+                    "Target module does not contain typedef '" + name + "'.");
+        }
+        return result;
+    }
 
-            result.put(lookedUpBuilder, constraints);
-            // return lookedUpBuilder;
-            return result;
+    /**
+     * Pull restriction from referenced type and add them to given constraints
+     *
+     * @param referencedType
+     * @param constraints
+     */
+    private void mergeConstraints(TypeDefinition<?> referencedType,
+            TypeConstraints constraints) {
+
+        if (referencedType instanceof DecimalTypeDefinition) {
+            constraints.addRanges(((DecimalTypeDefinition) referencedType)
+                    .getRangeStatements());
+            constraints
+                    .setFractionDigits(((DecimalTypeDefinition) referencedType)
+                            .getFractionDigits());
+        } else if (referencedType instanceof IntegerTypeDefinition) {
+            constraints.addRanges(((IntegerTypeDefinition) referencedType)
+                    .getRangeStatements());
+        } else if (referencedType instanceof StringTypeDefinition) {
+            constraints.addPatterns(((StringTypeDefinition) referencedType)
+                    .getPatterns());
+            constraints.addLengths(((StringTypeDefinition) referencedType)
+                    .getLengthStatements());
+        } else if (referencedType instanceof BinaryTypeDefinition) {
+            constraints.addLengths(((BinaryTypeDefinition) referencedType)
+                    .getLengthConstraints());
         }
     }
 
@@ -403,13 +574,13 @@ public class YangModelParserImpl implements YangModelParser {
      *
      * @param modules
      *            all available modules
-     * @param builder
+     * @param module
      *            current module
      */
     private void resolveAugments(
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            ModuleBuilder builder) {
-        Set<AugmentationSchemaBuilder> augmentBuilders = builder
+            ModuleBuilder module) {
+        Set<AugmentationSchemaBuilder> augmentBuilders = module
                 .getAddedAugments();
 
         Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
@@ -417,27 +588,14 @@ public class YangModelParserImpl implements YangModelParser {
             SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
             String prefix = null;
             List<String> augmentTargetPath = new ArrayList<String>();
+
             for (QName pathPart : augmentTargetSchemaPath.getPath()) {
                 prefix = pathPart.getPrefix();
                 augmentTargetPath.add(pathPart.getLocalName());
             }
-            ModuleImport dependentModuleImport = getModuleImport(builder,
-                    prefix);
-            String dependentModuleName = dependentModuleImport.getModuleName();
-            augmentTargetPath.add(0, dependentModuleName);
-
-            Date dependentModuleRevision = dependentModuleImport.getRevision();
-
-            TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
-                    .get(dependentModuleName);
-            ModuleBuilder dependentModule;
-            if (dependentModuleRevision == null) {
-                dependentModule = moduleBuildersByRevision.lastEntry()
-                        .getValue();
-            } else {
-                dependentModule = moduleBuildersByRevision
-                        .get(dependentModuleRevision);
-            }
+            ModuleBuilder dependentModule = findDependentModule(modules,
+                    module, prefix);
+            augmentTargetPath.add(0, dependentModule.getName());
 
             AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
                     .getNode(augmentTargetPath);
@@ -446,7 +604,7 @@ public class YangModelParserImpl implements YangModelParser {
             fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
             augments.add(result);
         }
-        builder.setAugmentations(augments);
+        module.setAugmentations(augments);
     }
 
     /**
@@ -464,148 +622,118 @@ public class YangModelParserImpl implements YangModelParser {
     }
 
     /**
-     * Get module import referenced by given prefix.
+     * Go through identity statements defined in current module and resolve
+     * their 'base' statement if present.
      *
-     * @param builder
-     *            module to search
-     * @param prefix
-     *            prefix associated with import
-     * @return ModuleImport based on given prefix
+     * @param modules
+     *            all modules
+     * @param module
+     *            module being resolved
      */
-    private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
-        ModuleImport moduleImport = null;
-        for (ModuleImport mi : builder.getModuleImports()) {
-            if (mi.getPrefix().equals(prefix)) {
-                moduleImport = mi;
-                break;
+    private void resolveIdentities(
+            Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            ModuleBuilder module) {
+        Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
+        for (IdentitySchemaNodeBuilder identity : identities) {
+            String baseIdentityName = identity.getBaseIdentityName();
+            if (baseIdentityName != null) {
+                String baseIdentityPrefix = null;
+                String baseIdentityLocalName = null;
+                if (baseIdentityName.contains(":")) {
+                    String[] splitted = baseIdentityName.split(":");
+                    baseIdentityPrefix = splitted[0];
+                    baseIdentityLocalName = splitted[1];
+                } else {
+                    baseIdentityPrefix = module.getPrefix();
+                    baseIdentityLocalName = baseIdentityName;
+                }
+                ModuleBuilder dependentModule = findDependentModule(modules,
+                        module, baseIdentityPrefix);
+
+                Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
+                        .getAddedIdentities();
+                for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
+                    if (idBuilder.getQName().getLocalName()
+                            .equals(baseIdentityLocalName)) {
+                        identity.setBaseIdentity(idBuilder);
+                    }
+                }
             }
         }
-        return moduleImport;
     }
 
     /**
-     * Helper method for resolving special 'min' or 'max' values in range
-     * constraint
+     * Find dependent module based on given prefix
      *
-     * @param ranges
-     *            ranges to resolve
-     * @param typeToResolve
-     *            type to resolve
-     * @param targetType
-     *            target type
      * @param modules
      *            all available modules
-     * @param builder
+     * @param module
      *            current module
+     * @param prefix
+     *            target module prefix
+     * @return
      */
-    private void resolveRanges(List<RangeConstraint> ranges,
-            TypeAwareBuilder typeToResolve, TypeDefinitionBuilder targetType,
+    private ModuleBuilder findDependentModule(
             Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            ModuleBuilder builder) {
-        if (ranges != null && ranges.size() > 0) {
-            Long min = (Long) ranges.get(0).getMin();
-            Long max = (Long) ranges.get(ranges.size() - 1).getMax();
-            // if range contains one of the special values 'min' or 'max'
-            if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {
-                Long[] values = parseRangeConstraint(typeToResolve, targetType,
-                        modules, builder);
-                if (min.equals(Long.MIN_VALUE)) {
-                    min = values[0];
-                    RangeConstraint oldFirst = ranges.get(0);
-                    RangeConstraint newFirst = BaseConstraints.rangeConstraint(
-                            min, oldFirst.getMax(), oldFirst.getDescription(),
-                            oldFirst.getReference());
-                    ranges.set(0, newFirst);
-                }
-                if (max.equals(Long.MAX_VALUE)) {
-                    max = values[1];
-                    RangeConstraint oldLast = ranges.get(ranges.size() - 1);
-                    RangeConstraint newLast = BaseConstraints.rangeConstraint(
-                            oldLast.getMin(), max, oldLast.getDescription(),
-                            oldLast.getReference());
-                    ranges.set(ranges.size() - 1, newLast);
-                }
+            ModuleBuilder module, String prefix) {
+        ModuleBuilder dependentModule = null;
+        Date dependentModuleRevision = null;
+
+        if (prefix.equals(module.getPrefix())) {
+            dependentModule = module;
+        } else {
+            ModuleImport dependentModuleImport = getModuleImport(module, prefix);
+            if (dependentModuleImport == null) {
+                throw new YangParseException("No import found with prefix '"
+                        + prefix + "' in module " + module.getName() + "'.");
+            }
+            String dependentModuleName = dependentModuleImport.getModuleName();
+            dependentModuleRevision = dependentModuleImport.getRevision();
+
+            TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
+                    .get(dependentModuleName);
+            if (dependentModuleRevision == null) {
+                dependentModule = moduleBuildersByRevision.lastEntry()
+                        .getValue();
+            } else {
+                dependentModule = moduleBuildersByRevision
+                        .get(dependentModuleRevision);
             }
         }
+
+        if (dependentModule == null) {
+            throw new YangParseException(
+                    "Failed to find dependent module with prefix '" + prefix
+                            + "' and revision '" + dependentModuleRevision
+                            + "'.");
+        }
+        return dependentModule;
     }
 
     /**
-     * Helper method for resolving special 'min' or 'max' values in length
-     * constraint
+     * Get module import referenced by given prefix.
      *
-     * @param ranges
-     *            ranges to resolve
-     * @param typeToResolve
-     *            type to resolve
-     * @param targetType
-     *            target type
-     * @param modules
-     *            all available modules
      * @param builder
-     *            current module
+     *            module to search
+     * @param prefix
+     *            prefix associated with import
+     * @return ModuleImport based on given prefix
      */
-    private void resolveLengths(List<LengthConstraint> lengths,
-            TypeAwareBuilder typeToResolve, TypeDefinitionBuilder targetType,
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            ModuleBuilder builder) {
-        if (lengths != null && lengths.size() > 0) {
-            Long min = lengths.get(0).getMin();
-            Long max = lengths.get(lengths.size() - 1).getMax();
-            // if length contains one of the special values 'min' or 'max'
-            if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {
-                Long[] values = parseRangeConstraint(typeToResolve, targetType,
-                        modules, builder);
-                if (min.equals(Long.MIN_VALUE)) {
-                    min = values[0];
-                    LengthConstraint oldFirst = lengths.get(0);
-                    LengthConstraint newFirst = BaseConstraints
-                            .lengthConstraint(min, oldFirst.getMax(),
-                                    oldFirst.getDescription(),
-                                    oldFirst.getReference());
-                    lengths.set(0, newFirst);
-                }
-                if (max.equals(Long.MAX_VALUE)) {
-                    max = values[1];
-                    LengthConstraint oldLast = lengths.get(lengths.size() - 1);
-                    LengthConstraint newLast = BaseConstraints
-                            .lengthConstraint(oldLast.getMin(), max,
-                                    oldLast.getDescription(),
-                                    oldLast.getReference());
-                    lengths.set(lengths.size() - 1, newLast);
-                }
+    private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
+        ModuleImport moduleImport = null;
+        for (ModuleImport mi : builder.getModuleImports()) {
+            if (mi.getPrefix().equals(prefix)) {
+                moduleImport = mi;
+                break;
             }
         }
-    }
-
-    private Long[] parseRangeConstraint(TypeAwareBuilder typeToResolve,
-            TypeDefinitionBuilder targetType,
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            ModuleBuilder builder) {
-        TypeDefinition<?> targetBaseType = targetType.getBaseType();
-
-        if (targetBaseType instanceof IntegerTypeDefinition) {
-            IntegerTypeDefinition itd = (IntegerTypeDefinition) targetBaseType;
-            List<RangeConstraint> ranges = itd.getRangeStatements();
-            Long min = (Long) ranges.get(0).getMin();
-            Long max = (Long) ranges.get(ranges.size() - 1).getMax();
-            return new Long[] { min, max };
-        } else if (targetBaseType instanceof DecimalTypeDefinition) {
-            DecimalTypeDefinition dtd = (DecimalTypeDefinition) targetBaseType;
-            List<RangeConstraint> ranges = dtd.getRangeStatements();
-            Long min = (Long) ranges.get(0).getMin();
-            Long max = (Long) ranges.get(ranges.size() - 1).getMax();
-            return new Long[] { min, max };
-        } else {
-            return parseRangeConstraint(typeToResolve,
-                    findTypeDefinitionBuilder(modules, typeToResolve, builder),
-                    modules, builder);
-        }
+        return moduleImport;
     }
 
     private Date createEpochTime() {
-        Calendar c = Calendar.getInstance();
-        c.setTimeInMillis(0);
-        return c.getTime();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(0);
+        return calendar.getTime();
     }
 
     private static class SchemaContextImpl implements SchemaContext {
@@ -657,45 +785,4 @@ public class YangModelParserImpl implements YangModelParser {
         }
     }
 
-    private static class TypeConstraints {
-        private final List<RangeConstraint> ranges = new ArrayList<RangeConstraint>();
-        private final List<LengthConstraint> lengths = new ArrayList<LengthConstraint>();
-        private final List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
-        private Integer fractionDigits;
-
-        public List<RangeConstraint> getRanges() {
-            return ranges;
-        }
-
-        public void addRanges(List<RangeConstraint> ranges) {
-            this.ranges.addAll(0, ranges);
-        }
-
-        public List<LengthConstraint> getLengths() {
-            return lengths;
-        }
-
-        public void addLengths(List<LengthConstraint> lengths) {
-            this.lengths.addAll(0, lengths);
-        }
-
-        public List<PatternConstraint> getPatterns() {
-            return patterns;
-        }
-
-        public void addPatterns(List<PatternConstraint> patterns) {
-            this.patterns.addAll(0, patterns);
-        }
-
-        public Integer getFractionDigits() {
-            return fractionDigits;
-        }
-
-        public void setFractionDigits(Integer fractionDigits) {
-            if (fractionDigits != null) {
-                this.fractionDigits = fractionDigits;
-            }
-        }
-    }
-
 }