Revert "BUG-7568: Use YangTextSchemaSource to emit schema files"
[yangtools.git] / yang / yang-maven-plugin / src / main / java / org / opendaylight / yangtools / yang2sources / plugin / YangToSourcesProcessor.java
index a708c412b9415ba58abe0dc4fc52835a2b89a860..97c810d751130b8a843cf8021f05a18b949b4409 100644 (file)
@@ -8,9 +8,12 @@
 package org.opendaylight.yangtools.yang2sources.plugin;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.io.CharStreams;
 import java.io.File;
@@ -19,20 +22,27 @@ import java.io.Reader;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.util.FileUtils;
-import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
+import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaSourceRegistration;
 import org.opendaylight.yangtools.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
+import org.opendaylight.yangtools.yang2sources.plugin.Util.ContextHolder;
 import org.opendaylight.yangtools.yang2sources.spi.BasicCodeGenerator;
 import org.opendaylight.yangtools.yang2sources.spi.BuildContextAware;
 import org.opendaylight.yangtools.yang2sources.spi.MavenProjectAware;
@@ -60,6 +70,14 @@ class YangToSourcesProcessor {
     private final BuildContext buildContext;
     private final YangProvider yangProvider;
 
+    @VisibleForTesting
+    YangToSourcesProcessor(final File yangFilesRootDir, final Collection<File> excludedFiles,
+            final List<CodeGeneratorArg> codeGenerators, final MavenProject project, final boolean inspectDependencies,
+            final YangProvider yangProvider) {
+        this(new DefaultBuildContext(), yangFilesRootDir, excludedFiles, codeGenerators, project,
+                inspectDependencies, yangProvider);
+    }
+
     private YangToSourcesProcessor(final BuildContext buildContext, final File yangFilesRootDir,
             final Collection<File> excludedFiles, final List<CodeGeneratorArg> codeGenerators,
             final MavenProject project, final boolean inspectDependencies, final YangProvider yangProvider) {
@@ -69,67 +87,45 @@ class YangToSourcesProcessor {
         this.codeGenerators = ImmutableList.copyOf(codeGenerators);
         this.project = Preconditions.checkNotNull(project);
         this.inspectDependencies = inspectDependencies;
-        this.yangProvider = Preconditions.checkNotNull(yangProvider);
-    }
-
-    @VisibleForTesting
-    YangToSourcesProcessor(final File yangFilesRootDir, final Collection<File> excludedFiles,
-            final List<CodeGeneratorArg> codeGenerators, final MavenProject project, final boolean inspectDependencies,
-            final YangProvider yangProvider) {
-        this(new DefaultBuildContext(), yangFilesRootDir, excludedFiles, codeGenerators, project,
-                inspectDependencies, yangProvider);
+        this.yangProvider = yangProvider;
     }
 
     YangToSourcesProcessor(final BuildContext buildContext, final File yangFilesRootDir,
                 final Collection<File> excludedFiles, final List<CodeGeneratorArg> codeGenerators,
                 final MavenProject project, final boolean inspectDependencies) {
-        this(yangFilesRootDir, excludedFiles, codeGenerators, project, inspectDependencies, YangProvider.getInstance());
+        this(yangFilesRootDir, excludedFiles, codeGenerators, project, inspectDependencies, new YangProvider());
     }
 
     public void execute() throws MojoExecutionException, MojoFailureException {
-        conditionalExecute(false);
+        ContextHolder context = processYang();
+        if (context != null) {
+            generateSources(context);
+            yangProvider.addYangsToMetaInf(project, yangFilesRootDir, excludedFiles);
+        }
     }
 
     void conditionalExecute(final boolean skip) throws MojoExecutionException, MojoFailureException {
-        final Optional<ProcessorModuleReactor> optReactor = createReactor();
-        if (!optReactor.isPresent()) {
-            return;
-        }
+        if (skip) {
+            LOG.info("Skipping YANG code generation because property yang.skip is true");
 
-        final ProcessorModuleReactor reactor = optReactor.get();
-        if (!skip) {
-            final ContextHolder holder;
+            // But manually add resources
+            // add META_INF/yang
+            yangProvider.addYangsToMetaInf(project, yangFilesRootDir, excludedFiles);
 
-            try {
-                holder = createContextHolder(reactor);
-            } catch (SchemaSourceException | YangSyntaxErrorException e) {
-                throw new MojoFailureException("Failed to process reactor " + reactor, e);
-            } catch (IOException e) {
-                throw new MojoExecutionException("Failed to read reactor " + reactor, e);
-            }
+            // add META_INF/services
+            File generatedServicesDir = new GeneratedDirectories(project).getYangServicesDir();
+            YangProvider.setResource(generatedServicesDir, project);
+            LOG.debug("{} Yang services files from: {} marked as resources: {}", LOG_PREFIX, generatedServicesDir,
+                    META_INF_YANG_SERVICES_STRING_JAR);
 
-            generateSources(holder);
-        } else {
-            LOG.info("Skipping YANG code generation because property yang.skip is true");
-        }
 
-        // add META_INF/yang
-        final Collection<YangTextSchemaSource> models = reactor.getModelsInProject();
-        try {
-            yangProvider.addYangsToMetaInf(project, models);
-        } catch (IOException e) {
-            throw new MojoExecutionException("Failed write model files for " + models, e);
+        } else {
+            execute();
         }
-
-        // add META_INF/services
-        File generatedServicesDir = new GeneratedDirectories(project).getYangServicesDir();
-        YangProvider.setResource(generatedServicesDir, project);
-        LOG.debug("{} Yang services files from: {} marked as resources: {}", LOG_PREFIX, generatedServicesDir,
-            META_INF_YANG_SERVICES_STRING_JAR);
     }
 
     @SuppressWarnings("checkstyle:illegalCatch")
-    private Optional<ProcessorModuleReactor> createReactor() throws MojoExecutionException {
+    private ContextHolder processYang() throws MojoExecutionException {
         LOG.info("{} Inspecting {}", LOG_PREFIX, yangFilesRootDir);
         try {
             /*
@@ -146,7 +142,7 @@ class YangToSourcesProcessor {
 
             if (allFiles.isEmpty()) {
                 LOG.info("{} No input files found", LOG_PREFIX);
-                return Optional.empty();
+                return null;
             }
 
             /*
@@ -164,20 +160,61 @@ class YangToSourcesProcessor {
 
             if (noChange) {
                 LOG.info("{} None of {} input files changed", LOG_PREFIX, allFiles.size());
-                return Optional.empty();
+                return null;
             }
 
+            final Builder<SourceIdentifier, String> b = ImmutableMap.builder();
             final YangTextSchemaContextResolver resolver = YangTextSchemaContextResolver.create("maven-plugin");
             for (final File f : yangFilesInProject) {
-                resolver.registerSource(YangTextSchemaSource.forFile(f));
+                final YangTextSchemaSourceRegistration reg = resolver.registerSource(YangTextSchemaSource.forFile(f));
+                // Registration has an accurate identifier
+                b.put(reg.getInstance().getIdentifier(), f.getName());
+            }
+
+            final Map<SourceIdentifier, String> sourcesInProject = b.build();
+
+            /**
+             * Set contains all modules generated from input sources. Number of
+             * modules may differ from number of sources due to submodules
+             * (parsed submodule's data are added to its parent module). Set
+             * cannot contains null values.
+             */
+            if (inspectDependencies) {
+                final List<YangTextSchemaSource> sourcesInDependencies = Util.findYangFilesInDependenciesAsStream(
+                    project);
+                for (YangTextSchemaSource s : toUniqueSources(sourcesInDependencies)) {
+                    resolver.registerSource(s);
+                }
+            }
+
+            final SchemaContext schemaContext = resolver.trySchemaContext();
+            final Set<Module> projectYangModules = new HashSet<>();
+            final Map<Module, String> projectYangFiles = new HashMap<>();
+            for (Module module : schemaContext.getModules()) {
+                final SourceIdentifier modId = moduleToIdentifier(module);
+                LOG.debug("Looking for source {}", modId);
+                final String file = sourcesInProject.get(modId);
+                if (file != null) {
+                    LOG.debug("Module {} belongs to current project", module);
+                    projectYangModules.add(module);
+                    projectYangFiles.put(module, file);
+
+                    for (Module sub : module.getSubmodules()) {
+                        final SourceIdentifier subId = moduleToIdentifier(sub);
+                        final String subFile = sourcesInProject.get(subId);
+                        if (subFile != null) {
+                            LOG.debug("Submodule {} belongs to current project", sub);
+                            projectYangFiles.put(sub, subFile);
+                        } else {
+                            LOG.warn("Submodule {} not found in input files", sub);
+                        }
+                    }
+                }
             }
 
             LOG.debug("Processed project files: {}", yangFilesInProject);
             LOG.info("{} Project model files parsed: {}", LOG_PREFIX, yangFilesInProject.size());
-
-            final ProcessorModuleReactor reactor = new ProcessorModuleReactor(resolver);
-            LOG.debug("Initialized reactor {}", reactor, yangFilesInProject);
-            return Optional.of(reactor);
+            return new ContextHolder(schemaContext, projectYangModules, projectYangFiles);
         } catch (Exception e) {
             // MojoExecutionException is thrown since execution cannot continue
             LOG.error("{} Unable to parse {} files from {}", LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir, e);
@@ -187,23 +224,17 @@ class YangToSourcesProcessor {
         }
     }
 
-    private ContextHolder createContextHolder(final ProcessorModuleReactor reactor) throws MojoFailureException,
-            IOException, SchemaSourceException, YangSyntaxErrorException {
-        /**
-         * Set contains all modules generated from input sources. Number of
-         * modules may differ from number of sources due to submodules
-         * (parsed submodule's data are added to its parent module). Set
-         * cannot contains null values.
-         */
-        if (inspectDependencies) {
-            final List<YangTextSchemaSource> sourcesInDependencies = Util.findYangFilesInDependenciesAsStream(
-                project);
-            for (YangTextSchemaSource s : toUniqueSources(sourcesInDependencies)) {
-                reactor.registerSource(s);
-            }
+    private static SourceIdentifier moduleToIdentifier(final Module module) {
+        final QNameModule mod = module.getQNameModule();
+        final Date rev = mod.getRevision();
+        final Optional<String> optRev;
+        if (!SimpleDateFormatUtil.DEFAULT_DATE_REV.equals(rev)) {
+            optRev = Optional.of(mod.getFormattedRevision());
+        } else {
+            optRev = Optional.absent();
         }
 
-        return reactor.toContext();
+        return RevisionSourceIdentifier.create(module.getName(), optRev);
     }
 
     private static Collection<YangTextSchemaSource> toUniqueSources(final Collection<YangTextSchemaSource> sources)