Merge "Parents pom distribution"
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / parser / impl / YangParserImpl.java
index 7c2aa6692b8df09ec97a9e70f92a65726613e1b4..94437170f4be3c8ef91ae774debd26cb1d4f8963 100644 (file)
@@ -12,7 +12,6 @@ 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;
@@ -20,9 +19,9 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.TreeMap;
@@ -34,22 +33,14 @@ 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.util.ExtendedType;
@@ -58,9 +49,10 @@ import org.opendaylight.controller.yang.model.util.UnknownType;
 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.Builder;
-import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
@@ -73,11 +65,11 @@ import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBu
 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.controller.yang.parser.builder.impl.TypedefBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
-import org.opendaylight.controller.yang.parser.util.ModuleDependencySort.ModuleSimple;
 import org.opendaylight.controller.yang.parser.util.ParserUtils;
 import org.opendaylight.controller.yang.parser.util.RefineHolder;
 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
@@ -86,35 +78,80 @@ import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class YangParserImpl implements YangModelParser {
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public final class YangParserImpl implements YangModelParser {
 
     private static final Logger logger = LoggerFactory
             .getLogger(YangParserImpl.class);
 
     @Override
-    public Set<Module> parseYangModels(final List<File> yangFiles) {
+    public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
         if (yangFiles != null) {
-            final List<InputStream> inputStreams = new ArrayList<InputStream>();
+            final Map<InputStream, File> inputStreams = Maps.newHashMap();
 
             for (final File yangFile : yangFiles) {
                 try {
-                    inputStreams.add(new FileInputStream(yangFile));
+                    inputStreams.put(new FileInputStream(yangFile), yangFile);
                 } catch (FileNotFoundException e) {
                     logger.warn("Exception while reading yang file: "
                             + yangFile.getName(), e);
                 }
             }
-            final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(inputStreams);
-            return build(modules);
+
+            Map<ModuleBuilder, InputStream> builderToStreamMap = Maps
+                    .newHashMap();
+
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
+                    Lists.newArrayList(inputStreams.keySet()),
+                    builderToStreamMap);
+            // return new LinkedHashSet<Module>(build(modules).values());
+
+            Map<File, Module> retVal = Maps.newLinkedHashMap();
+            Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
+
+            for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap
+                    .entrySet()) {
+                retVal.put(inputStreams.get(builderToStreamMap
+                        .get(builderToModule.getKey())), builderToModule
+                        .getValue());
+            }
+
+            return retVal;
         }
-        return Collections.emptySet();
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Set<Module> parseYangModels(final List<File> yangFiles) {
+        return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
     }
 
     @Override
     public Set<Module> parseYangModelsFromStreams(
             final List<InputStream> yangModelStreams) {
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
-        return build(modules);
+        return Sets.newHashSet(parseYangModelsFromStreamsMapped(
+                yangModelStreams).values());
+    }
+
+    @Override
+    public Map<InputStream, Module> parseYangModelsFromStreamsMapped(
+            final List<InputStream> yangModelStreams) {
+        Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
+
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
+                yangModelStreams, builderToStreamMap);
+        Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
+        Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
+
+        for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap
+                .entrySet()) {
+            retVal.put(builderToStreamMap.get(builderToModule.getKey()),
+                    builderToModule.getValue());
+        }
+        return retVal;
     }
 
     @Override
@@ -122,11 +159,11 @@ public class YangParserImpl implements YangModelParser {
         return new SchemaContextImpl(modules);
     }
 
-    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
-            final List<InputStream> yangFileStreams) {
-        final Map<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
+    private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
+            Map<ModuleBuilder, InputStream> streamToBuilderMap) {
+
         final ParseTreeWalker walker = new ParseTreeWalker();
-        final List<ParseTree> trees = parseStreams(yangFileStreams);
+        final List<ParseTree> trees = parseStreams(inputStreams);
         final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
 
         // validate yang
@@ -136,28 +173,30 @@ public class YangParserImpl implements YangModelParser {
         for (int i = 0; i < trees.size(); i++) {
             yangModelParser = new YangParserListenerImpl();
             walker.walk(yangModelParser, trees.get(i));
-            builders[i] = yangModelParser.getModuleBuilder();
+            ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
+
+            // We expect the order of trees and streams has to be the same
+            streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
+            builders[i] = moduleBuilder;
         }
+        return builders;
+    }
+
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
+            final List<InputStream> yangFileStreams,
+            Map<ModuleBuilder, InputStream> streamToBuilderMap) {
+
+        final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams,
+                streamToBuilderMap);
+
+        // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
+        // of items stored in map.
+        final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
 
         // module dependency graph sorted
-        List<ModuleSimple> sorted = new ModuleDependencySort(builders).sort();
-
-        // TODO FIX THIS ASAP!
-        // FIXME this is just temp workaround the ModuleDependencySort MUST
-        // RETURN ordered List
-        // of SORTED and DEPENDECNY RESOLVED MODULE BUILDERS!!!!!!
-        final List<ModuleBuilder> orderedBuilders = new ArrayList<ModuleBuilder>();
-        for (final ModuleSimple ms : sorted) {
-            for (int i = 0; i < builders.length; ++i) {
-                if (ms.getName().equals(builders[i].getName())
-                        && ms.getRevision().equals(builders[i].getRevision())) {
-                    orderedBuilders.add(builders[i]);
-                }
-            }
-        }
-        // FIXME END OF WORKAROUND
+        List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
 
-        for (ModuleBuilder builder : orderedBuilders) {
+        for (ModuleBuilder builder : sorted) {
             final String builderName = builder.getName();
             Date builderRevision = builder.getRevision();
             if (builderRevision == null) {
@@ -189,6 +228,7 @@ public class YangParserImpl implements YangModelParser {
             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);
@@ -196,7 +236,7 @@ public class YangParserImpl implements YangModelParser {
         return result;
     }
 
-    private Set<Module> build(
+    private Map<ModuleBuilder, Module> build(
             final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
         // fix unresolved nodes
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
@@ -210,7 +250,10 @@ public class YangParserImpl implements YangModelParser {
         resolveAugments(modules);
 
         // build
-        final Set<Module> result = new LinkedHashSet<Module>();
+        // LinkedHashMap MUST be used otherwise the values will not maintain
+        // order!
+        // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
+        final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
                 .entrySet()) {
             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
@@ -219,7 +262,7 @@ public class YangParserImpl implements YangModelParser {
                 final ModuleBuilder moduleBuilder = childEntry.getValue();
                 final Module module = moduleBuilder.build();
                 modulesByRevision.put(childEntry.getKey(), module);
-                result.add(module);
+                result.put(moduleBuilder, module);
             }
         }
         return result;
@@ -230,7 +273,7 @@ public class YangParserImpl implements YangModelParser {
             final ModuleBuilder builder) {
         resolveDirtyNodes(modules, builder);
         resolveIdentities(modules, builder);
-        resolveUses(modules, builder);
+        resolveUsesRefines(modules, builder);
         resolveUnknownNodes(modules, builder);
     }
 
@@ -251,237 +294,116 @@ public class YangParserImpl implements YangModelParser {
         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);
+                    // special handling for union types
+                    resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules,
+                            module);
                 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
+                    // special handling for identityref types
                     IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
                             .getTypedef();
                     nodeToResolve.setType(new IdentityrefType(findFullQName(
                             modules, module, idref), idref.getPath()));
                 } else {
-                    final TypeDefinitionBuilder resolvedType = resolveType(
-                            nodeToResolve, modules, module);
-                    nodeToResolve.setType(resolvedType);
+                    resolveType(nodeToResolve, modules, module);
                 }
             }
         }
     }
 
-    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,
+    private void resolveType(final TypeAwareBuilder nodeToResolve,
             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
+        TypeDefinitionBuilder resolvedType = null;
+        final int line = nodeToResolve.getLine();
+        final TypeDefinition<?> typedefType = nodeToResolve.getType();
+        final QName unknownTypeQName = typedefType.getBaseType().getQName();
         final ModuleBuilder dependentModule = findDependentModule(modules,
-                builder, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
-        final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
-                dependentModule, unknownTypeQName.getLocalName(),
-                builder.getName(), nodeToResolve.getLine());
-
-        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(), nodeToResolve.getLine());
-        final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
-                dependentModule, unknownTypeQName.getLocalName(),
-                module.getName(), nodeToResolve.getLine());
-
-        final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
-                lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
-        final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
-                lookedUpBuilderCopy, modules, dependentModule);
-        return resolvedCopy;
-    }
+                builder, unknownTypeQName.getPrefix(), line);
 
-    private TypeDefinitionBuilder copyTypedefBuilder(
-            final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
-        if (old instanceof UnionTypeBuilder) {
-            final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
-            final UnionTypeBuilder newUnion = new UnionTypeBuilder(
-                    oldUnion.getActualPath(), oldUnion.getNamespace(),
-                    oldUnion.getRevision(), old.getLine());
-            for (TypeDefinition<?> td : oldUnion.getTypes()) {
-                newUnion.setType(td);
-            }
-            for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
-                newUnion.setType(copyTypedefBuilder(tdb, true));
-            }
-            return newUnion;
-        }
+        final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(
+                nodeToResolve.getPath(), dependentModule,
+                unknownTypeQName.getLocalName(), builder.getName(), line);
 
-        final QName oldName = old.getQName();
-        final QName newName = new QName(oldName.getNamespace(),
-                oldName.getRevision(), oldName.getPrefix(),
-                oldName.getLocalName());
-        final TypeDefinitionBuilder tdb = new TypedefBuilder(newName,
-                old.getLine());
-
-        tdb.setRanges(old.getRanges());
-        tdb.setLengths(old.getLengths());
-        tdb.setPatterns(old.getPatterns());
-        tdb.setFractionDigits(old.getFractionDigits());
-        tdb.setPath(old.getPath());
-
-        final TypeDefinition<?> oldType = old.getType();
-        if (oldType == null) {
-            tdb.setType(old.getTypedef());
+        if (typedefType instanceof ExtendedType) {
+            final ExtendedType extType = (ExtendedType) typedefType;
+            final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(
+                    nodeToResolve, targetTypeBuilder, extType, modules, builder);
+            resolvedType = newType;
         } 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());
+            resolvedType = targetTypeBuilder;
         }
-        return tdb;
+        nodeToResolve.setTypedef(resolvedType);
     }
 
-    private TypeDefinitionBuilder resolveCopiedBuilder(
-            final TypeDefinitionBuilder copy,
+    private void resolveTypeUnion(final UnionTypeBuilder union,
             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);
+        final List<TypeDefinition<?>> unionTypes = union.getTypes();
+        final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
+        for (TypeDefinition<?> unionType : unionTypes) {
+            if (unionType instanceof UnknownType) {
+                final UnknownType ut = (UnknownType) unionType;
+                final ModuleBuilder dependentModule = findDependentModule(
+                        modules, builder, ut.getQName().getPrefix(),
+                        union.getLine());
+                final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(
+                        union.getPath(), dependentModule, ut.getQName()
+                                .getLocalName(), builder.getName(),
+                        union.getLine());
+                union.setTypedef(resolvedType);
+                toRemove.add(ut);
+            } else if (unionType instanceof ExtendedType) {
+                final ExtendedType extType = (ExtendedType) unionType;
+                TypeDefinition<?> extTypeBase = extType.getBaseType();
+                if (extTypeBase instanceof UnknownType) {
+                    final UnknownType ut = (UnknownType) extTypeBase;
+                    final ModuleBuilder dependentModule = findDependentModule(
+                            modules, builder, ut.getQName().getPrefix(),
+                            union.getLine());
+                    final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(
+                            union.getPath(), dependentModule, ut.getQName()
+                                    .getLocalName(), builder.getName(),
+                            union.getLine());
+
+                    final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(
+                            targetTypeBuilder, targetTypeBuilder, extType,
+                            modules, builder);
+
+                    union.setTypedef(newType);
+                    toRemove.add(extType);
                 }
             }
-            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, copy.getLine());
-            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("Failed to resolve type "
-                    + copy.getQName().getLocalName());
         }
+        unionTypes.removeAll(toRemove);
     }
 
-    private TypeDefinitionBuilder findTypedefBuilder(
-            final QName unknownTypeQName,
+    private TypeDefinitionBuilder extendedTypeWithNewBaseType(
+            final TypeAwareBuilder nodeToResolve,
+            final TypeDefinitionBuilder newBaseType,
+            final ExtendedType oldExtendedType,
             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            final ModuleBuilder builder, int line) {
-        // search for module which contains referenced typedef
-        final ModuleBuilder dependentModule = findDependentModule(modules,
-                builder, unknownTypeQName.getPrefix(), line);
-        final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
-                dependentModule, unknownTypeQName.getLocalName(),
-                builder.getName(), line);
-        return copyTypedefBuilder(lookedUpBuilder, true);
+            final ModuleBuilder builder) {
+        final TypeConstraints constraints = findConstraints(nodeToResolve,
+                new TypeConstraints(), modules, builder);
+        final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(
+                oldExtendedType.getQName(), nodeToResolve.getLine());
+        newType.setTypedef(newBaseType);
+        newType.setPath(oldExtendedType.getPath());
+        newType.setDescription(oldExtendedType.getDescription());
+        newType.setReference(oldExtendedType.getReference());
+        newType.setStatus(oldExtendedType.getStatus());
+        newType.setLengths(constraints.getLength());
+        newType.setPatterns(constraints.getPatterns());
+        newType.setRanges(constraints.getRange());
+        newType.setFractionDigits(constraints.getFractionDigits());
+        newType.setUnits(oldExtendedType.getUnits());
+        newType.setDefaultValue(oldExtendedType.getDefaultValue());
+        newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
+        return newType;
     }
 
     private TypeConstraints findConstraints(
@@ -489,101 +411,134 @@ public class YangParserImpl implements YangModelParser {
             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 = nodeToResolve.getTypedef();
-            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,
-                            nodeToResolve.getLine()), 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(),
-                    nodeToResolve.getLine());
-            final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
-                    unknown.getQName(), modules, builder,
-                    nodeToResolve.getLine());
-            return findConstraints(utBuilder, constraints, modules,
-                    dependentModule);
+        if (nodeToResolve instanceof TypeDefinitionBuilder) {
+            TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
+            constraints.addFractionDigits(typedefToResolve.getFractionDigits());
+            constraints.addLengths(typedefToResolve.getLengths());
+            constraints.addPatterns(typedefToResolve.getPatterns());
+            constraints.addRanges(typedefToResolve.getRanges());
+        }
+
+        TypeDefinition<?> type = nodeToResolve.getType();
+        if (type == null) {
+            return findConstraints(nodeToResolve.getTypedef(), constraints,
+                    modules, builder);
         } else {
-            // HANDLE BASE YANG TYPE
-            mergeConstraints(referencedType, constraints);
-            return constraints;
+            if (type instanceof UnknownType) {
+                ModuleBuilder dependentModule = findDependentModule(modules,
+                        builder, type.getQName().getPrefix(),
+                        nodeToResolve.getLine());
+                TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(
+                        nodeToResolve.getPath(), dependentModule, type
+                                .getQName().getLocalName(), builder.getName(),
+                        nodeToResolve.getLine());
+                return findConstraints(tdb, constraints, modules,
+                        dependentModule);
+            } else if (type instanceof ExtendedType) {
+                ExtendedType extType = (ExtendedType) type;
+                constraints.addFractionDigits(extType.getFractionDigits());
+                constraints.addLengths(extType.getLengths());
+                constraints.addPatterns(extType.getPatterns());
+                constraints.addRanges(extType.getRanges());
+
+                TypeDefinition<?> base = extType.getBaseType();
+                if (base instanceof UnknownType) {
+                    ModuleBuilder dependentModule = findDependentModule(
+                            modules, builder, base.getQName().getPrefix(),
+                            nodeToResolve.getLine());
+                    TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(
+                            nodeToResolve.getPath(), dependentModule, base
+                                    .getQName().getLocalName(),
+                            builder.getName(), nodeToResolve.getLine());
+                    return findConstraints(tdb, constraints, modules,
+                            dependentModule);
+                } else {
+                    // it has to be base yang type
+                    mergeConstraints(type, constraints);
+                    return constraints;
+                }
+            } else {
+                // it is base yang type
+                mergeConstraints(type, constraints);
+                return constraints;
+            }
         }
     }
 
     /**
-     * Go through all typedef statements from given module and search for one
-     * with given name
+     * Search for type definition builder by name.
      *
-     * @param typedefs
-     *            typedef statements to search
-     * @param name
-     *            name of searched typedef
-     * @return typedef with name equals to given name
+     * @param dirtyNodeSchemaPath
+     *            schema path of node which contains unresolved type
+     * @param dependentModule
+     *            module which should contains referenced type
+     * @param typeName
+     *            name of type definition
+     * @param currentModuleName
+     *            name of current module
+     * @param line
+     *            current line in yang model
+     * @return
      */
-    private TypeDefinitionBuilder findTypedefBuilderByName(
-            final ModuleBuilder dependentModule, final String name,
+    private TypeDefinitionBuilder findTypeDefinitionBuilder(
+            SchemaPath dirtyNodeSchemaPath,
+            final ModuleBuilder dependentModule, final String typeName,
             final String currentModuleName, final int line) {
+        final List<QName> path = dirtyNodeSchemaPath.getPath();
         TypeDefinitionBuilder result = null;
-        final Set<TypeDefinitionBuilder> typedefs = dependentModule
+
+        Set<TypeDefinitionBuilder> typedefs = dependentModule
                 .getModuleTypedefs();
-        for (TypeDefinitionBuilder td : typedefs) {
-            if (td.getQName().getLocalName().equals(name)) {
-                result = td;
-                break;
+        result = findTdb(typedefs, typeName);
+
+        if (result == null) {
+            Builder currentNode = null;
+            final List<String> currentPath = new ArrayList<String>();
+            currentPath.add(dependentModule.getName());
+
+            for (int i = 0; i < path.size(); i++) {
+                QName qname = path.get(i);
+                currentPath.add(qname.getLocalName());
+                currentNode = dependentModule.getModuleNode(currentPath);
+
+                if (currentNode instanceof RpcDefinitionBuilder) {
+                    typedefs = ((RpcDefinitionBuilder) currentNode)
+                            .getTypeDefinitions();
+                } else if (currentNode instanceof DataNodeContainerBuilder) {
+                    typedefs = ((DataNodeContainerBuilder) currentNode)
+                            .getTypeDefinitions();
+                } else {
+                    typedefs = Collections.emptySet();
+                }
+
+                result = findTdb(typedefs, typeName);
+                if (result != null) {
+                    break;
+                }
             }
         }
-        if (result == null) {
-            throw new YangParseException(currentModuleName, line,
-                    "Target module '" + dependentModule.getName()
-                            + "' does not contain typedef '" + name + "'.");
+
+        if (result != null) {
+            return result;
         }
-        return result;
+        throw new YangParseException(currentModuleName, line,
+                "Referenced type '" + typeName + "' not found.");
+    }
+
+    private TypeDefinitionBuilder findTdb(Set<TypeDefinitionBuilder> types,
+            String name) {
+        for (TypeDefinitionBuilder td : types) {
+            if (td.getQName().getLocalName().equals(name)) {
+                return td;
+            }
+        }
+        return null;
     }
 
     /**
@@ -599,7 +554,7 @@ public class YangParserImpl implements YangModelParser {
             constraints.addRanges(((DecimalTypeDefinition) referencedType)
                     .getRangeStatements());
             constraints
-                    .setFractionDigits(((DecimalTypeDefinition) referencedType)
+                    .addFractionDigits(((DecimalTypeDefinition) referencedType)
                             .getFractionDigits());
         } else if (referencedType instanceof IntegerTypeDefinition) {
             constraints.addRanges(((IntegerTypeDefinition) referencedType)
@@ -616,8 +571,8 @@ public class YangParserImpl implements YangModelParser {
     }
 
     /**
-     * Go through all augmentation definitions and resolve them. This method
-     * also finds referenced node and add child nodes to it.
+     * Go through all augment definitions and resolve them. This method also
+     * finds augment target node and add child nodes to it.
      *
      * @param modules
      *            all available modules
@@ -642,7 +597,7 @@ public class YangParserImpl implements YangModelParser {
             // while all augments are not resolved
             final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
                     .iterator();
-            while (!(module.getAugmentsResolved() == module.getAddedAugments()
+            while (!(module.getAugmentsResolved() == module.getAugments()
                     .size())) {
                 ModuleBuilder nextModule = null;
                 // try resolve other module augments
@@ -670,17 +625,16 @@ public class YangParserImpl implements YangModelParser {
     private void resolveAugment(
             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module) {
-        if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
+        if (module.getAugmentsResolved() < module.getAugments().size()) {
             for (AugmentationSchemaBuilder augmentBuilder : module
-                    .getAddedAugments()) {
+                    .getAugments()) {
 
                 if (!augmentBuilder.isResolved()) {
                     final SchemaPath augmentTargetSchemaPath = augmentBuilder
                             .getTargetPath();
                     final List<QName> path = augmentTargetSchemaPath.getPath();
 
-                    int i = 0;
-                    final QName qname = path.get(i);
+                    final QName qname = path.get(0);
                     String prefix = qname.getPrefix();
                     if (prefix == null) {
                         prefix = module.getPrefix();
@@ -695,15 +649,18 @@ public class YangParserImpl implements YangModelParser {
                         if (childQName.getLocalName().equals(
                                 qname.getLocalName())) {
                             currentParent = child;
-                            i++;
                             break;
                         }
                     }
 
-                    for (; i < path.size(); i++) {
+                    if (currentParent == null) {
+                        continue;
+                    }
+
+                    for (int i = 1; i < path.size(); i++) {
                         final QName currentQName = path.get(i);
                         DataSchemaNodeBuilder newParent = null;
-                        for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
+                        for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) currentParent)
                                 .getChildNodes()) {
                             final QName childQName = child.getQName();
                             if (childQName.getLocalName().equals(
@@ -724,8 +681,14 @@ public class YangParserImpl implements YangModelParser {
                             .get(path.size() - 1);
                     if (currentQName.getLocalName().equals(
                             lastAugmentPathElement.getLocalName())) {
-                        ParserUtils.fillAugmentTarget(augmentBuilder,
-                                (ChildNodeBuilder) currentParent);
+
+                        if (currentParent instanceof ChoiceBuilder) {
+                            ParserUtils.fillAugmentTarget(augmentBuilder,
+                                    (ChoiceBuilder) currentParent);
+                        } else {
+                            ParserUtils.fillAugmentTarget(augmentBuilder,
+                                    (DataNodeContainerBuilder) currentParent);
+                        }
                         ((AugmentationTargetBuilder) currentParent)
                                 .addAugmentation(augmentBuilder);
                         SchemaPath oldPath = currentParent.getPath();
@@ -753,7 +716,7 @@ public class YangParserImpl implements YangModelParser {
             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module) {
         final Set<IdentitySchemaNodeBuilder> identities = module
-                .getAddedIdentities();
+                .getIdentities();
         for (IdentitySchemaNodeBuilder identity : identities) {
             final String baseIdentityName = identity.getBaseIdentityName();
             if (baseIdentityName != null) {
@@ -771,7 +734,7 @@ public class YangParserImpl implements YangModelParser {
                         modules, module, baseIdentityPrefix, identity.getLine());
 
                 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
-                        .getAddedIdentities();
+                        .getIdentities();
                 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
                     if (idBuilder.getQName().getLocalName()
                             .equals(baseIdentityLocalName)) {
@@ -791,128 +754,140 @@ public class YangParserImpl implements YangModelParser {
      * @param module
      *            module being resolved
      */
-    private void resolveUses(
+    private void resolveUsesRefines(
             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module) {
         final Map<List<String>, UsesNodeBuilder> moduleUses = module
-                .getAddedUsesNodes();
+                .getUsesNodes();
         for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
                 .entrySet()) {
-            final List<String> key = entry.getKey();
             final UsesNodeBuilder usesNode = entry.getValue();
+            final int line = usesNode.getLine();
 
-            final String groupingName = key.get(key.size() - 1);
+            GroupingBuilder targetGrouping = getTargetGrouping(usesNode, modules, module);
+            usesNode.setGroupingPath(targetGrouping.getPath());
 
             for (RefineHolder refine : usesNode.getRefines()) {
-                // 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();
-                final List<UnknownSchemaNodeBuilder> unknownNodes = refine
-                        .getUnknownNodes();
-
-                Builder refineTarget = getRefineTargetBuilder(groupingName,
-                        refine, modules, module);
+                SchemaNodeBuilder refineTarget = getRefineNodeBuilderCopy(
+                        targetGrouping, refine, modules, module);
+                ParserUtils.checkRefine(refineTarget, refine);
+                ParserUtils.refineDefault(refineTarget, refine, line);
                 if (refineTarget instanceof LeafSchemaNodeBuilder) {
                     final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
-                    if (defaultStr != null && !("".equals(defaultStr))) {
-                        leaf.setDefaultStr(defaultStr);
-                    }
-                    if (mandatory != null) {
-                        leaf.getConstraints().setMandatory(mandatory);
-                    }
-                    if (must != null) {
-                        leaf.getConstraints().addMustDefinition(must);
-                    }
-                    if (unknownNodes != null) {
-                        for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
-                            leaf.addUnknownSchemaNode(unknown);
-                        }
-                    }
+                    ParserUtils.refineLeaf(leaf, refine, line);
                     usesNode.addRefineNode(leaf);
                 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
                     final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
-                    if (presence != null) {
-                        container.setPresence(presence);
-                    }
-                    if (must != null) {
-                        container.getConstraints().addMustDefinition(must);
-                    }
-                    if (unknownNodes != null) {
-                        for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
-                            container.addUnknownSchemaNode(unknown);
-                        }
-                    }
+                    ParserUtils.refineContainer(container, refine, line);
                     usesNode.addRefineNode(container);
                 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
                     final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
-                    if (must != null) {
-                        list.getConstraints().addMustDefinition(must);
-                    }
-                    if (min != null) {
-                        list.getConstraints().setMinElements(min);
-                    }
-                    if (max != null) {
-                        list.getConstraints().setMaxElements(max);
-                    }
-                    if (unknownNodes != null) {
-                        for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
-                            list.addUnknownSchemaNode(unknown);
-                        }
-                    }
+                    ParserUtils.refineList(list, refine, line);
+                    usesNode.addRefineNode(list);
                 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
-                    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);
-                    }
-                    if (unknownNodes != null) {
-                        for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
-                            leafList.addUnknownSchemaNode(unknown);
-                        }
-                    }
+                    final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) refineTarget;
+                    ParserUtils.refineLeafList(leafList, refine, line);
+                    usesNode.addRefineNode(leafList);
                 } else if (refineTarget instanceof ChoiceBuilder) {
                     final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
-                    if (defaultStr != null) {
-                        choice.setDefaultCase(defaultStr);
-                    }
-                    if (mandatory != null) {
-                        choice.getConstraints().setMandatory(mandatory);
-                    }
-                    if (unknownNodes != null) {
-                        for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
-                            choice.addUnknownSchemaNode(unknown);
-                        }
-                    }
+                    ParserUtils.refineChoice(choice, refine, line);
+                    usesNode.addRefineNode(choice);
                 } else if (refineTarget instanceof AnyXmlBuilder) {
                     final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
-                    if (mandatory != null) {
-                        anyXml.getConstraints().setMandatory(mandatory);
-                    }
-                    if (must != null) {
-                        anyXml.getConstraints().addMustDefinition(must);
-                    }
-                    if (unknownNodes != null) {
-                        for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
-                            anyXml.addUnknownSchemaNode(unknown);
-                        }
-                    }
+                    ParserUtils.refineAnyxml(anyXml, refine, line);
+                    usesNode.addRefineNode(anyXml);
+                } else if (refineTarget instanceof GroupingBuilder) {
+                    usesNode.addRefineNode(refineTarget);
+                } else if (refineTarget instanceof TypeDefinitionBuilder) {
+                    usesNode.addRefineNode(refineTarget);
+                }
+            }
+        }
+    }
+
+    private GroupingBuilder getTargetGrouping(
+            final UsesNodeBuilder usesBuilder,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module) {
+        final int line = usesBuilder.getLine();
+        String groupingString = usesBuilder.getGroupingName();
+        String groupingPrefix;
+        String groupingName;
+
+        if(groupingString.contains(":")) {
+            String[] splitted = groupingString.split(":");
+            if(splitted.length != 2 || groupingString.contains("/")) {
+                throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
+            }
+            groupingPrefix = splitted[0];
+            groupingName = splitted[1];
+        } else {
+            groupingPrefix = module.getPrefix();
+            groupingName = groupingString;
+        }
+
+        ModuleBuilder dependentModule = null;
+        if(groupingPrefix.equals(module.getPrefix())) {
+            dependentModule = module;
+        } else {
+            dependentModule = findDependentModule(modules, module, groupingPrefix, line);
+        }
+
+
+        List<QName> path = usesBuilder.getPath().getPath();
+        GroupingBuilder result = null;
+        Set<GroupingBuilder> groupings = dependentModule.getModuleGroupings();
+        result = findGrouping(groupings, groupingName);
+
+        if (result == null) {
+            Builder currentNode = null;
+            final List<String> currentPath = new ArrayList<String>();
+            currentPath.add(dependentModule.getName());
+
+            for (int i = 0; i < path.size(); i++) {
+                QName qname = path.get(i);
+                currentPath.add(qname.getLocalName());
+                currentNode = dependentModule.getModuleNode(currentPath);
+
+                if (currentNode instanceof RpcDefinitionBuilder) {
+                    groupings = ((RpcDefinitionBuilder) currentNode).getGroupings();
+                } else if (currentNode instanceof DataNodeContainerBuilder) {
+                    groupings = ((DataNodeContainerBuilder) currentNode).getGroupings();
+                } else {
+                    groupings = Collections.emptySet();
+                }
+
+                result = findGrouping(groupings, groupingName);
+                if (result != null) {
+                    break;
                 }
             }
         }
+
+        if (result != null) {
+            return result;
+        }
+        throw new YangParseException(module.getName(), line,
+                "Referenced grouping '" + groupingName + "' not found.");
+    }
+
+    private GroupingBuilder findGrouping(Set<GroupingBuilder> groupings,
+            String name) {
+        for (GroupingBuilder grouping : groupings) {
+            if (grouping.getQName().getLocalName().equals(name)) {
+                return grouping;
+            }
+        }
+        return null;
     }
 
     /**
-     * Find original builder of refine node and return copy of this builder.
+     * Find original builder of node to refine and return copy of this builder.
+     * <p>
+     * We must create and use a copy of builder to preserve original builder
+     * state, because this object will be refined (modified) and later added to
+     * {@link UsesNodeBuilder}.
+     * </p>
      *
      * @param groupingPath
      *            path to grouping which contains node to refine
@@ -922,15 +897,15 @@ public class YangParserImpl implements YangModelParser {
      *            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
+     * @return copy of node to be refined if it is present in grouping, null
+     *         otherwise
      */
-    private Builder getRefineTargetBuilder(final String groupingPath,
-            final RefineHolder refine,
+    private SchemaNodeBuilder getRefineNodeBuilderCopy(
+            final GroupingBuilder targetGrouping, final RefineHolder refine,
             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module) {
         Builder result = null;
-        final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
+        final Builder lookedUpBuilder = findRefineTargetBuilder(targetGrouping,
                 refine, modules, module);
         if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
             result = ParserUtils
@@ -950,11 +925,17 @@ public class YangParserImpl implements YangModelParser {
         } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
             result = ParserUtils
                     .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof GroupingBuilder) {
+            result = ParserUtils
+                    .copyGroupingBuilder((GroupingBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) {
+            result = ParserUtils
+                    .copyTypedefBuilder((TypeDefinitionBuilderImpl) lookedUpBuilder);
         } else {
             throw new YangParseException(module.getName(), refine.getLine(),
                     "Target '" + refine.getName() + "' can not be refined");
         }
-        return result;
+        return (SchemaNodeBuilder) result;
     }
 
     /**
@@ -962,8 +943,8 @@ public class YangParserImpl implements YangModelParser {
      *
      * @param groupingPath
      *            path to grouping which contains node to refine
-     * @param refineNodeName
-     *            name of node to be refined
+     * @param refine
+     *            object containing refine information
      * @param modules
      *            all loaded modules
      * @param module
@@ -971,29 +952,31 @@ public class YangParserImpl implements YangModelParser {
      * @return Builder object of refine node if it is present in grouping, null
      *         otherwise
      */
-    private Builder findRefineTargetBuilder(final String groupingPath,
+    private Builder findRefineTargetBuilder(final GroupingBuilder builder,
             final RefineHolder refine,
             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();
+        final String refineNodeName = refine.getName();
+        Builder result = builder.getChildNode(refineNodeName);
+        if (result == null) {
+            Set<GroupingBuilder> grps = builder.getGroupings();
+            for (GroupingBuilder gr : grps) {
+                if (gr.getQName().getLocalName().equals(refineNodeName)) {
+                    result = gr;
+                    break;
+                }
+            }
         }
-        if (prefix == null) {
-            prefix = module.getPrefix();
+        if (result == null) {
+            Set<TypeDefinitionBuilder> typedefs = builder.getTypeDefinitions();
+            for (TypeDefinitionBuilder typedef : typedefs) {
+                if (typedef.getQName().getLocalName().equals(refineNodeName)) {
+                    result = typedef;
+                    break;
+                }
+            }
         }
-
-        final ModuleBuilder dependentModule = findDependentModule(modules,
-                module, prefix, refine.getLine());
-        builderPath.add(0, "grouping");
-        builderPath.add(0, dependentModule.getName());
-        final GroupingBuilder builder = (GroupingBuilder) dependentModule
-                .getNode(builderPath);
-
-        return builder.getChildNode(refine.getName());
+        return result;
     }
 
     private QName findFullQName(
@@ -1023,7 +1006,7 @@ public class YangParserImpl implements YangModelParser {
     private void resolveUnknownNodes(
             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module) {
-        for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) {
+        for (UnknownSchemaNodeBuilder usnb : module.getUnknownNodes()) {
             QName nodeType = usnb.getNodeType();
             if (nodeType.getNamespace() == null
                     || nodeType.getRevision() == null) {
@@ -1053,6 +1036,8 @@ public class YangParserImpl implements YangModelParser {
      *            current module
      * @param prefix
      *            target module prefix
+     * @param line
+     *            current line in yang model
      * @return
      */
     private ModuleBuilder findDependentModule(
@@ -1099,82 +1084,4 @@ public class YangParserImpl implements YangModelParser {
         return dependentModule;
     }
 
-    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) {
-                for (final Module module : modules) {
-                    if (revision == null) {
-                        if (module.getName().equals(name)) {
-                            return module;
-                        }
-                    } else 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;
-        }
-    }
-
 }