Refactored uses statement handling in parser.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserImpl.java
index 4bd6f20ffa49f5b2c6bff03290c668d39b245951..f6d4d67cbbe1c3f2b2a53062546106aa6204f8c4 100644 (file)
@@ -15,7 +15,9 @@ 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.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -40,15 +42,15 @@ import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
-import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
@@ -61,7 +63,7 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilde
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.util.CopyUtils;
+import org.opendaylight.yangtools.yang.parser.util.GroupingSort;
 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
@@ -70,6 +72,7 @@ import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -77,6 +80,60 @@ import com.google.common.collect.Sets;
 public final class YangParserImpl implements YangModelParser {
     private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
 
+    private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
+
+    @Override
+    public Set<Module> parseYangModels(final File yangFile, final File directory) {
+        Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
+        Preconditions.checkState(directory.exists(), directory + " does not exists");
+        Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
+
+        final String yangFileName = yangFile.getName();
+        final String[] fileList = directory.list();
+        Preconditions.checkNotNull(fileList, directory + " not found");
+
+        FileInputStream yangFileStream = null;
+        LinkedHashMap<InputStream, File> streamToFileMap = new LinkedHashMap<>();
+
+        try {
+            yangFileStream = new FileInputStream(yangFile);
+            streamToFileMap.put(yangFileStream, yangFile);
+        } catch (FileNotFoundException e) {
+            LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
+        }
+
+        for (String fileName : fileList) {
+            if (fileName.equals(yangFileName)) {
+                continue;
+            }
+            File dependency = new File(directory, fileName);
+            try {
+                if (dependency.isFile()) {
+                    streamToFileMap.put(new FileInputStream(dependency), dependency);
+                }
+            } catch (FileNotFoundException e) {
+                LOG.warn("Exception while reading yang file: " + fileName, e);
+            }
+        }
+
+        Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(new ArrayList<>(streamToFileMap.keySet()),
+                new HashMap<ModuleBuilder, InputStream>());
+        ModuleBuilder main = parsedBuilders.get(yangFileStream);
+
+        List<ModuleBuilder> moduleBuilders = new ArrayList<>();
+        moduleBuilders.add(main);
+        filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders);
+
+        ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()];
+        moduleBuilders.toArray(builders);
+
+        // module dependency graph sorted
+        List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
+
+        final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
+        return new LinkedHashSet<>(build(modules).values());
+    }
+
     @Override
     public Set<Module> parseYangModels(final List<File> yangFiles) {
         return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
@@ -96,7 +153,6 @@ public final class YangParserImpl implements YangModelParser {
             }
 
             Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
-
             final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
                     Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
 
@@ -108,7 +164,7 @@ public final class YangParserImpl implements YangModelParser {
                 }
             }
 
-            return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
+            return new LinkedHashSet<>(buildWithContext(modules, context).values());
         }
         return Collections.emptySet();
     }
@@ -124,7 +180,7 @@ public final class YangParserImpl implements YangModelParser {
             Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
             final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
                     yangModelStreams, builderToStreamMap, context);
-            return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
+            return new LinkedHashSet<>(buildWithContext(modules, context).values());
         }
         return Collections.emptySet();
     }
@@ -187,26 +243,27 @@ public final class YangParserImpl implements YangModelParser {
         return new SchemaContextImpl(modules);
     }
 
-    private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
+    private Map<InputStream, ModuleBuilder> parseModuleBuilders(List<InputStream> inputStreams,
             Map<ModuleBuilder, InputStream> streamToBuilderMap) {
 
         final ParseTreeWalker walker = new ParseTreeWalker();
-        final List<ParseTree> trees = parseStreams(inputStreams);
-        final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
+        final Map<InputStream, ParseTree> trees = parseStreams(inputStreams);
+        final Map<InputStream, ModuleBuilder> builders = new LinkedHashMap<>();
 
         // validate yang
-        new YangModelBasicValidator(walker).validate(trees);
+        new YangModelBasicValidator(walker).validate(new ArrayList<>(trees.values()));
 
-        YangParserListenerImpl yangModelParser = null;
-        for (int i = 0; i < trees.size(); i++) {
+        YangParserListenerImpl yangModelParser;
+        for (Map.Entry<InputStream, ParseTree> entry : trees.entrySet()) {
             yangModelParser = new YangParserListenerImpl();
-            walker.walk(yangModelParser, trees.get(i));
+            walker.walk(yangModelParser, entry.getValue());
             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;
+            streamToBuilderMap.put(moduleBuilder, entry.getKey());
+            builders.put(entry.getKey(), moduleBuilder);
         }
+
         return builders;
     }
 
@@ -218,20 +275,32 @@ public final class YangParserImpl implements YangModelParser {
     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
             final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
             final SchemaContext context) {
-        final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
-
-        // LinkedHashMap must be used to preserve order
-        final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
+        Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
+        ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()];
+        parsedBuilders.values().toArray(builders);
 
         // module dependency graph sorted
-        List<ModuleBuilder> sorted = null;
+        List<ModuleBuilder> sorted;
         if (context == null) {
             sorted = ModuleDependencySort.sort(builders);
         } else {
             sorted = ModuleDependencySort.sortWithContext(context, builders);
         }
 
-        for (final ModuleBuilder builder : sorted) {
+        return orderModules(sorted);
+    }
+
+    /**
+     * Order modules by name and revision.
+     *
+     * @param modules
+     *            modules to order
+     * @return modules ordered by name and revision
+     */
+    private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(List<ModuleBuilder> modules) {
+        // LinkedHashMap must be used to preserve order
+        LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
+        for (final ModuleBuilder builder : modules) {
             if (builder == null) {
                 continue;
             }
@@ -240,20 +309,42 @@ public final class YangParserImpl implements YangModelParser {
             if (builderRevision == null) {
                 builderRevision = new Date(0L);
             }
-            TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
+            TreeMap<Date, ModuleBuilder> builderByRevision = result.get(builderName);
             if (builderByRevision == null) {
-                builderByRevision = new TreeMap<Date, ModuleBuilder>();
+                builderByRevision = new TreeMap<>();
             }
             builderByRevision.put(builderRevision, builder);
-            modules.put(builderName, builderByRevision);
+            result.put(builderName, builderByRevision);
         }
-        return modules;
+        return result;
     }
 
-    private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
-        final List<ParseTree> trees = new ArrayList<ParseTree>();
+    private void filterImports(ModuleBuilder main, List<ModuleBuilder> other, List<ModuleBuilder> filtered) {
+        for (ModuleImport mi : main.getModuleImports()) {
+            for (ModuleBuilder builder : other) {
+                if (mi.getModuleName().equals(builder.getModuleName())) {
+                    if (mi.getRevision() == null) {
+                        if (!filtered.contains(builder)) {
+                            filtered.add(builder);
+                            filterImports(builder, other, filtered);
+                        }
+                    } else {
+                        if (mi.getRevision().equals(builder.getRevision())) {
+                            if (!filtered.contains(builder)) {
+                                filtered.add(builder);
+                                filterImports(builder, other, filtered);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private Map<InputStream, ParseTree> parseStreams(final List<InputStream> yangStreams) {
+        final Map<InputStream, ParseTree> trees = new HashMap<>();
         for (InputStream yangStream : yangStreams) {
-            trees.add(parseStream(yangStream));
+            trees.put(yangStream, parseStream(yangStream));
         }
         return trees;
     }
@@ -266,9 +357,10 @@ public final class YangParserImpl implements YangModelParser {
             final CommonTokenStream tokens = new CommonTokenStream(lexer);
             final YangParser parser = new YangParser(tokens);
             parser.removeErrorListeners();
-            parser.addErrorListener(new YangErrorListener());
-
+            YangErrorListener errorListener = new YangErrorListener();
+            parser.addErrorListener(errorListener);
             result = parser.yang();
+            errorListener.validate();
         } catch (IOException e) {
             LOG.warn("Exception while reading yang file: " + yangStream, e);
         }
@@ -276,28 +368,21 @@ public final class YangParserImpl implements YangModelParser {
     }
 
     private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
-        findUsesTargets(modules, null);
-
         // 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);
-            }
-        }
-        finishResolveDirtyNodes(modules);
+        resolveDirtyNodes(modules);
+        resolveAugmentsTargetPath(modules, null);
+        resolveUsesTargetGrouping(modules, null);
+        resolveUsesForGroupings(modules, null);
+        resolveUsesForNodes(modules, null);
         resolveAugments(modules);
-        resolveUses(modules);
         resolveDeviations(modules);
 
         // build
-        final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
+        final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
         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.put(moduleBuilder, module);
             }
         }
@@ -305,46 +390,49 @@ public final class YangParserImpl implements YangModelParser {
     }
 
     private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            SchemaContext context) {
-        findUsesTargets(modules, context);
-
+            final SchemaContext context) {
         // 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();
-                fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
-            }
-        }
-        finishResolveDirtyNodes(modules);
+        resolvedDirtyNodesWithContext(modules, context);
+        resolveAugmentsTargetPath(modules, context);
+        resolveUsesTargetGrouping(modules, context);
+        resolveUsesForGroupings(modules, context);
+        resolveUsesForNodes(modules, context);
         resolveAugmentsWithContext(modules, context);
-        resolveUsesWithContext(modules, context);
         resolveDeviationsWithContext(modules, context);
 
         // build
-        final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
+        final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
         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.put(moduleBuilder, module);
             }
         }
         return result;
     }
 
-    private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
-        resolveDirtyNodes(modules, builder);
-        resolveIdentities(modules, builder);
-        resolveUnknownNodes(modules, builder);
+    private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder module = childEntry.getValue();
+                resolveUnknownNodes(modules, module);
+                resolveIdentities(modules, module);
+                resolveDirtyNodes(modules, module);
+            }
+        }
     }
 
-    private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            final ModuleBuilder builder, final SchemaContext context) {
-        resolveDirtyNodesWithContext(modules, builder, context);
-        resolveIdentitiesWithContext(modules, builder, context);
-        resolveUnknownNodesWithContext(modules, builder, context);
+    private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final SchemaContext context) {
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder module = childEntry.getValue();
+                resolveUnknownNodesWithContext(modules, module, context);
+                resolveIdentitiesWithContext(modules, module, context);
+                resolveDirtyNodesWithContext(modules, module, context);
+            }
+        }
     }
 
     /**
@@ -366,48 +454,15 @@ public final class YangParserImpl implements YangModelParser {
                 } 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 {
-                    resolveType(nodeToResolve, modules, module);
-                }
-            }
-        }
-    }
-
-    private void finishResolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
-        final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
-        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
-            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
-                dirtyNodes.addAll(inner.getValue().getDirtyNodes());
-            }
-        }
-
-        if (!dirtyNodes.isEmpty()) {
-            for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
-                if (nodeToResolve instanceof UnionTypeBuilder) {
-                    List<TypeDefinitionBuilder> newTypes = new ArrayList<>();
-                    List<TypeDefinitionBuilder> oldTypes = ((UnionTypeBuilder) nodeToResolve).getTypedefs();
-                    for (TypeDefinitionBuilder tdb : oldTypes) {
-                        TypeDefinitionBuilder newType = CopyUtils.copy(tdb, nodeToResolve, false);
-                        ParserUtils.correctTypeAwareNodePath(newType);
-                        newTypes.add(newType);
+                    IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
+                            idref.getLine());
+                    if (identity == null) {
+                        throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
                     }
-                    oldTypes.clear();
-                    oldTypes.addAll(newTypes);
-                } else if (nodeToResolve.getType() instanceof IdentityrefType) {
-                    TypeDefinition<?> idRef = ParserUtils.createCorrectTypeDefinition(nodeToResolve.getPath(),
-                            nodeToResolve.getType());
-                    nodeToResolve.setType(idRef);
+                    idref.setBaseIdentity(identity);
+                    nodeToResolve.setType(idref.build(null));
                 } else {
-                    if (nodeToResolve.getType() == null) {
-                        TypeDefinitionBuilder tdb = CopyUtils.copy(nodeToResolve.getTypedef(), nodeToResolve, false);
-                        ParserUtils.correctTypeAwareNodePath(tdb);
-                        nodeToResolve.setTypedef(tdb);
-                    } else {
-                        TypeDefinition<?> td = ParserUtils.createCorrectTypeDefinition(nodeToResolve.getPath(),
-                                nodeToResolve.getType());
-                        nodeToResolve.setType(td);
-                    }
+                    resolveType(nodeToResolve, modules, module);
                 }
             }
         }
@@ -424,7 +479,10 @@ public final class YangParserImpl implements YangModelParser {
                 } 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()));
+                    IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
+                            idref.getLine());
+                    idref.setBaseIdentity(identity);
+                    nodeToResolve.setType(idref.build(null));
                 } else {
                     resolveTypeWithContext(nodeToResolve, modules, module, context);
                 }
@@ -432,6 +490,101 @@ public final class YangParserImpl implements YangModelParser {
         }
     }
 
+    /**
+     * Correct augment target path.
+     *
+     * @param modules
+     *            all loaded modules
+     */
+    private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            SchemaContext context) {
+        // collect augments from all loaded modules
+        final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
+                allAugments.addAll(inner.getValue().getAllAugments());
+            }
+        }
+
+        for (AugmentationSchemaBuilder augment : allAugments) {
+            setCorrectAugmentTargetPath(modules, augment, context);
+        }
+    }
+
+    private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final AugmentationSchemaBuilder augment, final SchemaContext context) {
+        ModuleBuilder module = ParserUtils.getParentModule(augment);
+        SchemaPath oldSchemaPath = augment.getTargetPath();
+        List<QName> oldPath = oldSchemaPath.getPath();
+        List<QName> newPath = new ArrayList<>();
+
+        Builder parent = augment.getParent();
+        if (parent instanceof UsesNodeBuilder) {
+            DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent();
+            newPath.addAll(usesParent.getPath().getPath());
+
+            URI ns;
+            Date revision;
+            String prefix;
+            QName baseQName = usesParent.getQName();
+            if (baseQName == null) {
+                ModuleBuilder m = ParserUtils.getParentModule(usesParent);
+                ns = m.getNamespace();
+                revision = m.getRevision();
+                prefix = m.getPrefix();
+            } else {
+                ns = baseQName.getNamespace();
+                revision = baseQName.getRevision();
+                prefix = baseQName.getPrefix();
+            }
+
+            for (QName qn : oldSchemaPath.getPath()) {
+                newPath.add(new QName(ns, revision, prefix, qn.getLocalName()));
+            }
+        } else {
+
+            for (QName qn : oldPath) {
+                URI ns = module.getNamespace();
+                Date rev = module.getRevision();
+                String pref = module.getPrefix();
+                String localPrefix = qn.getPrefix();
+                if (localPrefix != null && !("".equals(localPrefix))) {
+                    ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix,
+                            augment.getLine());
+                    if (currentModule == null) {
+                        Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine());
+                        if (m == null) {
+                            throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix "
+                                    + localPrefix + " not found.");
+                        }
+                        ns = m.getNamespace();
+                        rev = m.getRevision();
+                        pref = m.getPrefix();
+                    } else {
+                        ns = currentModule.getNamespace();
+                        rev = currentModule.getRevision();
+                        pref = currentModule.getPrefix();
+                    }
+                }
+                newPath.add(new QName(ns, rev, pref, qn.getLocalName()));
+            }
+        }
+        augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
+
+        for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
+            correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
+        }
+    }
+
+    private void correctPathForAugmentNodes(DataSchemaNodeBuilder node, SchemaPath parentPath) {
+        node.setPath(ParserUtils.createSchemaPath(parentPath, node.getQName()));
+        if (node instanceof DataNodeContainerBuilder) {
+            for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) {
+                correctPathForAugmentNodes(child, node.getPath());
+            }
+        }
+    }
+
     /**
      * Go through all augment definitions and perform augmentation. It is
      * expected that modules are already sorted by their dependencies.
@@ -448,6 +601,8 @@ public final class YangParserImpl implements YangModelParser {
             }
         }
 
+        checkAugmentMandatoryNodes(allAugments);
+
         for (int i = 0; i < allAugments.size(); i++) {
             // pick one augment
             final AugmentationSchemaBuilder augment = allAugments.get(i);
@@ -475,27 +630,55 @@ public final class YangParserImpl implements YangModelParser {
         }
     }
 
+    /**
+     * Check augments for mandatory nodes. If the target node is in another
+     * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
+     * If mandatory node is found, throw an exception.
+     *
+     * @param augments
+     *            augments to check
+     */
+    private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
+        for (AugmentationSchemaBuilder augment : augments) {
+            String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
+            ModuleBuilder module = ParserUtils.getParentModule(augment);
+            String modulePrefix = module.getPrefix();
+
+            if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
+                continue;
+            }
+
+            for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
+                if (childNode.getConstraints().isMandatory()) {
+                    throw new YangParseException(augment.getModuleName(), augment.getLine(),
+                            "Error in augment parsing: cannot augment mandatory node "
+                                    + childNode.getQName().getLocalName());
+                }
+            }
+        }
+    }
+
     /**
      * Search for augment target and perform augmentation.
      *
      * @param modules
      *            all loaded modules
-     * @param augmentBuilder
+     * @param augment
      *            augment to resolve
      * @return true if target node found, false otherwise
      */
     private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            final AugmentationSchemaBuilder augmentBuilder) {
-        if (augmentBuilder.isResolved()) {
+            final AugmentationSchemaBuilder augment) {
+        if (augment.isResolved()) {
             return true;
         }
 
-        int line = augmentBuilder.getLine();
-        ModuleBuilder module = getParentModule(augmentBuilder);
-        List<QName> path = augmentBuilder.getTargetPath().getPath();
-        Builder augmentParent = augmentBuilder.getParent();
+        int line = augment.getLine();
+        ModuleBuilder module = getParentModule(augment);
+        List<QName> path = augment.getTargetPath().getPath();
+        Builder augmentParent = augment.getParent();
 
-        Builder firstNodeParent = null;
+        Builder firstNodeParent;
         if (augmentParent instanceof ModuleBuilder) {
             // if augment is defined under module, parent of first node is
             // target module
@@ -504,16 +687,16 @@ public final class YangParserImpl implements YangModelParser {
             if (prefix == null) {
                 prefix = module.getPrefix();
             }
-            firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
+            firstNodeParent = findModuleFromBuilders(modules, module, prefix, line);
         } else if (augmentParent instanceof UsesNodeBuilder) {
             firstNodeParent = augmentParent.getParent();
         } else {
             // augment can be defined only under module or uses
-            throw new YangParseException(augmentBuilder.getModuleName(), line,
+            throw new YangParseException(augment.getModuleName(), line,
                     "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
         }
 
-        return processAugmentation(augmentBuilder, firstNodeParent, path);
+        return processAugmentation(augment, firstNodeParent, path);
     }
 
     /**
@@ -576,18 +759,17 @@ public final class YangParserImpl implements YangModelParser {
         }
         int line = augment.getLine();
         ModuleBuilder module = getParentModule(augment);
-        List<QName> path = augment.getTargetPath().getPath();
+        List<QName> path = augment.getTargetNodeSchemaPath().getPath();
         final QName firstNameInPath = path.get(0);
         String prefix = firstNameInPath.getPrefix();
         if (prefix == null) {
             prefix = module.getPrefix();
         }
         Builder augmentParent = augment.getParent();
-        Builder currentParent = null;
-
+        Builder currentParent;
         if (augmentParent instanceof ModuleBuilder) {
             // if augment is defined under module, first parent is target module
-            currentParent = findDependentModuleBuilder(modules, module, prefix, line);
+            currentParent = findModuleFromBuilders(modules, module, prefix, line);
         } else if (augmentParent instanceof UsesNodeBuilder) {
             currentParent = augmentParent.getParent();
         } else {
@@ -616,25 +798,13 @@ public final class YangParserImpl implements YangModelParser {
         final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
         for (IdentitySchemaNodeBuilder identity : identities) {
             final String baseIdentityName = identity.getBaseIdentityName();
+            final int line = identity.getLine();
             if (baseIdentityName != null) {
-                String baseIdentityPrefix = null;
-                String baseIdentityLocalName = null;
-                if (baseIdentityName.contains(":")) {
-                    final String[] splitted = baseIdentityName.split(":");
-                    baseIdentityPrefix = splitted[0];
-                    baseIdentityLocalName = splitted[1];
+                IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
+                if (baseIdentity == null) {
+                    throw new YangParseException(module.getName(), identity.getLine(), "Failed to find base identity");
                 } else {
-                    baseIdentityPrefix = module.getPrefix();
-                    baseIdentityLocalName = baseIdentityName;
-                }
-                final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
-                        identity.getLine());
-
-                final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
-                for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
-                    if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
-                        identity.setBaseIdentity(idBuilder);
-                    }
+                    identity.setBaseIdentity(baseIdentity);
                 }
             }
         }
@@ -657,44 +827,22 @@ public final class YangParserImpl implements YangModelParser {
         final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
         for (IdentitySchemaNodeBuilder identity : identities) {
             final String baseIdentityName = identity.getBaseIdentityName();
+            final int line = identity.getLine();
             if (baseIdentityName != null) {
-                String baseIdentityPrefix = null;
-                String baseIdentityLocalName = null;
-                if (baseIdentityName.contains(":")) {
-                    final String[] splitted = baseIdentityName.split(":");
-                    baseIdentityPrefix = splitted[0];
-                    baseIdentityLocalName = splitted[1];
+                IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
+                if (baseIdentity == null) {
+                    IdentitySchemaNode baseId = findBaseIdentityFromContext(modules, module, baseIdentityName, line,
+                            context);
+                    identity.setBaseIdentity(baseId);
                 } else {
-                    baseIdentityPrefix = module.getPrefix();
-                    baseIdentityLocalName = baseIdentityName;
-                }
-                final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
-                        baseIdentityPrefix, identity.getLine());
-
-                if (dependentModuleBuilder == null) {
-                    final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
-                            identity.getLine());
-                    final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
-                    for (IdentitySchemaNode idNode : dependentModuleIdentities) {
-                        if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
-                            identity.setBaseIdentity(idNode);
-                        }
-                    }
-                } else {
-                    final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
-                            .getIdentities();
-                    for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
-                        if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
-                            identity.setBaseIdentity(idBuilder);
-                        }
-                    }
+                    identity.setBaseIdentity(baseIdentity);
                 }
             }
         }
     }
 
     /**
-     * Find target grouping for all uses nodes.
+     * Find and add reference of uses target grouping.
      *
      * @param modules
      *            all loaded modules
@@ -702,7 +850,8 @@ public final class YangParserImpl implements YangModelParser {
      *            SchemaContext containing already resolved modules or null if
      *            context is not available
      */
-    private void findUsesTargets(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
+    private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final SchemaContext context) {
         final List<UsesNodeBuilder> allUses = new ArrayList<>();
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
@@ -716,118 +865,102 @@ public final class YangParserImpl implements YangModelParser {
             if (targetGroupingBuilder == null) {
                 if (context == null) {
                     throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
-                            + usesNode.getGroupingName() + "' not found.");
+                            + usesNode.getGroupingPathAsString() + "' not found.");
                 } else {
                     GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
                             module, context);
                     usesNode.setGroupingDefinition(targetGroupingDefinition);
-                    usesNode.setGroupingPath(targetGroupingDefinition.getPath());
                 }
             } else {
                 usesNode.setGrouping(targetGroupingBuilder);
-                usesNode.setGroupingPath(targetGroupingBuilder.getPath());
             }
         }
     }
 
-    /**
-     * Copy data from uses target, update uses parent and perform refinement.
-     * Augmentations have to be resolved already.
-     *
-     * @param modules
-     *            all loaded modules
-     */
-    private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+    private void resolveUsesForGroupings(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
+        final Set<GroupingBuilder> allGroupings = new HashSet<>();
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
                 ModuleBuilder module = inner.getValue();
-                List<UsesNodeBuilder> usesNodes = null;
-                boolean dataCollected = module.isAllUsesDataCollected();
-
-                while (!dataCollected) {
-                    usesNodes = new ArrayList<>(module.getAllUsesNodes());
-                    for (UsesNodeBuilder usesNode : usesNodes) {
-                        if (!usesNode.isDataCollected()) {
-                            GroupingUtils.collectUsesData(usesNode);
-                        }
-                    }
-                    dataCollected = module.isAllUsesDataCollected();
-                }
-            }
-        }
-
-        // new cycle is must because in collecting data process new uses could
-        // be created
-        final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
-        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
-            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
-                allModulesUses.addAll(inner.getValue().getAllUsesNodes());
+                allGroupings.addAll(module.getAllGroupings());
             }
         }
-
-        for (UsesNodeBuilder usesNode : allModulesUses) {
-            GroupingUtils.updateUsesParent(usesNode);
-            GroupingUtils.performRefine(usesNode);
-        }
-        for (UsesNodeBuilder usesNode : allModulesUses) {
-            GroupingUtils.fixUsesNodesPath(usesNode);
-        }
-
-        for (UsesNodeBuilder usesNode : allModulesUses) {
-            if (usesNode.isCopy()) {
-                usesNode.getParent().getUsesNodes().remove(usesNode);
+        final List<GroupingBuilder> sorted = GroupingSort.sort(allGroupings);
+        for (GroupingBuilder gb : sorted) {
+            List<UsesNodeBuilder> usesNodes = new ArrayList<>(GroupingSort.getAllUsesNodes(gb));
+            Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
+            for (UsesNodeBuilder usesNode : usesNodes) {
+                resolveUses(usesNode, modules, context);
             }
         }
     }
 
-    /**
-     * Copy data from uses target, update uses parent and perform refinement.
-     * Augmentations have to be resolved already.
-     *
-     * @param modules
-     *            all loaded modules
-     * @param context
-     *            SchemaContext containing already resolved modules
-     */
-    private void resolveUsesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            final SchemaContext context) {
+    private void resolveUsesForNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
                 ModuleBuilder module = inner.getValue();
-                List<UsesNodeBuilder> usesNodes = null;
-                boolean dataCollected = module.isAllUsesDataCollected();
-
-                while (!dataCollected) {
-                    usesNodes = new ArrayList<>(module.getAllUsesNodes());
-                    for (UsesNodeBuilder usesNode : usesNodes) {
-                        if (!usesNode.isDataCollected()) {
-                            if (usesNode.getGroupingBuilder() == null) {
-                                GroupingUtils.collectUsesDataFromContext(usesNode);
-                            } else {
-                                GroupingUtils.collectUsesData(usesNode);
-                            }
-                        }
-                    }
-                    dataCollected = module.isAllUsesDataCollected();
+                List<UsesNodeBuilder> usesNodes = module.getAllUsesNodes();
+                Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
+                for (UsesNodeBuilder usesNode : usesNodes) {
+                    resolveUses(usesNode, modules, context);
                 }
             }
         }
+    }
 
-        // new cycle is must because in collecting data process new uses could
-        // be created
-        final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
-        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
-            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
-                allModulesUses.addAll(inner.getValue().getAllUsesNodes());
-            }
-        }
+    private void resolveUses(UsesNodeBuilder usesNode,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
+        if (!usesNode.isResolved()) {
+            final int line = usesNode.getLine();
+            DataNodeContainerBuilder parent = usesNode.getParent();
+            ModuleBuilder module = ParserUtils.getParentModule(parent);
+            GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module);
+            if (target == null) {
+                URI ns = null;
+                Date rev = null;
+                String prefix = null;
+                if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) {
+                    ns = module.getNamespace();
+                    rev = module.getRevision();
+                    prefix = module.getPrefix();
+                } else {
+                    ns = ((DataSchemaNodeBuilder) parent).getQName().getNamespace();
+                    rev = ((DataSchemaNodeBuilder) parent).getQName().getRevision();
+                    prefix = ((DataSchemaNodeBuilder) parent).getQName().getPrefix();
+                }
 
-        for (UsesNodeBuilder usesNode : allModulesUses) {
-            GroupingUtils.updateUsesParent(usesNode);
-            GroupingUtils.performRefine(usesNode);
-        }
-        for (UsesNodeBuilder usesNode : allModulesUses) {
-            GroupingUtils.fixUsesNodesPath(usesNode);
+                Set<DataSchemaNodeBuilder> childNodes = GroupingUtils.getTargetGroupingDefinitionNodesWithNewNamespace(
+                        usesNode, ns, rev, prefix, module.getName(), line);
+                parent.getChildNodeBuilders().addAll(childNodes);
+                Set<TypeDefinitionBuilder> typedefs = GroupingUtils
+                        .getTargetGroupingDefinitionTypedefsWithNewNamespace(usesNode, ns, rev, prefix,
+                                module.getName(), line);
+                parent.getTypeDefinitionBuilders().addAll(typedefs);
+                Set<GroupingBuilder> groupings = GroupingUtils.getTargetGroupingDefinitionGroupingsWithNewNamespace(
+                        usesNode, ns, rev, prefix, module.getName(), line);
+                parent.getGroupingBuilders().addAll(groupings);
+                List<UnknownSchemaNodeBuilder> unknownNodes = GroupingUtils
+                        .getTargetGroupingDefinitionUnknownNodesWithNewNamespace(usesNode, ns, rev, prefix,
+                                module.getName(), line);
+                parent.getUnknownNodeBuilders().addAll(unknownNodes);
+                usesNode.setResolved(true);
+
+                for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
+                    processAugmentationOnContext(augment, augment.getTargetPath().getPath(), module, prefix, context);
+                }
+                GroupingUtils.performRefine(usesNode);
+            } else {
+                parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent));
+                parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
+                parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
+                parent.getUnknownNodeBuilders().addAll(target.instantiateUnknownNodes(parent));
+                usesNode.setResolved(true);
+
+                for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
+                    processAugmentation(augment, parent, augment.getTargetPath().getPath());
+                }
+                GroupingUtils.performRefine(usesNode);
+            }
         }
     }
 
@@ -835,17 +968,18 @@ public final class YangParserImpl implements YangModelParser {
         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
             QName nodeType = usnb.getNodeType();
             try {
-                ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
+                ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
                         usnb.getLine());
                 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
                     if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
+                        usnb.setNodeType(extension.getQName());
                         usnb.setExtensionBuilder(extension);
                         break;
                     }
                 }
             } catch (YangParseException e) {
                 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
-                        + ": no such extension definition found.");
+                        + ": no such extension definition found.", e);
             }
         }
     }
@@ -855,14 +989,16 @@ public final class YangParserImpl implements YangModelParser {
         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
             QName nodeType = usnb.getNodeType();
             try {
-                ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
-                        nodeType.getPrefix(), usnb.getLine());
+                ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
+                        usnb.getLine());
 
                 if (dependentModuleBuilder == null) {
                     Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
                             usnb.getLine());
                     for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
                         if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
+                            usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
+                                    nodeType.getPrefix(), e.getQName().getLocalName()));
                             usnb.setExtensionDefinition(e);
                             break;
                         }
@@ -878,7 +1014,7 @@ public final class YangParserImpl implements YangModelParser {
 
             } catch (YangParseException e) {
                 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
-                        + ": no such extension definition found.");
+                        + ": no such extension definition found.", e);
             }
 
         }
@@ -918,7 +1054,7 @@ public final class YangParserImpl implements YangModelParser {
                 prefix = module.getPrefix();
             }
 
-            ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
+            ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
             processDeviation(dev, dependentModuleBuilder, path, module);
         }
     }
@@ -964,26 +1100,23 @@ public final class YangParserImpl implements YangModelParser {
             if (prefix == null) {
                 prefix = module.getPrefix();
             }
-            String name = null;
 
-            ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
+            ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
             if (dependentModuleBuilder == null) {
-                Module dependentModule = findModuleFromContext(context, module, prefix, line);
-                Object currentParent = dependentModule;
+                Object currentParent = findModuleFromContext(context, module, prefix, line);
 
-                for (int i = 0; i < path.size(); i++) {
+                for (QName q : path) {
                     if (currentParent == null) {
-                        throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+                        throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
                     }
-                    QName q = path.get(i);
-                    name = q.getLocalName();
+                    String name = q.getLocalName();
                     if (currentParent instanceof DataNodeContainer) {
                         currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
                     }
                 }
 
                 if (currentParent == null) {
-                    throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+                    throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
                 }
                 if (currentParent instanceof SchemaNode) {
                     dev.setTargetPath(((SchemaNode) currentParent).getPath());
@@ -1012,19 +1145,18 @@ public final class YangParserImpl implements YangModelParser {
         final int line = dev.getLine();
         Builder currentParent = dependentModuleBuilder;
 
-        for (int i = 0; i < path.size(); i++) {
+        for (QName q : path) {
             if (currentParent == null) {
-                throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+                throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
             }
-            QName q = path.get(i);
             String name = q.getLocalName();
             if (currentParent instanceof DataNodeContainerBuilder) {
                 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
             }
         }
 
-        if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
-            throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+        if (!(currentParent instanceof SchemaNodeBuilder)) {
+            throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
         }
         dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
     }