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 / YangModelParserImpl.java
index 5cc9f8e4aa065ca7a189ba2c31408c3894957267..af972f08a5a687849d0bc2a67f41b312a0063133 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.yang.model.parser.impl;\r
-\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileNotFoundException;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.util.ArrayList;\r
-import java.util.Calendar;\r
-import java.util.Date;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.TreeMap;\r
-\r
-import org.antlr.v4.runtime.ANTLRInputStream;\r
-import org.antlr.v4.runtime.CommonTokenStream;\r
-import org.antlr.v4.runtime.tree.ParseTree;\r
-import org.antlr.v4.runtime.tree.ParseTreeWalker;\r
-import org.opendaylight.controller.antlrv4.code.gen.YangLexer;\r
-import org.opendaylight.controller.antlrv4.code.gen.YangParser;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.model.api.AugmentationSchema;\r
-import org.opendaylight.controller.yang.model.api.DataSchemaNode;\r
-import org.opendaylight.controller.yang.model.api.ExtensionDefinition;\r
-import org.opendaylight.controller.yang.model.api.Module;\r
-import org.opendaylight.controller.yang.model.api.ModuleImport;\r
-import org.opendaylight.controller.yang.model.api.NotificationDefinition;\r
-import org.opendaylight.controller.yang.model.api.RpcDefinition;\r
-import org.opendaylight.controller.yang.model.api.SchemaContext;\r
-import org.opendaylight.controller.yang.model.api.SchemaPath;\r
-import org.opendaylight.controller.yang.model.api.TypeDefinition;\r
-import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;\r
-import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;\r
-import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;\r
-import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;\r
-import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;\r
-import org.opendaylight.controller.yang.model.api.type.LengthConstraint;\r
-import org.opendaylight.controller.yang.model.api.type.PatternConstraint;\r
-import org.opendaylight.controller.yang.model.api.type.RangeConstraint;\r
-import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;\r
-import org.opendaylight.controller.yang.model.parser.api.YangModelParser;\r
-import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;\r
-import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;\r
-import org.opendaylight.controller.yang.model.util.BaseConstraints;\r
-import org.opendaylight.controller.yang.model.util.BinaryType;\r
-import org.opendaylight.controller.yang.model.util.BitsType;\r
-import org.opendaylight.controller.yang.model.util.StringType;\r
-import org.opendaylight.controller.yang.model.util.UnknownType;\r
-import org.opendaylight.controller.yang.model.util.YangTypesConverter;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-public class YangModelParserImpl implements YangModelParser {\r
-\r
-    private static final Logger logger = LoggerFactory\r
-            .getLogger(YangModelParserImpl.class);\r
-\r
-    @Override\r
-    public Module parseYangModel(String yangFile) {\r
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);\r
-        Set<Module> result = build(modules);\r
-        return result.iterator().next();\r
-    }\r
-\r
-    @Override\r
-    public Set<Module> parseYangModels(String... yangFiles) {\r
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);\r
-        Set<Module> result = build(modules);\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    public Set<Module> parseYangModelsFromStreams(\r
-            InputStream... yangModelStreams) {\r
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);\r
-        Set<Module> result = build(modules);\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    public SchemaContext resolveSchemaContext(Set<Module> modules) {\r
-        return new SchemaContextImpl(modules);\r
-    }\r
-\r
-    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(\r
-            String... yangFiles) {\r
-        InputStream[] streams = new InputStream[yangFiles.length];\r
-        for (int i = 0; i < yangFiles.length; i++) {\r
-            final String yangFileName = yangFiles[i];\r
-            final File yangFile = new File(yangFileName);\r
-            FileInputStream inStream = null;\r
-            try {\r
-                inStream = new FileInputStream(yangFile);\r
-            } catch (FileNotFoundException e) {\r
-                logger.warn("Exception while reading yang stream: " + inStream,\r
-                        e);\r
-            }\r
-            streams[i] = inStream;\r
-        }\r
-        return resolveModuleBuildersFromStreams(streams);\r
-    }\r
-\r
-    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(\r
-            InputStream... yangFiles) {\r
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();\r
-        final ParseTreeWalker walker = new ParseTreeWalker();\r
-        final List<ParseTree> trees = parseStreams(yangFiles);\r
-        final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];\r
-\r
-        for (int i = 0; i < trees.size(); i++) {\r
-            final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();\r
-            walker.walk(yangModelParser, trees.get(i));\r
-            builders[i] = yangModelParser.getModuleBuilder();\r
-        }\r
-\r
-        for (ModuleBuilder builder : builders) {\r
-            final String builderName = builder.getName();\r
-            Date builderRevision = builder.getRevision();\r
-            if (builderRevision == null) {\r
-                builderRevision = createEpochTime();\r
-            }\r
-            TreeMap<Date, ModuleBuilder> builderByRevision = modules\r
-                    .get(builderName);\r
-            if (builderByRevision == null) {\r
-                builderByRevision = new TreeMap<Date, ModuleBuilder>();\r
-            }\r
-            builderByRevision.put(builderRevision, builder);\r
-            modules.put(builderName, builderByRevision);\r
-        }\r
-        return modules;\r
-    }\r
-\r
-    private List<ParseTree> parseStreams(InputStream... yangStreams) {\r
-        List<ParseTree> trees = new ArrayList<ParseTree>();\r
-        for (InputStream yangStream : yangStreams) {\r
-            trees.add(parseStream(yangStream));\r
-        }\r
-        return trees;\r
-    }\r
-\r
-    private ParseTree parseStream(InputStream yangStream) {\r
-        ParseTree result = null;\r
-        try {\r
-            final ANTLRInputStream input = new ANTLRInputStream(yangStream);\r
-            final YangLexer lexer = new YangLexer(input);\r
-            final CommonTokenStream tokens = new CommonTokenStream(lexer);\r
-            final YangParser parser = new YangParser(tokens);\r
-            result = parser.yang();\r
-        } catch (IOException e) {\r
-            logger.warn("Exception while reading yang file: " + yangStream, e);\r
-        }\r
-        return result;\r
-    }\r
-\r
-    private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {\r
-        // first validate\r
-        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules\r
-                .entrySet()) {\r
-            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()\r
-                    .entrySet()) {\r
-                ModuleBuilder moduleBuilder = childEntry.getValue();\r
-                validateBuilder(modules, moduleBuilder);\r
-            }\r
-        }\r
-        // then build\r
-        final Set<Module> result = new HashSet<Module>();\r
-        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules\r
-                .entrySet()) {\r
-            final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();\r
-            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()\r
-                    .entrySet()) {\r
-                ModuleBuilder moduleBuilder = childEntry.getValue();\r
-                modulesByRevision.put(childEntry.getKey(),\r
-                        moduleBuilder.build());\r
-                result.add(moduleBuilder.build());\r
-            }\r
-        }\r
-\r
-        return result;\r
-    }\r
-\r
-    private void validateBuilder(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder builder) {\r
-        resolveTypedefs(modules, builder);\r
-        resolveAugments(modules, builder);\r
-        resolveIdentities(modules, builder);\r
-    }\r
-\r
-    /**\r
-     * Search for dirty nodes (node which contains UnknownType) and resolve\r
-     * unknown types.\r
-     *\r
-     * @param modules\r
-     *            all available modules\r
-     * @param module\r
-     *            current module\r
-     */\r
-    private void resolveTypedefs(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder module) {\r
-        Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();\r
-        if (dirtyNodes.size() == 0) {\r
-            return;\r
-        } else {\r
-            for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes\r
-                    .entrySet()) {\r
-                TypeAwareBuilder typeToResolve = entry.getValue();\r
-\r
-                if (typeToResolve instanceof UnionTypeBuilder) {\r
-                    resolveUnionTypeBuilder(modules, module,\r
-                            (UnionTypeBuilder) typeToResolve);\r
-                } else {\r
-                    UnknownType ut = (UnknownType) typeToResolve.getType();\r
-                    TypeDefinition<?> resolvedType = findTargetType(ut,\r
-                            modules, module);\r
-                    typeToResolve.setType(resolvedType);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    private UnionTypeBuilder resolveUnionTypeBuilder(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder builder, UnionTypeBuilder unionTypeBuilderToResolve) {\r
-        List<TypeDefinition<?>> resolvedTypes = new ArrayList<TypeDefinition<?>>();\r
-        List<TypeDefinition<?>> typesToRemove = new ArrayList<TypeDefinition<?>>();\r
-\r
-        for (TypeDefinition<?> td : unionTypeBuilderToResolve.getTypes()) {\r
-            if (td instanceof UnknownType) {\r
-                TypeDefinition<?> resolvedType = findTargetType(\r
-                        (UnknownType) td, modules, builder);\r
-                resolvedTypes.add(resolvedType);\r
-                typesToRemove.add(td);\r
-            }\r
-        }\r
-\r
-        List<TypeDefinition<?>> unionTypeBuilderTypes = unionTypeBuilderToResolve\r
-                .getTypes();\r
-        unionTypeBuilderTypes.addAll(resolvedTypes);\r
-        unionTypeBuilderTypes.removeAll(typesToRemove);\r
-\r
-        return unionTypeBuilderToResolve;\r
-    }\r
-\r
-    private TypeDefinition<?> findTargetType(UnknownType ut,\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder builder) {\r
-\r
-        Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(\r
-                modules, ut, builder);\r
-        TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder\r
-                .entrySet().iterator().next().getKey();\r
-        TypeConstraints constraints = foundedTypeDefinitionBuilder.entrySet()\r
-                .iterator().next().getValue();\r
-\r
-        TypeDefinition<?> targetTypeBaseType = targetType.getBaseType();\r
-\r
-        // RANGE\r
-        List<RangeConstraint> ranges = ut.getRangeStatements();\r
-        resolveRanges(ranges, targetType, modules, builder);\r
-        // LENGTH\r
-        List<LengthConstraint> lengths = ut.getLengthStatements();\r
-        resolveLengths(lengths, targetType, modules, builder);\r
-        // PATTERN\r
-        List<PatternConstraint> patterns = ut.getPatterns();\r
-        // Fraction Digits\r
-        Integer fractionDigits = ut.getFractionDigits();\r
-\r
-        targetTypeBaseType = mergeConstraints(targetTypeBaseType, constraints, ranges, lengths,\r
-                patterns, fractionDigits);\r
-\r
-        return targetTypeBaseType;\r
-    }\r
-\r
-    /**\r
-     * Merge curent constraints with founded type constraints\r
-     *\r
-     * @param targetTypeBaseType\r
-     * @param constraints\r
-     * @param ranges\r
-     * @param lengths\r
-     * @param patterns\r
-     * @param fractionDigits\r
-     */\r
-    private TypeDefinition<?> mergeConstraints(TypeDefinition<?> targetTypeBaseType,\r
-            TypeConstraints constraints, List<RangeConstraint> ranges,\r
-            List<LengthConstraint> lengths, List<PatternConstraint> patterns,\r
-            Integer fractionDigits) {\r
-        String targetTypeBaseTypeName = targetTypeBaseType.getQName()\r
-                .getLocalName();\r
-        // enumeration, leafref and identityref omitted because they have no\r
-        // restrictions\r
-        if (targetTypeBaseType instanceof DecimalTypeDefinition) {\r
-            List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();\r
-            fullRanges.addAll(constraints.getRanges());\r
-            fullRanges.addAll(ranges);\r
-            Integer fd = fractionDigits == null ? constraints\r
-                    .getFractionDigits() : fractionDigits;\r
-            targetTypeBaseType = YangTypesConverter\r
-                    .javaTypeForBaseYangDecimal64Type(fullRanges, fd);\r
-        } else if (targetTypeBaseType instanceof IntegerTypeDefinition) {\r
-            List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();\r
-            fullRanges.addAll(constraints.getRanges());\r
-            fullRanges.addAll(ranges);\r
-            if (targetTypeBaseTypeName.startsWith("int")) {\r
-                targetTypeBaseType = YangTypesConverter\r
-                        .javaTypeForBaseYangSignedIntegerType(\r
-                                targetTypeBaseTypeName, fullRanges);\r
-            } else {\r
-                targetTypeBaseType = YangTypesConverter\r
-                        .javaTypeForBaseYangUnsignedIntegerType(\r
-                                targetTypeBaseTypeName, fullRanges);\r
-            }\r
-        } else if (targetTypeBaseType instanceof StringTypeDefinition) {\r
-            List<LengthConstraint> fullLengths = new ArrayList<LengthConstraint>();\r
-            fullLengths.addAll(constraints.getLengths());\r
-            fullLengths.addAll(lengths);\r
-            List<PatternConstraint> fullPatterns = new ArrayList<PatternConstraint>();\r
-            fullPatterns.addAll(constraints.getPatterns());\r
-            fullPatterns.addAll(patterns);\r
-            targetTypeBaseType = new StringType(fullLengths, fullPatterns);\r
-        } else if (targetTypeBaseType instanceof BitsTypeDefinition) {\r
-            BitsTypeDefinition bitsType = (BitsTypeDefinition) targetTypeBaseType;\r
-            List<Bit> bits = bitsType.getBits();\r
-            targetTypeBaseType = new BitsType(bits);\r
-        } else if (targetTypeBaseType instanceof BinaryTypeDefinition) {\r
-            targetTypeBaseType = new BinaryType(null, lengths, null);\r
-        }\r
-        return targetTypeBaseType;\r
-    }\r
-\r
-    private TypeDefinitionBuilder findTypeDefinitionBuilder(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            UnknownType unknownType, ModuleBuilder builder) {\r
-        Map<TypeDefinitionBuilder, TypeConstraints> result = findTypeDefinitionBuilderWithConstraints(\r
-                modules, unknownType, builder);\r
-        return result.entrySet().iterator().next().getKey();\r
-    }\r
-\r
-    private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            UnknownType unknownType, ModuleBuilder builder) {\r
-        return findTypeDefinitionBuilderWithConstraints(new TypeConstraints(),\r
-                modules, unknownType, builder);\r
-    }\r
-\r
-    /**\r
-     * Traverse through all referenced types chain until base YANG type is\r
-     * founded.\r
-     *\r
-     * @param constraints\r
-     *            current type constraints\r
-     * @param modules\r
-     *            all available modules\r
-     * @param unknownType\r
-     *            unknown type\r
-     * @param builder\r
-     *            current module\r
-     * @return map, where key is type referenced and value is its constraints\r
-     */\r
-    private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(\r
-            TypeConstraints constraints,\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            UnknownType unknownType, ModuleBuilder builder) {\r
-        Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();\r
-        QName unknownTypeQName = unknownType.getQName();\r
-        String unknownTypeName = unknownTypeQName.getLocalName();\r
-        String unknownTypePrefix = unknownTypeQName.getPrefix();\r
-\r
-        // search for module which contains referenced typedef\r
-        ModuleBuilder dependentModuleBuilder;\r
-        if (unknownTypePrefix.equals(builder.getPrefix())) {\r
-            dependentModuleBuilder = builder;\r
-        } else {\r
-            dependentModuleBuilder = findDependentModule(modules, builder,\r
-                    unknownTypePrefix);\r
-        }\r
-\r
-        // pull all typedef statements from dependent module...\r
-        final Set<TypeDefinitionBuilder> typedefs = dependentModuleBuilder\r
-                .getModuleTypedefs();\r
-        // and search for referenced typedef\r
-        TypeDefinitionBuilder lookedUpBuilder = null;\r
-        for (TypeDefinitionBuilder tdb : typedefs) {\r
-            QName qname = tdb.getQName();\r
-            if (qname.getLocalName().equals(unknownTypeName)) {\r
-                lookedUpBuilder = tdb;\r
-                break;\r
-            }\r
-        }\r
-\r
-        // if referenced type is UnknownType again, search recursively with\r
-        // current constraints\r
-        TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();\r
-        if (referencedType instanceof UnknownType) {\r
-            UnknownType unknown = (UnknownType) lookedUpBuilder.getBaseType();\r
-\r
-            final List<RangeConstraint> ranges = unknown.getRangeStatements();\r
-            constraints.addRanges(ranges);\r
-            final List<LengthConstraint> lengths = unknown\r
-                    .getLengthStatements();\r
-            constraints.addLengths(lengths);\r
-            final List<PatternConstraint> patterns = unknown.getPatterns();\r
-            constraints.addPatterns(patterns);\r
-            return findTypeDefinitionBuilderWithConstraints(constraints,\r
-                    modules, unknown, dependentModuleBuilder);\r
-        } else {\r
-            // pull restriction from this base type and add them to\r
-            // 'constraints'\r
-            if (referencedType instanceof DecimalTypeDefinition) {\r
-                constraints.addRanges(((DecimalTypeDefinition) referencedType)\r
-                        .getRangeStatements());\r
-                constraints\r
-                        .setFractionDigits(((DecimalTypeDefinition) referencedType)\r
-                                .getFractionDigits());\r
-            } else if (referencedType instanceof IntegerTypeDefinition) {\r
-                constraints.addRanges(((IntegerTypeDefinition) referencedType)\r
-                        .getRangeStatements());\r
-            } else if (referencedType instanceof StringTypeDefinition) {\r
-                constraints.addPatterns(((StringTypeDefinition) referencedType)\r
-                        .getPatterns());\r
-            } else if (referencedType instanceof BinaryTypeDefinition) {\r
-                constraints.addLengths(((BinaryTypeDefinition) referencedType)\r
-                        .getLengthConstraints());\r
-            }\r
-            result.put(lookedUpBuilder, constraints);\r
-            return result;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Go through all augmentation definitions and resolve them. This means find\r
-     * referenced node and add child nodes to it.\r
-     *\r
-     * @param modules\r
-     *            all available modules\r
-     * @param module\r
-     *            current module\r
-     */\r
-    private void resolveAugments(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder module) {\r
-        Set<AugmentationSchemaBuilder> augmentBuilders = module\r
-                .getAddedAugments();\r
-\r
-        Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();\r
-        for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {\r
-            SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();\r
-            String prefix = null;\r
-            List<String> augmentTargetPath = new ArrayList<String>();\r
-\r
-            for (QName pathPart : augmentTargetSchemaPath.getPath()) {\r
-                prefix = pathPart.getPrefix();\r
-                augmentTargetPath.add(pathPart.getLocalName());\r
-            }\r
-            ModuleBuilder dependentModule = findDependentModule(modules,\r
-                    module, prefix);\r
-            //\r
-            augmentTargetPath.add(0, dependentModule.getName());\r
-            //\r
-\r
-\r
-            AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule\r
-                    .getNode(augmentTargetPath);\r
-            AugmentationSchema result = augmentBuilder.build();\r
-            augmentTarget.addAugmentation(result);\r
-            fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);\r
-            augments.add(result);\r
-        }\r
-        module.setAugmentations(augments);\r
-    }\r
-\r
-    /**\r
-     * Add all augment's child nodes to given target.\r
-     *\r
-     * @param augment\r
-     * @param target\r
-     */\r
-    private void fillAugmentTarget(AugmentationSchemaBuilder augment,\r
-            ChildNodeBuilder target) {\r
-        for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {\r
-            builder.setAugmenting(true);\r
-            target.addChildNode(builder);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Go through identity statements defined in current module and resolve\r
-     * their 'base' statement if present.\r
-     *\r
-     * @param modules\r
-     *            all modules\r
-     * @param module\r
-     *            module being resolved\r
-     */\r
-    private void resolveIdentities(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder module) {\r
-        Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();\r
-        for (IdentitySchemaNodeBuilder identity : identities) {\r
-            String baseIdentityName = identity.getBaseIdentityName();\r
-            if (baseIdentityName != null) {\r
-                String baseIdentityPrefix = null;\r
-                String baseIdentityLocalName = null;\r
-                if (baseIdentityName.contains(":")) {\r
-                    String[] splitted = baseIdentityName.split(":");\r
-                    baseIdentityPrefix = splitted[0];\r
-                    baseIdentityLocalName = splitted[1];\r
-                } else {\r
-                    baseIdentityPrefix = module.getPrefix();\r
-                    baseIdentityLocalName = baseIdentityName;\r
-                }\r
-                ModuleBuilder dependentModule;\r
-                if (baseIdentityPrefix.equals(module.getPrefix())) {\r
-                    dependentModule = module;\r
-                } else {\r
-                    dependentModule = findDependentModule(modules, module,\r
-                            baseIdentityPrefix);\r
-                }\r
-\r
-                Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule\r
-                        .getAddedIdentities();\r
-                for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {\r
-                    if (idBuilder.getQName().getLocalName()\r
-                            .equals(baseIdentityLocalName)) {\r
-                        identity.setBaseIdentity(idBuilder);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Find dependent module based on given prefix\r
-     *\r
-     * @param modules\r
-     *            all available modules\r
-     * @param module\r
-     *            current module\r
-     * @param prefix\r
-     *            target module prefix\r
-     * @return dependent module builder\r
-     */\r
-    private ModuleBuilder findDependentModule(\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder module, String prefix) {\r
-        ModuleImport dependentModuleImport = getModuleImport(module, prefix);\r
-        String dependentModuleName = dependentModuleImport.getModuleName();\r
-        Date dependentModuleRevision = dependentModuleImport.getRevision();\r
-\r
-        TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules\r
-                .get(dependentModuleName);\r
-        ModuleBuilder dependentModule;\r
-        if (dependentModuleRevision == null) {\r
-            dependentModule = moduleBuildersByRevision.lastEntry().getValue();\r
-        } else {\r
-            dependentModule = moduleBuildersByRevision\r
-                    .get(dependentModuleRevision);\r
-        }\r
-        return dependentModule;\r
-    }\r
-\r
-    /**\r
-     * Get module import referenced by given prefix.\r
-     *\r
-     * @param builder\r
-     *            module to search\r
-     * @param prefix\r
-     *            prefix associated with import\r
-     * @return ModuleImport based on given prefix\r
-     */\r
-    private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {\r
-        ModuleImport moduleImport = null;\r
-        for (ModuleImport mi : builder.getModuleImports()) {\r
-            if (mi.getPrefix().equals(prefix)) {\r
-                moduleImport = mi;\r
-                break;\r
-            }\r
-        }\r
-        return moduleImport;\r
-    }\r
-\r
-    /**\r
-     * Helper method for resolving special 'min' or 'max' values in range\r
-     * constraint\r
-     *\r
-     * @param ranges\r
-     *            ranges to resolve\r
-     * @param targetType\r
-     *            target type\r
-     * @param modules\r
-     *            all available modules\r
-     * @param builder\r
-     *            current module\r
-     */\r
-    private void resolveRanges(List<RangeConstraint> ranges,\r
-            TypeDefinitionBuilder targetType,\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder builder) {\r
-        if (ranges != null && ranges.size() > 0) {\r
-            Long min = (Long) ranges.get(0).getMin();\r
-            Long max = (Long) ranges.get(ranges.size() - 1).getMax();\r
-            // if range contains one of the special values 'min' or 'max'\r
-            if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {\r
-                Long[] values = parseRangeConstraint(targetType, modules,\r
-                        builder);\r
-                if (min.equals(Long.MIN_VALUE)) {\r
-                    min = values[0];\r
-                    RangeConstraint oldFirst = ranges.get(0);\r
-                    RangeConstraint newFirst = BaseConstraints.rangeConstraint(\r
-                            min, oldFirst.getMax(), oldFirst.getDescription(),\r
-                            oldFirst.getReference());\r
-                    ranges.set(0, newFirst);\r
-                }\r
-                if (max.equals(Long.MAX_VALUE)) {\r
-                    max = values[1];\r
-                    RangeConstraint oldLast = ranges.get(ranges.size() - 1);\r
-                    RangeConstraint newLast = BaseConstraints.rangeConstraint(\r
-                            oldLast.getMin(), max, oldLast.getDescription(),\r
-                            oldLast.getReference());\r
-                    ranges.set(ranges.size() - 1, newLast);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Helper method for resolving special 'min' or 'max' values in length\r
-     * constraint\r
-     *\r
-     * @param lengths\r
-     *            lengths to resolve\r
-     * @param targetType\r
-     *            target type\r
-     * @param modules\r
-     *            all available modules\r
-     * @param builder\r
-     *            current module\r
-     */\r
-    private void resolveLengths(List<LengthConstraint> lengths,\r
-            TypeDefinitionBuilder targetType,\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder builder) {\r
-        if (lengths != null && lengths.size() > 0) {\r
-            Long min = lengths.get(0).getMin().longValue();\r
-            Long max = lengths.get(lengths.size() - 1).getMax().longValue();\r
-            // if length contains one of the special values 'min' or 'max'\r
-            if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {\r
-                Long[] values = parseRangeConstraint(targetType, modules,\r
-                        builder);\r
-                if (min.equals(Long.MIN_VALUE)) {\r
-                    min = values[0];\r
-                    LengthConstraint oldFirst = lengths.get(0);\r
-                    LengthConstraint newFirst = BaseConstraints\r
-                            .lengthConstraint(min, oldFirst.getMax(),\r
-                                    oldFirst.getDescription(),\r
-                                    oldFirst.getReference());\r
-                    lengths.set(0, newFirst);\r
-                }\r
-                if (max.equals(Long.MAX_VALUE)) {\r
-                    max = values[1];\r
-                    LengthConstraint oldLast = lengths.get(lengths.size() - 1);\r
-                    LengthConstraint newLast = BaseConstraints\r
-                            .lengthConstraint(oldLast.getMin(), max,\r
-                                    oldLast.getDescription(),\r
-                                    oldLast.getReference());\r
-                    lengths.set(lengths.size() - 1, newLast);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    private Long[] parseRangeConstraint(TypeDefinitionBuilder targetType,\r
-            Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
-            ModuleBuilder builder) {\r
-        TypeDefinition<?> targetBaseType = targetType.getBaseType();\r
-\r
-        if (targetBaseType instanceof IntegerTypeDefinition) {\r
-            IntegerTypeDefinition itd = (IntegerTypeDefinition) targetBaseType;\r
-            List<RangeConstraint> ranges = itd.getRangeStatements();\r
-            Long min = (Long) ranges.get(0).getMin();\r
-            Long max = (Long) ranges.get(ranges.size() - 1).getMax();\r
-            return new Long[] { min, max };\r
-        } else if (targetBaseType instanceof DecimalTypeDefinition) {\r
-            DecimalTypeDefinition dtd = (DecimalTypeDefinition) targetBaseType;\r
-            List<RangeConstraint> ranges = dtd.getRangeStatements();\r
-            Long min = (Long) ranges.get(0).getMin();\r
-            Long max = (Long) ranges.get(ranges.size() - 1).getMax();\r
-            return new Long[] { min, max };\r
-        } else {\r
-            return parseRangeConstraint(\r
-                    findTypeDefinitionBuilder(modules,\r
-                            (UnknownType) targetBaseType, builder), modules,\r
-                    builder);\r
-        }\r
-    }\r
-\r
-    private Date createEpochTime() {\r
-        Calendar c = Calendar.getInstance();\r
-        c.setTimeInMillis(0);\r
-        return c.getTime();\r
-    }\r
-\r
-    private static class SchemaContextImpl implements SchemaContext {\r
-        private final Set<Module> modules;\r
-\r
-        private SchemaContextImpl(Set<Module> modules) {\r
-            this.modules = modules;\r
-        }\r
-\r
-        @Override\r
-        public Set<DataSchemaNode> getDataDefinitions() {\r
-            final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();\r
-            for (Module m : modules) {\r
-                dataDefs.addAll(m.getChildNodes());\r
-            }\r
-            return dataDefs;\r
-        }\r
-\r
-        @Override\r
-        public Set<Module> getModules() {\r
-            return modules;\r
-        }\r
-\r
-        @Override\r
-        public Set<NotificationDefinition> getNotifications() {\r
-            final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();\r
-            for (Module m : modules) {\r
-                notifications.addAll(m.getNotifications());\r
-            }\r
-            return notifications;\r
-        }\r
-\r
-        @Override\r
-        public Set<RpcDefinition> getOperations() {\r
-            final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();\r
-            for (Module m : modules) {\r
-                rpcs.addAll(m.getRpcs());\r
-            }\r
-            return rpcs;\r
-        }\r
-\r
-        @Override\r
-        public Set<ExtensionDefinition> getExtensions() {\r
-            final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();\r
-            for (Module m : modules) {\r
-                extensions.addAll(m.getExtensionSchemaNodes());\r
-            }\r
-            return extensions;\r
-        }\r
-    }\r
-\r
-    private static class TypeConstraints {\r
-        private final List<RangeConstraint> ranges = new ArrayList<RangeConstraint>();\r
-        private final List<LengthConstraint> lengths = new ArrayList<LengthConstraint>();\r
-        private final List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();\r
-        private Integer fractionDigits;\r
-\r
-        public List<RangeConstraint> getRanges() {\r
-            return ranges;\r
-        }\r
-\r
-        public void addRanges(List<RangeConstraint> ranges) {\r
-            this.ranges.addAll(0, ranges);\r
-        }\r
-\r
-        public List<LengthConstraint> getLengths() {\r
-            return lengths;\r
-        }\r
-\r
-        public void addLengths(List<LengthConstraint> lengths) {\r
-            this.lengths.addAll(0, lengths);\r
-        }\r
-\r
-        public List<PatternConstraint> getPatterns() {\r
-            return patterns;\r
-        }\r
-\r
-        public void addPatterns(List<PatternConstraint> patterns) {\r
-            this.patterns.addAll(0, patterns);\r
-        }\r
-\r
-        public Integer getFractionDigits() {\r
-            return fractionDigits;\r
-        }\r
-\r
-        public void setFractionDigits(Integer fractionDigits) {\r
-            if (fractionDigits != null) {\r
-                this.fractionDigits = fractionDigits;\r
-            }\r
-        }\r
-    }\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+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.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+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.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;
+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;
+import org.opendaylight.controller.yang.model.parser.builder.api.Builder;
+import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder;
+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.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.ContainerSchemaNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.builder.impl.IdentityrefTypeBuilder;
+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;
+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.ParserUtils;
+import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
+import org.opendaylight.controller.yang.model.parser.util.RefineHolder.Refine;
+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.IdentityrefType;
+import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.model.validator.YangModelBasicValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class YangModelParserImpl implements YangModelParser {
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(YangModelParserImpl.class);
+
+    @Override
+    public Module parseYangModel(final String yangFile) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFile);
+        final Set<Module> result = build(modules);
+        return result.iterator().next();
+    }
+
+    @Override
+    public Set<Module> parseYangModels(final String... yangFiles) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFiles);
+        return build(modules);
+    }
+
+    @Override
+    public Set<Module> parseYangModelsFromStreams(
+            final InputStream... yangModelStreams) {
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
+        return build(modules);
+    }
+
+    @Override
+    public SchemaContext resolveSchemaContext(final Set<Module> modules) {
+        return new SchemaContextImpl(modules);
+    }
+
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
+            final String... yangFiles) {
+        final InputStream[] streams = loadStreams(yangFiles);
+        Map<String, TreeMap<Date, ModuleBuilder>> result = Collections
+                .emptyMap();
+
+        if (streams != null) {
+            result = resolveModuleBuilders(streams);
+            closeStreams(streams);
+        }
+        return result;
+    }
+
+    private InputStream[] loadStreams(final String... yangFiles) {
+        final InputStream[] streams = new InputStream[yangFiles.length];
+        for (int i = 0; i < yangFiles.length; i++) {
+            final String yangFileName = yangFiles[i];
+            final File yangFile = new File(yangFileName);
+            try {
+                streams[i] = new FileInputStream(yangFile);
+            } catch (FileNotFoundException e) {
+                logger.warn("Exception while reading yang stream: "
+                        + streams[i], e);
+            }
+        }
+        return streams;
+    }
+
+    private void closeStreams(final InputStream[] streams) {
+        if (streams != null) {
+            for (int i = 0; i < streams.length; i++) {
+                try {
+                    if (streams[i] != null) {
+                        streams[i].close();
+                    }
+                } catch (IOException e) {
+                    logger.warn("Exception while closing yang stream: "
+                            + streams[i], e);
+                }
+            }
+        }
+    }
+
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
+            final 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()];
+
+        // validate yang
+        new YangModelBasicValidator(walker).validate(trees);
+
+        YangModelParserListenerImpl yangModelParser = null;
+        for (int i = 0; i < trees.size(); i++) {
+            yangModelParser = new YangModelParserListenerImpl();
+            walker.walk(yangModelParser, trees.get(i));
+            builders[i] = yangModelParser.getModuleBuilder();
+        }
+
+        for (ModuleBuilder builder : builders) {
+            final String builderName = builder.getName();
+            Date builderRevision = builder.getRevision();
+            if (builderRevision == null) {
+                builderRevision = new Date(0L);
+            }
+            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> parseStreams(final InputStream... yangStreams) {
+        final List<ParseTree> trees = new ArrayList<ParseTree>();
+        for (InputStream yangStream : yangStreams) {
+            trees.add(parseStream(yangStream));
+        }
+        return trees;
+    }
+
+    private ParseTree parseStream(final InputStream yangStream) {
+        ParseTree result = null;
+        try {
+            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: " + yangStream, e);
+        }
+        return result;
+    }
+
+    private Set<Module> build(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+        // fix unresolved nodes
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
+                .entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
+                    .entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                fixUnresolvedNodes(modules, moduleBuilder);
+            }
+        }
+        resolveAugments(modules);
+
+        // build
+        final Set<Module> result = new HashSet<Module>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
+                .entrySet()) {
+            final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
+                    .entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                final Module module = moduleBuilder.build();
+                modulesByRevision.put(childEntry.getKey(), module);
+                result.add(module);
+            }
+        }
+        return result;
+    }
+
+    private void fixUnresolvedNodes(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+        resolveDirtyNodes(modules, builder);
+        resolveIdentities(modules, builder);
+        resolveUses(modules, builder);
+    }
+
+    /**
+     * Search for dirty nodes (node which contains UnknownType) and resolve
+     * unknown types.
+     *
+     * @param modules
+     *            all available modules
+     * @param module
+     *            current module
+     */
+    private void resolveDirtyNodes(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
+                .getDirtyNodes();
+        if (!dirtyNodes.isEmpty()) {
+            for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
+                    .entrySet()) {
+
+                final TypeAwareBuilder nodeToResolve = entry.getValue();
+                // different handling for union types
+                if (nodeToResolve instanceof UnionTypeBuilder) {
+                    final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
+                    final List<TypeDefinition<?>> unionTypes = union.getTypes();
+                    final List<UnknownType> toRemove = new ArrayList<UnknownType>();
+                    for (TypeDefinition<?> td : unionTypes) {
+                        if (td instanceof UnknownType) {
+                            final UnknownType unknownType = (UnknownType) td;
+                            final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
+                                    nodeToResolve, unknownType, modules, module);
+                            union.setType(resolvedType);
+                            toRemove.add(unknownType);
+                        }
+                    }
+                    unionTypes.removeAll(toRemove);
+                } else if(nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
+                    IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder)nodeToResolve.getTypedef();
+                    nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref)));
+                } else {
+                    final TypeDefinitionBuilder resolvedType = resolveType(
+                            nodeToResolve, modules, module);
+                    nodeToResolve.setType(resolvedType);
+                }
+            }
+        }
+    }
+
+    private TypeDefinitionBuilder resolveType(
+            final TypeAwareBuilder typeToResolve,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+        final TypeConstraints constraints = new TypeConstraints();
+
+        final TypeDefinitionBuilder targetType = getTypedefBuilder(
+                typeToResolve, modules, builder);
+        final 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 TypeDefinitionBuilder resolveTypeUnion(
+            final TypeAwareBuilder typeToResolve,
+            final UnknownType unknownType,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+        final TypeConstraints constraints = new TypeConstraints();
+
+        final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
+                unknownType, modules, builder);
+        final 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 TypeDefinitionBuilder getTypedefBuilder(
+            final TypeAwareBuilder nodeToResolve,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+
+        final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
+        if (nodeToResolveBase != null
+                && !(nodeToResolveBase instanceof UnknownType)) {
+            return (TypeDefinitionBuilder) nodeToResolve;
+        }
+
+        final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
+        final QName unknownTypeQName = unknownType.getQName();
+
+        // search for module which contains referenced typedef
+        final ModuleBuilder dependentModule = findDependentModule(modules,
+                builder, unknownTypeQName.getPrefix());
+        final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
+                dependentModule, unknownTypeQName.getLocalName());
+
+        final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
+                lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
+        final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
+                lookedUpBuilderCopy, modules, dependentModule);
+        return resolvedCopy;
+    }
+
+    private TypeDefinitionBuilder getUnionBuilder(
+            final TypeAwareBuilder nodeToResolve,
+            final UnknownType unknownType,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+
+        final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
+        if (baseTypeToResolve != null
+                && !(baseTypeToResolve instanceof UnknownType)) {
+            return (TypeDefinitionBuilder) nodeToResolve;
+        }
+
+        final QName unknownTypeQName = unknownType.getQName();
+        // search for module which contains referenced typedef
+        final ModuleBuilder dependentModule = findDependentModule(modules,
+                module, unknownTypeQName.getPrefix());
+        final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
+                dependentModule, unknownTypeQName.getLocalName());
+
+        final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
+                lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
+        final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
+                lookedUpBuilderCopy, modules, dependentModule);
+        return resolvedCopy;
+    }
+
+    private TypeDefinitionBuilder copyTypedefBuilder(
+            final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
+        if (old instanceof UnionTypeBuilder) {
+            final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
+            final UnionTypeBuilder newUnion = new UnionTypeBuilder();
+            for (TypeDefinition<?> td : oldUnion.getTypes()) {
+                newUnion.setType(td);
+            }
+            for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
+                newUnion.setType(copyTypedefBuilder(tdb, true));
+            }
+            return newUnion;
+        }
+
+        final QName oldName = old.getQName();
+        final QName newName = new QName(oldName.getNamespace(),
+                oldName.getRevision(), oldName.getPrefix(),
+                oldName.getLocalName());
+        final TypeDefinitionBuilder tdb = new TypedefBuilder(newName);
+
+        tdb.setRanges(old.getRanges());
+        tdb.setLengths(old.getLengths());
+        tdb.setPatterns(old.getPatterns());
+        tdb.setFractionDigits(old.getFractionDigits());
+
+        final 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(
+            final TypeDefinitionBuilder copy,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+
+        if (copy instanceof UnionTypeBuilder) {
+            final UnionTypeBuilder union = (UnionTypeBuilder) copy;
+            final List<TypeDefinition<?>> unionTypes = union.getTypes();
+            final List<UnknownType> toRemove = new ArrayList<UnknownType>();
+            for (TypeDefinition<?> td : unionTypes) {
+                if (td instanceof UnknownType) {
+                    final UnknownType unknownType = (UnknownType) td;
+                    final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
+                            union, unknownType, modules, builder);
+                    union.setType(resolvedType);
+                    toRemove.add(unknownType);
+                }
+            }
+            unionTypes.removeAll(toRemove);
+
+            return union;
+        }
+
+        final TypeDefinition<?> base = copy.getType();
+        final TypeDefinitionBuilder baseTdb = copy.getTypedef();
+        if (base != null && !(base instanceof UnknownType)) {
+            return copy;
+        } else if (base instanceof UnknownType) {
+            final UnknownType unknownType = (UnknownType) base;
+            final QName unknownTypeQName = unknownType.getQName();
+            final String unknownTypePrefix = unknownTypeQName.getPrefix();
+            final ModuleBuilder dependentModule = findDependentModule(modules,
+                    builder, unknownTypePrefix);
+            final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
+                    modules, dependentModule);
+            copy.setType(utBuilder);
+            return copy;
+        } else if (base == null && baseTdb != null) {
+            // make a copy of baseTypeDef and call again
+            final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
+                    baseTdb, true);
+            final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
+                    baseTdbCopy, modules, builder);
+            copy.setType(baseTdbCopyResolved);
+            return copy;
+        } else {
+            throw new IllegalStateException(
+                    "TypeDefinitionBuilder in unexpected state");
+        }
+    }
+
+    private TypeDefinitionBuilder findTypedefBuilder(
+            final QName unknownTypeQName,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+
+        // search for module which contains referenced typedef
+        final ModuleBuilder dependentModule = findDependentModule(modules,
+                builder, unknownTypeQName.getPrefix());
+
+        final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
+                dependentModule, unknownTypeQName.getLocalName());
+
+        return copyTypedefBuilder(lookedUpBuilder, true);
+    }
+
+    private TypeConstraints findConstraints(
+            final TypeAwareBuilder nodeToResolve,
+            final TypeConstraints constraints,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder) {
+
+        // union type cannot be restricted
+        if (nodeToResolve instanceof UnionTypeBuilder) {
+            return constraints;
+        }
+
+        // if referenced type is UnknownType again, search recursively with
+        // current constraints
+        final TypeDefinition<?> referencedType = nodeToResolve.getType();
+        List<RangeConstraint> ranges = Collections.emptyList();
+        List<LengthConstraint> lengths = Collections.emptyList();
+        List<PatternConstraint> patterns = Collections.emptyList();
+        Integer fractionDigits = null;
+        if (referencedType == null) {
+            final TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
+            ranges = tdb.getRanges();
+            constraints.addRanges(ranges);
+            lengths = tdb.getLengths();
+            constraints.addLengths(lengths);
+            patterns = tdb.getPatterns();
+            constraints.addPatterns(patterns);
+            fractionDigits = tdb.getFractionDigits();
+            constraints.setFractionDigits(fractionDigits);
+            return constraints;
+        } else if (referencedType instanceof ExtendedType) {
+            final ExtendedType ext = (ExtendedType) referencedType;
+            ranges = ext.getRanges();
+            constraints.addRanges(ranges);
+            lengths = ext.getLengths();
+            constraints.addLengths(lengths);
+            patterns = ext.getPatterns();
+            constraints.addPatterns(patterns);
+            fractionDigits = ext.getFractionDigits();
+            constraints.setFractionDigits(fractionDigits);
+            return findConstraints(
+                    findTypedefBuilder(ext.getQName(), modules, builder),
+                    constraints, modules, builder);
+        } else if (referencedType instanceof UnknownType) {
+            final UnknownType unknown = (UnknownType) referencedType;
+            ranges = unknown.getRangeStatements();
+            constraints.addRanges(ranges);
+            lengths = unknown.getLengthStatements();
+            constraints.addLengths(lengths);
+            patterns = unknown.getPatterns();
+            constraints.addPatterns(patterns);
+            fractionDigits = unknown.getFractionDigits();
+            constraints.setFractionDigits(fractionDigits);
+
+            String unknownTypePrefix = unknown.getQName().getPrefix();
+            if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
+                unknownTypePrefix = builder.getPrefix();
+            }
+            final ModuleBuilder dependentModule = findDependentModule(modules,
+                    builder, unknown.getQName().getPrefix());
+            final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
+                    unknown.getQName(), modules, builder);
+            return findConstraints(utBuilder, constraints, modules,
+                    dependentModule);
+        } else {
+            // 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 findTypedefBuilderByName(
+            final ModuleBuilder dependentModule, final String name) {
+        TypeDefinitionBuilder result = null;
+        final Set<TypeDefinitionBuilder> typedefs = dependentModule
+                .getModuleTypedefs();
+        for (TypeDefinitionBuilder td : typedefs) {
+            if (td.getQName().getLocalName().equals(name)) {
+                result = td;
+                break;
+            }
+        }
+        if (result == null) {
+            throw new YangParseException("Target module '"
+                    + dependentModule.getName()
+                    + "' does not contain typedef '" + name + "'.");
+        }
+        return result;
+    }
+
+    /**
+     * Pull restriction from referenced type and add them to given constraints
+     *
+     * @param referencedType
+     * @param constraints
+     */
+    private void mergeConstraints(final TypeDefinition<?> referencedType,
+            final 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());
+        }
+    }
+
+    /**
+     * Go through all augmentation definitions and resolve them. This method
+     * also finds referenced node and add child nodes to it.
+     *
+     * @param modules
+     *            all available modules
+     */
+    private void resolveAugments(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+        final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
+        final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
+                .entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
+                    .entrySet()) {
+                allModulesList.add(inner.getValue());
+                allModulesSet.add(inner.getValue());
+            }
+        }
+
+        for (int i = 0; i < allModulesList.size(); i++) {
+            final ModuleBuilder module = allModulesList.get(i);
+            // try to resolve augments in module
+            resolveAugment(modules, module);
+            // while all augments are not resolved
+            final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
+                    .iterator();
+            while (!(module.getAugmentsResolved() == module.getAddedAugments()
+                    .size())) {
+                ModuleBuilder nextModule = null;
+                // try resolve other module augments
+                try {
+                    nextModule = allModulesIterator.next();
+                    resolveAugment(modules, nextModule);
+                } catch (NoSuchElementException e) {
+                    throw new YangParseException(
+                            "Failed to resolve augments in module '"
+                                    + module.getName() + "'.", e);
+                }
+                // then try to resolve first module again
+                resolveAugment(modules, module);
+            }
+        }
+    }
+
+    private void resolveAugment(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
+            for (AugmentationSchemaBuilder augmentBuilder : module
+                    .getAddedAugments()) {
+                final SchemaPath augmentTargetSchemaPath = augmentBuilder
+                        .getTargetPath();
+                final List<QName> path = augmentTargetSchemaPath.getPath();
+
+                int i = 0;
+                final QName qname = path.get(i);
+                String prefix = qname.getPrefix();
+                if(prefix == null) {
+                    prefix = module.getPrefix();
+                }
+
+                DataSchemaNodeBuilder currentParent = null;
+                final ModuleBuilder dependentModule = findDependentModule(
+                        modules, module, prefix);
+                for (DataSchemaNodeBuilder child : dependentModule
+                        .getChildNodes()) {
+                    final QName childQName = child.getQName();
+                    if (childQName.getLocalName().equals(qname.getLocalName())) {
+                        currentParent = child;
+                        i++;
+                        break;
+                    }
+                }
+
+                for (; i < path.size(); i++) {
+                    final QName currentQName = path.get(i);
+                    DataSchemaNodeBuilder newParent = null;
+                    for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
+                            .getChildNodes()) {
+                        final QName childQName = child.getQName();
+                        if (childQName.getLocalName().equals(
+                                currentQName.getLocalName())) {
+                            newParent = child;
+                            break;
+                        }
+                    }
+                    if (newParent == null) {
+                        break; // node not found, quit search
+                    } else {
+                        currentParent = newParent;
+                    }
+                }
+
+                final QName currentQName = currentParent.getQName();
+                final QName lastAugmentPathElement = path.get(path.size() - 1);
+
+                if (currentQName.getLocalName().equals(
+                        lastAugmentPathElement.getLocalName())) {
+                    fillAugmentTarget(augmentBuilder,
+                            (ChildNodeBuilder) currentParent);
+                    ((AugmentationTargetBuilder) currentParent)
+                            .addAugmentation(augmentBuilder);
+                    module.augmentResolved();
+                }
+            }
+        }
+    }
+
+    /**
+     * Add all augment's child nodes to given target.
+     *
+     * @param augment
+     * @param target
+     */
+    private void fillAugmentTarget(final AugmentationSchemaBuilder augment,
+            final ChildNodeBuilder target) {
+        for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
+            builder.setAugmenting(true);
+            target.addChildNode(builder);
+        }
+    }
+
+    /**
+     * Go through identity statements defined in current module and resolve
+     * their 'base' statement if present.
+     *
+     * @param modules
+     *            all modules
+     * @param module
+     *            module being resolved
+     */
+    private void resolveIdentities(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        final Set<IdentitySchemaNodeBuilder> identities = module
+                .getAddedIdentities();
+        for (IdentitySchemaNodeBuilder identity : identities) {
+            final String baseIdentityName = identity.getBaseIdentityName();
+            if (baseIdentityName != null) {
+                String baseIdentityPrefix = null;
+                String baseIdentityLocalName = null;
+                if (baseIdentityName.contains(":")) {
+                    final String[] splitted = baseIdentityName.split(":");
+                    baseIdentityPrefix = splitted[0];
+                    baseIdentityLocalName = splitted[1];
+                } else {
+                    baseIdentityPrefix = module.getPrefix();
+                    baseIdentityLocalName = baseIdentityName;
+                }
+                final ModuleBuilder dependentModule = findDependentModule(
+                        modules, module, baseIdentityPrefix);
+
+                final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
+                        .getAddedIdentities();
+                for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
+                    if (idBuilder.getQName().getLocalName()
+                            .equals(baseIdentityLocalName)) {
+                        identity.setBaseIdentity(idBuilder);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Go through uses statements defined in current module and resolve their
+     * refine statements.
+     *
+     * @param modules
+     *            all modules
+     * @param module
+     *            module being resolved
+     */
+    private void resolveUses(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        final Map<List<String>, UsesNodeBuilder> moduleUses = module
+                .getAddedUsesNodes();
+        for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
+                .entrySet()) {
+            final List<String> key = entry.getKey();
+            final UsesNodeBuilder usesNode = entry.getValue();
+
+            final String groupingName = key.get(key.size() - 1);
+
+            final List<RefineHolder> refines = usesNode.getRefines();
+            for (RefineHolder refine : refines) {
+                final Refine refineType = refine.getType();
+                // refine statements
+                final String defaultStr = refine.getDefaultStr();
+                final Boolean mandatory = refine.isMandatory();
+                final MustDefinition must = refine.getMust();
+                final Boolean presence = refine.isPresence();
+                final Integer min = refine.getMinElements();
+                final Integer max = refine.getMaxElements();
+
+                switch (refineType) {
+                case LEAF:
+                    final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) getRefineTargetBuilder(
+                            groupingName, refine, modules, module);
+                    if (defaultStr != null && !("".equals(defaultStr))) {
+                        leaf.setDefaultStr(defaultStr);
+                    }
+                    if (mandatory != null) {
+                        leaf.getConstraints().setMandatory(mandatory);
+                    }
+                    if (must != null) {
+                        leaf.getConstraints().addMustDefinition(must);
+                    }
+                    usesNode.addRefineNode(leaf);
+                    break;
+                case CONTAINER:
+                    final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) getRefineTargetBuilder(
+                            groupingName, refine, modules, module);
+                    if (presence != null) {
+                        container.setPresence(presence);
+                    }
+                    if (must != null) {
+                        container.getConstraints().addMustDefinition(must);
+                    }
+                    usesNode.addRefineNode(container);
+                    break;
+                case LIST:
+                    final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) getRefineTargetBuilder(
+                            groupingName, refine, modules, module);
+                    if (must != null) {
+                        list.getConstraints().addMustDefinition(must);
+                    }
+                    if (min != null) {
+                        list.getConstraints().setMinElements(min);
+                    }
+                    if (max != null) {
+                        list.getConstraints().setMaxElements(max);
+                    }
+                    break;
+                case LEAF_LIST:
+                    final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
+                            groupingName, refine, modules, module);
+                    if (must != null) {
+                        leafList.getConstraints().addMustDefinition(must);
+                    }
+                    if (min != null) {
+                        leafList.getConstraints().setMinElements(min);
+                    }
+                    if (max != null) {
+                        leafList.getConstraints().setMaxElements(max);
+                    }
+                    break;
+                case CHOICE:
+                    final ChoiceBuilder choice = (ChoiceBuilder) getRefineTargetBuilder(
+                            groupingName, refine, modules, module);
+                    if (defaultStr != null) {
+                        choice.setDefaultCase(defaultStr);
+                    }
+                    if (mandatory != null) {
+                        choice.getConstraints().setMandatory(mandatory);
+                    }
+                    break;
+                case ANYXML:
+                    final AnyXmlBuilder anyXml = (AnyXmlBuilder) getRefineTargetBuilder(
+                            groupingName, refine, modules, module);
+                    if (mandatory != null) {
+                        anyXml.getConstraints().setMandatory(mandatory);
+                    }
+                    if (must != null) {
+                        anyXml.getConstraints().addMustDefinition(must);
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Find original builder of refine node and return copy of this builder.
+     *
+     * @param groupingPath
+     *            path to grouping which contains node to refine
+     * @param refine
+     *            refine object containing informations about refine
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @return copy of Builder object of node to be refined if it is present in
+     *         grouping, null otherwise
+     */
+    private Builder getRefineTargetBuilder(final String groupingPath,
+            final RefineHolder refine,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        Builder result = null;
+        final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
+                refine.getName(), modules, module);
+        if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
+            result = ParserUtils
+                    .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
+            result = ParserUtils
+                    .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
+            result = ParserUtils
+                    .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
+            result = ParserUtils
+                    .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof ChoiceBuilder) {
+            result = ParserUtils
+                    .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
+            result = ParserUtils
+                    .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
+        } else {
+            throw new YangParseException("Target '" + refine.getName()
+                    + "' can not be refined");
+        }
+        return result;
+    }
+
+    /**
+     * Find builder of refine node.
+     *
+     * @param groupingPath
+     *            path to grouping which contains node to refine
+     * @param refineNodeName
+     *            name of node to be refined
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @return Builder object of refine node if it is present in grouping, null
+     *         otherwise
+     */
+    private Builder findRefineTargetBuilder(final String groupingPath,
+            final String refineNodeName,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
+        final List<String> builderPath = new ArrayList<String>();
+        String prefix = null;
+        for (QName qname : path.getPath()) {
+            builderPath.add(qname.getLocalName());
+            prefix = qname.getPrefix();
+        }
+        if (prefix == null) {
+            prefix = module.getPrefix();
+        }
+
+        final ModuleBuilder dependentModule = findDependentModule(modules,
+                module, prefix);
+        builderPath.add(0, "grouping");
+        builderPath.add(0, dependentModule.getName());
+        final GroupingBuilder builder = (GroupingBuilder) dependentModule
+                .getNode(builderPath);
+
+        return builder.getChildNode(refineNodeName);
+    }
+
+    private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
+        QName result = null;
+        String baseString = idref.getBaseString();
+        if(baseString.contains(":")) {
+            String[] splittedBase = baseString.split(":");
+            if(splittedBase.length > 2) {
+                throw new YangParseException("Failed to parse identity base: "+ baseString);
+            }
+            String prefix = splittedBase[0];
+            String name = splittedBase[1];
+            ModuleBuilder dependentModule = findDependentModule(modules, module, prefix);
+            result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
+        } else {
+            result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
+        }
+        return result;
+    }
+
+    /**
+     * Find dependent module based on given prefix
+     *
+     * @param modules
+     *            all available modules
+     * @param module
+     *            current module
+     * @param prefix
+     *            target module prefix
+     * @return
+     */
+    private ModuleBuilder findDependentModule(
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final String prefix) {
+        ModuleBuilder dependentModule = null;
+        Date dependentModuleRevision = null;
+
+        if (prefix.equals(module.getPrefix())) {
+            dependentModule = module;
+        } else {
+            final ModuleImport dependentModuleImport = getModuleImport(module,
+                    prefix);
+            if (dependentModuleImport == null) {
+                throw new YangParseException("No import found with prefix '"
+                        + prefix + "' in module " + module.getName() + "'.");
+            }
+            final String dependentModuleName = dependentModuleImport
+                    .getModuleName();
+            dependentModuleRevision = dependentModuleImport.getRevision();
+
+            final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
+                    .get(dependentModuleName);
+            if (moduleBuildersByRevision == null) {
+                throw new YangParseException(
+                        "Failed to find dependent module '"
+                                + dependentModuleName + "' needed by module '"
+                                + module.getName() + "'.");
+            }
+            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;
+    }
+
+    /**
+     * Get module import referenced by given prefix.
+     *
+     * @param builder
+     *            module to search
+     * @param prefix
+     *            prefix associated with import
+     * @return ModuleImport based on given prefix
+     */
+    private ModuleImport getModuleImport(final ModuleBuilder builder,
+            final String prefix) {
+        ModuleImport moduleImport = null;
+        for (ModuleImport mi : builder.getModuleImports()) {
+            if (mi.getPrefix().equals(prefix)) {
+                moduleImport = mi;
+                break;
+            }
+        }
+        return moduleImport;
+    }
+
+    private static class SchemaContextImpl implements SchemaContext {
+        private final Set<Module> modules;
+
+        private SchemaContextImpl(final Set<Module> modules) {
+            this.modules = modules;
+        }
+
+        @Override
+        public Set<DataSchemaNode> getDataDefinitions() {
+            final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
+            for (Module m : modules) {
+                dataDefs.addAll(m.getChildNodes());
+            }
+            return dataDefs;
+        }
+
+        @Override
+        public Set<Module> getModules() {
+            return modules;
+        }
+
+        @Override
+        public Set<NotificationDefinition> getNotifications() {
+            final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
+            for (Module m : modules) {
+                notifications.addAll(m.getNotifications());
+            }
+            return notifications;
+        }
+
+        @Override
+        public Set<RpcDefinition> getOperations() {
+            final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
+            for (Module m : modules) {
+                rpcs.addAll(m.getRpcs());
+            }
+            return rpcs;
+        }
+
+        @Override
+        public Set<ExtensionDefinition> getExtensions() {
+            final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
+            for (Module m : modules) {
+                extensions.addAll(m.getExtensionSchemaNodes());
+            }
+            return extensions;
+        }
+
+        @Override
+        public Module findModuleByName(final String name, final Date revision) {
+            if ((name != null) && (revision != null)) {
+                for (final Module module : modules) {
+                    if (module.getName().equals(name)
+                            && module.getRevision().equals(revision)) {
+                        return module;
+                    }
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public Module findModuleByNamespace(final URI namespace) {
+            if (namespace != null) {
+                for (final Module module : modules) {
+                    if (module.getNamespace().equals(namespace)) {
+                        return module;
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+}