Updated error handling.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserImpl.java
index 3773ab4da46cb3305e389e62dae007a71a7e4b2f..f23235bc8c7edc47525d95a572e439b460726a67 100644 (file)
@@ -29,7 +29,6 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
 
-import com.google.common.base.Preconditions;
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
@@ -42,11 +41,11 @@ 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.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;
@@ -70,6 +69,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;
@@ -89,16 +89,46 @@ public final class YangParserImpl implements YangModelParser {
         final String[] fileList = directory.list();
         Preconditions.checkNotNull(fileList, directory + " not found");
 
-        final List<File> modules = new ArrayList<>();
+        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;
             }
-            modules.add(new File(directory, fileName));
+            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);
+            }
         }
-        modules.add(yangFile);
 
-        return parseYangModels(modules);
+        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
@@ -120,7 +150,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);
 
@@ -132,7 +161,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();
     }
@@ -148,7 +177,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();
     }
@@ -211,26 +240,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;
-        for (int i = 0; i < trees.size(); i++) {
+        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;
     }
 
@@ -242,10 +272,9 @@ 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;
@@ -255,7 +284,20 @@ public final class YangParserImpl implements YangModelParser {
             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;
             }
@@ -264,20 +306,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 result;
+    }
+
+    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);
+                            }
+                        }
+                    }
+                }
+            }
         }
-        return modules;
     }
 
-    private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
-        final List<ParseTree> trees = new ArrayList<ParseTree>();
+    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;
     }
@@ -290,9 +354,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);
         }
@@ -310,7 +375,7 @@ public final class YangParserImpl implements YangModelParser {
         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()) {
             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
                 final ModuleBuilder moduleBuilder = childEntry.getValue();
@@ -333,7 +398,7 @@ public final class YangParserImpl implements YangModelParser {
         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()) {
             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
                 final ModuleBuilder moduleBuilder = childEntry.getValue();
@@ -348,9 +413,9 @@ public final class YangParserImpl implements YangModelParser {
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
                 final ModuleBuilder module = childEntry.getValue();
-                resolveDirtyNodes(modules, module);
-                resolveIdentities(modules, module);
                 resolveUnknownNodes(modules, module);
+                resolveIdentities(modules, module);
+                resolveDirtyNodes(modules, module);
             }
         }
     }
@@ -360,9 +425,9 @@ public final class YangParserImpl implements YangModelParser {
         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
                 final ModuleBuilder module = childEntry.getValue();
-                resolveDirtyNodesWithContext(modules, module, context);
-                resolveIdentitiesWithContext(modules, module, context);
                 resolveUnknownNodesWithContext(modules, module, context);
+                resolveIdentitiesWithContext(modules, module, context);
+                resolveDirtyNodesWithContext(modules, module, context);
             }
         }
     }
@@ -386,7 +451,13 @@ 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());
+                    if (identity == null) {
+                        throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
+                    }
+                    idref.setBaseIdentity(identity);
+                    nodeToResolve.setType(idref.build(null));
                 } else {
                     resolveType(nodeToResolve, modules, module);
                 }
@@ -405,7 +476,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);
                 }
@@ -680,25 +754,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;
-                String baseIdentityLocalName;
-                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 = findModuleFromBuilders(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);
                 }
             }
         }
@@ -721,37 +783,15 @@ 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;
-                String baseIdentityLocalName;
-                if (baseIdentityName.contains(":")) {
-                    final String[] splitted = baseIdentityName.split(":");
-                    baseIdentityPrefix = splitted[0];
-                    baseIdentityLocalName = splitted[1];
-                } else {
-                    baseIdentityPrefix = module.getPrefix();
-                    baseIdentityLocalName = baseIdentityName;
-                }
-                final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(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);
-                        }
-                    }
+                IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
+                if (baseIdentity == null) {
+                    IdentitySchemaNode baseId = findBaseIdentityFromContext(modules, module, baseIdentityName, line,
+                            context);
+                    identity.setBaseIdentity(baseId);
                 } else {
-                    final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
-                            .getIdentities();
-                    for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
-                        if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
-                            identity.setBaseIdentity(idBuilder);
-                        }
-                    }
+                    identity.setBaseIdentity(baseIdentity);
                 }
             }
         }
@@ -1000,18 +1040,16 @@ public final class YangParserImpl implements YangModelParser {
             if (prefix == null) {
                 prefix = module.getPrefix();
             }
-            String name = null;
 
             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 (QName q : path) {
                     if (currentParent == null) {
                         throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
                     }
-                    name = q.getLocalName();
+                    String name = q.getLocalName();
                     if (currentParent instanceof DataNodeContainer) {
                         currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
                     }