BUG-7568: Use YangTextSchemaSource to emit schema files 85/52085/31
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 20 Feb 2017 20:46:34 +0000 (21:46 +0100)
committerRobert Varga <nite@hq.sk>
Tue, 5 Sep 2017 12:19:06 +0000 (12:19 +0000)
To properly address the issue of META-INF/yang files not having their
revisions we need to encapsulate minimal project initialization state,
which gives us properly-resolved revisions.

We then refactor the execution flow to first inspect files to
determine whan needs to happen and then execute.

Change-Id: I3257475f0b267adf0e4d5cd469829a267cfc68aa
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-maven-plugin-it/src/test/java/org/opendaylight/yangtools/yang2sources/plugin/it/YangToSourcesPluginTestIT.java
yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/ContextHolder.java [new file with mode: 0644]
yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/ProcessorModuleReactor.java [new file with mode: 0644]
yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/Util.java
yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/YangProvider.java
yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/YangToSourcesProcessor.java
yang/yang-maven-plugin/src/test/java/org/opendaylight/yangtools/yang2sources/plugin/GenerateSourcesTest.java
yang/yang-maven-plugin/src/test/java/org/opendaylight/yangtools/yang2sources/plugin/UtilTest.java
yang/yang-maven-plugin/src/test/java/org/opendaylight/yangtools/yang2sources/plugin/YangToSourcesMojoTest.java
yang/yang-maven-plugin/src/test/java/org/opendaylight/yangtools/yang2sources/plugin/YangToSourcesProcessorTest.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java

index b6f1b55d3b81864610bd8a0ce0fcd932d517bc25..c27c926132f623714ef8b304762f9fab9f30f4b9 100644 (file)
@@ -44,13 +44,13 @@ public class YangToSourcesPluginTestIT {
 
     @Test
     public void testAdditionalConfiguration() throws Exception {
-        final Verifier vrf = setUp("test-parent/AdditionalConfig/", false);
+        Verifier vrf = setUp("test-parent/AdditionalConfig/", false);
         vrf.verifyTextInLog("[DEBUG] yang-to-sources: Additional configuration picked up for : "
                 + "org.opendaylight.yangtools.yang2sources.spi.CodeGeneratorTestImpl: "
                 + "{nm1=abcd=a.b.c.d, nm2=abcd2=a.b.c.d.2}");
         vrf.verifyTextInLog("[DEBUG] yang-to-sources: Additional configuration picked up for : "
                 + "org.opendaylight.yangtools.yang2sources.spi.CodeGeneratorTestImpl: {c1=config}");
-        vrf.verifyTextInLog(File.separator + "files marked as resources: META-INF/yang");
+        vrf.verifyTextInLog("[DEBUG] yang-to-sources: YANG files marked as resources:");
         vrf.verifyTextInLog(Joiner.on(File.separator).join(Arrays.asList("target", "generated-sources", "spi"))
                 + " marked as resources for generator: org.opendaylight.yangtools.yang2sources.spi."
                 + "CodeGeneratorTestImpl");
@@ -145,19 +145,19 @@ public class YangToSourcesPluginTestIT {
         v1.executeGoal("package");
 
         String buildDir = getMavenBuildDirectory(v1);
-        v1.assertFilePresent(buildDir + "/classes/META-INF/yang/testfile1.yang");
-        v1.assertFilePresent(buildDir + "/classes/META-INF/yang/testfile2.yang");
-        v1.assertFilePresent(buildDir + "/classes/META-INF/yang/testfile3.yang");
+        v1.assertFilePresent(buildDir + "/classes/META-INF/yang/types1@2013-02-27.yang");
+        v1.assertFilePresent(buildDir + "/classes/META-INF/yang/types2@2013-02-27.yang");
+        v1.assertFilePresent(buildDir + "/classes/META-INF/yang/types3@2013-02-27.yang");
 
         Verifier v2 = setUp("test-parent/GenerateTest2/", false);
         v2.executeGoal("clean");
         v2.executeGoal("package");
 
         buildDir = getMavenBuildDirectory(v2);
-        v2.assertFilePresent(buildDir + "/classes/META-INF/yang/private.yang");
-        v2.assertFileNotPresent(buildDir + "/classes/META-INF/yang/testfile1.yang");
-        v2.assertFileNotPresent(buildDir + "/classes/META-INF/yang/testfile2.yang");
-        v2.assertFileNotPresent(buildDir + "/classes/META-INF/yang/testfile3.yang");
+        v2.assertFilePresent(buildDir + "/classes/META-INF/yang/private@2013-02-27.yang");
+        v2.assertFileNotPresent(buildDir + "/classes/META-INF/yang/types1@2013-02-27.yang");
+        v2.assertFileNotPresent(buildDir + "/classes/META-INF/yang/types2@2013-02-27.yang");
+        v2.assertFileNotPresent(buildDir + "/classes/META-INF/yang/types3@2013-02-27.yang");
     }
 
     private static String getMavenBuildDirectory(final Verifier verifier) throws IOException {
diff --git a/yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/ContextHolder.java b/yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/ContextHolder.java
new file mode 100644 (file)
index 0000000..0565ecf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang2sources.plugin;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import java.util.Optional;
+import java.util.Set;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+
+final class ContextHolder implements Immutable {
+    private final SchemaContext context;
+    private final Set<Module> modules;
+    private final Set<SourceIdentifier> sources;
+
+    ContextHolder(final SchemaContext context, final Set<Module> modules, final Set<SourceIdentifier> sources) {
+        this.context = Preconditions.checkNotNull(context);
+        this.modules = ImmutableSet.copyOf(modules);
+        this.sources = ImmutableSet.copyOf(sources);
+    }
+
+    SchemaContext getContext() {
+        return context;
+    }
+
+    Set<Module> getYangModules() {
+        return modules;
+    }
+
+    Optional<String> moduleToResourcePath(final Module mod) {
+        final SourceIdentifier id = Util.moduleToIdentifier(mod);
+        return sources.contains(id)
+                ? Optional.of("/" + YangToSourcesProcessor.META_INF_YANG_STRING_JAR + "/" + id.toYangFilename())
+                        : Optional.empty();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/ProcessorModuleReactor.java b/yang/yang-maven-plugin/src/main/java/org/opendaylight/yangtools/yang2sources/plugin/ProcessorModuleReactor.java
new file mode 100644 (file)
index 0000000..f801fb0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang2sources.plugin;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An incremental state reactor. Allows resolution of a SchemaContext based on a set of sources.
+ *
+ * @author Robert Varga
+ */
+@NotThreadSafe
+final class ProcessorModuleReactor {
+    private static final Logger LOG = LoggerFactory.getLogger(ProcessorModuleReactor.class);
+
+    private final YangTextSchemaContextResolver resolver;
+    private final Set<SourceIdentifier> sourcesInProject;
+
+    ProcessorModuleReactor(final YangTextSchemaContextResolver resolver) {
+        this.resolver = Preconditions.checkNotNull(resolver);
+        sourcesInProject = ImmutableSet.copyOf(resolver.getAvailableSources());
+    }
+
+    void registerSource(final YangTextSchemaSource source) throws SchemaSourceException, IOException,
+            YangSyntaxErrorException {
+        resolver.registerSource(source);
+    }
+
+    ContextHolder toContext() throws SchemaResolutionException {
+        final SchemaContext schemaContext = Verify.verifyNotNull(resolver.trySchemaContext());
+
+        final Set<Module> modules = new HashSet<>();
+        for (Module module : schemaContext.getModules()) {
+            final SourceIdentifier modId = Util.moduleToIdentifier(module);
+            LOG.debug("Looking for source {}", modId);
+            if (sourcesInProject.contains(modId)) {
+                LOG.debug("Module {} belongs to current project", module);
+                modules.add(module);
+
+                for (Module sub : module.getSubmodules()) {
+                    final SourceIdentifier subId = Util.moduleToIdentifier(sub);
+                    if (sourcesInProject.contains(subId)) {
+                        LOG.warn("Submodule {} not found in input files", sub);
+                    }
+                }
+            }
+        }
+
+        return new ContextHolder(schemaContext, modules, sourcesInProject);
+    }
+
+    Collection<YangTextSchemaSource> getModelsInProject() {
+        return Collections2.transform(sourcesInProject, id -> resolver.getSourceTexts(id).iterator().next());
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("sources", sourcesInProject).add("resolver", resolver).toString();
+    }
+}
index 2941edd4cb643104aec049b41f89a6416b9b6392..d897f109bd9180ede02b4e75ea1cbf77779f9da7 100644 (file)
@@ -12,9 +12,6 @@ import static org.opendaylight.yangtools.yang2sources.plugin.YangToSourcesProces
 import static org.opendaylight.yangtools.yang2sources.plugin.YangToSourcesProcessor.META_INF_YANG_STRING;
 import static org.opendaylight.yangtools.yang2sources.plugin.YangToSourcesProcessor.META_INF_YANG_STRING_JAR;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.io.ByteSource;
 import com.google.common.io.ByteStreams;
 import java.io.File;
@@ -23,11 +20,11 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -41,8 +38,11 @@ import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.repository.RepositorySystem;
+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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -290,32 +290,16 @@ final class Util {
         return yangsFilesFromDependencies;
     }
 
-    static final class ContextHolder {
-        private final SchemaContext context;
-        private final Set<Module> yangModules;
-        private final Map<Module, String> yangFiles;
-
-        ContextHolder(final SchemaContext context, final Set<Module> yangModules, final Map<Module, String> yangFiles) {
-            this.context = Preconditions.checkNotNull(context);
-            this.yangModules = ImmutableSet.copyOf(yangModules);
-            this.yangFiles = ImmutableMap.copyOf(yangFiles);
-        }
-
-        SchemaContext getContext() {
-            return context;
-        }
-
-        Set<Module> getYangModules() {
-            return yangModules;
+    static SourceIdentifier moduleToIdentifier(final Module module) {
+        final QNameModule mod = module.getQNameModule();
+        final Date rev = mod.getRevision();
+        final com.google.common.base.Optional<String> optRev;
+        if (SimpleDateFormatUtil.DEFAULT_DATE_REV.equals(rev)) {
+            optRev = com.google.common.base.Optional.absent();
+        } else {
+            optRev = com.google.common.base.Optional.of(mod.getFormattedRevision());
         }
 
-        Optional<String> moduleToResourcePath(final Module mod) {
-            final String fileName = yangFiles.get(mod);
-            if (fileName == null) {
-                return Optional.empty();
-            }
-
-            return Optional.of("/" + YangToSourcesProcessor.META_INF_YANG_STRING_JAR + "/" + fileName);
-        }
+        return RevisionSourceIdentifier.create(module.getName(), optRev);
     }
 }
index 29d72b513a09c629d81915e8558d709701a37d8b..b9c2ac9959a3b9f343aced80a1be0696f8bf393f 100644 (file)
@@ -7,48 +7,54 @@
  */
 package org.opendaylight.yangtools.yang2sources.plugin;
 
+import com.google.common.io.Files;
 import java.io.File;
 import java.io.IOException;
 import java.util.Collection;
 import org.apache.maven.model.Resource;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-class YangProvider {
-    private static final Logger LOG = LoggerFactory.getLogger(YangProvider.class);
+abstract class YangProvider {
+    private static final class Default extends YangProvider {
+        private static final Logger LOG = LoggerFactory.getLogger(YangProvider.class);
 
-    void addYangsToMetaInf(final MavenProject project, final File yangFilesRootDir,
-            final Collection<File> excludedFiles) throws MojoFailureException {
+        @Override
+        void addYangsToMetaInf(final MavenProject project, final Collection<YangTextSchemaSource> modelsInProject)
+                throws IOException {
 
-        // copy project's src/main/yang/*.yang to target/generated-sources/yang/META-INF/yang/*.yang
-        File generatedYangDir = new GeneratedDirectories(project).getYangDir();
-        addYangsToMetaInf(project, yangFilesRootDir, excludedFiles, generatedYangDir);
-    }
+            final File generatedYangDir = new GeneratedDirectories(project).getYangDir();
+            LOG.debug("Generated dir {}", generatedYangDir);
 
-    private static void addYangsToMetaInf(final MavenProject project, final File yangFilesRootDir,
-            final Collection<File> excludedFiles, final File generatedYangDir) throws MojoFailureException {
+            // copy project's src/main/yang/*.yang to ${project.builddir}/generated-sources/yang/META-INF/yang/
+            // This honors setups like a Eclipse-profile derived one
+            final File withMetaInf = new File(generatedYangDir, YangToSourcesProcessor.META_INF_YANG_STRING);
+            withMetaInf.mkdirs();
 
-        File withMetaInf = new File(generatedYangDir, YangToSourcesProcessor.META_INF_YANG_STRING);
-        withMetaInf.mkdirs();
+            for (YangTextSchemaSource source : modelsInProject) {
+                final String fileName = source.getIdentifier().toYangFilename();
+                final File file = new File(withMetaInf, fileName);
 
-        try {
-            Collection<File> files = Util.listFiles(yangFilesRootDir, excludedFiles);
-            for (File file : files) {
-                org.apache.commons.io.FileUtils.copyFile(file, new File(withMetaInf, file.getName()));
+                source.copyTo(Files.asByteSink(file));
+                LOG.debug("Created file {} for {}", file, source.getIdentifier());
             }
-        } catch (IOException e) {
-            LOG.warn("Failed to generate files into root {}", yangFilesRootDir, e);
-            throw new MojoFailureException("Unable to list yang files into resource folder", e);
+
+            setResource(generatedYangDir, project);
+            LOG.debug("{} YANG files marked as resources: {}", YangToSourcesProcessor.LOG_PREFIX, generatedYangDir);
         }
+    }
 
-        setResource(generatedYangDir, project);
+    private static final YangProvider DEFAULT = new Default();
 
-        LOG.debug("{} Yang files from: {} marked as resources: {}", YangToSourcesProcessor.LOG_PREFIX, yangFilesRootDir,
-                YangToSourcesProcessor.META_INF_YANG_STRING_JAR);
+    static YangProvider getInstance() {
+        return DEFAULT;
     }
 
+    abstract void addYangsToMetaInf(MavenProject project, Collection<YangTextSchemaSource> modelsInProject)
+            throws IOException;
+
     static void setResource(final File targetYangDir, final MavenProject project) {
         Resource res = new Resource();
         res.setDirectory(targetYangDir.getPath());
index 97c810d751130b8a843cf8021f05a18b949b4409..a708c412b9415ba58abe0dc4fc52835a2b89a860 100644 (file)
@@ -8,12 +8,9 @@
 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;
@@ -22,27 +19,20 @@ 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.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.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 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;
@@ -70,14 +60,6 @@ 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) {
@@ -87,45 +69,67 @@ class YangToSourcesProcessor {
         this.codeGenerators = ImmutableList.copyOf(codeGenerators);
         this.project = Preconditions.checkNotNull(project);
         this.inspectDependencies = inspectDependencies;
-        this.yangProvider = yangProvider;
+        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);
     }
 
     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, new YangProvider());
+        this(yangFilesRootDir, excludedFiles, codeGenerators, project, inspectDependencies, YangProvider.getInstance());
     }
 
     public void execute() throws MojoExecutionException, MojoFailureException {
-        ContextHolder context = processYang();
-        if (context != null) {
-            generateSources(context);
-            yangProvider.addYangsToMetaInf(project, yangFilesRootDir, excludedFiles);
-        }
+        conditionalExecute(false);
     }
 
     void conditionalExecute(final boolean skip) throws MojoExecutionException, MojoFailureException {
-        if (skip) {
-            LOG.info("Skipping YANG code generation because property yang.skip is true");
-
-            // But manually add resources
-            // add META_INF/yang
-            yangProvider.addYangsToMetaInf(project, yangFilesRootDir, excludedFiles);
+        final Optional<ProcessorModuleReactor> optReactor = createReactor();
+        if (!optReactor.isPresent()) {
+            return;
+        }
 
-            // 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);
+        final ProcessorModuleReactor reactor = optReactor.get();
+        if (!skip) {
+            final ContextHolder holder;
 
+            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);
+            }
 
+            generateSources(holder);
         } else {
-            execute();
+            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);
         }
+
+        // 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 ContextHolder processYang() throws MojoExecutionException {
+    private Optional<ProcessorModuleReactor> createReactor() throws MojoExecutionException {
         LOG.info("{} Inspecting {}", LOG_PREFIX, yangFilesRootDir);
         try {
             /*
@@ -142,7 +146,7 @@ class YangToSourcesProcessor {
 
             if (allFiles.isEmpty()) {
                 LOG.info("{} No input files found", LOG_PREFIX);
-                return null;
+                return Optional.empty();
             }
 
             /*
@@ -160,61 +164,20 @@ class YangToSourcesProcessor {
 
             if (noChange) {
                 LOG.info("{} None of {} input files changed", LOG_PREFIX, allFiles.size());
-                return null;
+                return Optional.empty();
             }
 
-            final Builder<SourceIdentifier, String> b = ImmutableMap.builder();
             final YangTextSchemaContextResolver resolver = YangTextSchemaContextResolver.create("maven-plugin");
             for (final File f : yangFilesInProject) {
-                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);
-                        }
-                    }
-                }
+                resolver.registerSource(YangTextSchemaSource.forFile(f));
             }
 
             LOG.debug("Processed project files: {}", yangFilesInProject);
             LOG.info("{} Project model files parsed: {}", LOG_PREFIX, yangFilesInProject.size());
-            return new ContextHolder(schemaContext, projectYangModules, projectYangFiles);
+
+            final ProcessorModuleReactor reactor = new ProcessorModuleReactor(resolver);
+            LOG.debug("Initialized reactor {}", reactor, yangFilesInProject);
+            return Optional.of(reactor);
         } catch (Exception e) {
             // MojoExecutionException is thrown since execution cannot continue
             LOG.error("{} Unable to parse {} files from {}", LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir, e);
@@ -224,17 +187,23 @@ class YangToSourcesProcessor {
         }
     }
 
-    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();
+    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);
+            }
         }
 
-        return RevisionSourceIdentifier.create(module.getName(), optRev);
+        return reactor.toContext();
     }
 
     private static Collection<YangTextSchemaSource> toUniqueSources(final Collection<YangTextSchemaSource> sources)
index 17f5074f4920acffe04cfe65a59f67d6fc4ccea3..53fb962ce7821da0be683d378efa2eaf1131d814 100644 (file)
@@ -56,11 +56,10 @@ public class GenerateSourcesTest {
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        this.yang = new File(getClass().getResource("/yang/mock.yang").toURI()).getParent();
-        this.outDir = new File("/outputDir");
+        yang = new File(getClass().getResource("/yang/mock.yang").toURI()).getParent();
+        outDir = new File("/outputDir");
         final YangProvider mock = mock(YangProvider.class);
-        doNothing().when(mock).addYangsToMetaInf(any(MavenProject.class), any(File.class),
-                any(Collection.class));
+        doNothing().when(mock).addYangsToMetaInf(any(MavenProject.class), any(Collection.class));
 
         final YangToSourcesProcessor processor = new YangToSourcesProcessor(new File(this.yang), ImmutableList.of(),
                 ImmutableList.of(new CodeGeneratorArg(GeneratorMock.class.getName(), "outputDir")), this.project, false,
@@ -76,16 +75,15 @@ public class GenerateSourcesTest {
 
     @Test
     public void test() throws Exception {
-        this.mojo.execute();
-        assertEquals(this.outDir, GeneratorMock.outputDir);
-        assertEquals(this.project, GeneratorMock.project);
+        mojo.execute();
+        assertEquals(outDir, GeneratorMock.outputDir);
+        assertEquals(project, GeneratorMock.project);
         assertTrue(GeneratorMock.additionalCfg.isEmpty());
         assertThat(GeneratorMock.resourceBaseDir.toString(), containsString("target" + File.separator
                 + "generated-sources" + File.separator + "spi"));
     }
 
     public static class GeneratorMock implements BasicCodeGenerator, MavenProjectAware {
-
         private static int called = 0;
         private static File outputDir;
         private static Map<String, String> additionalCfg;
index 5380b8b488d4d36298328f4a15d2ca3fd7d8a9e0..a6df5bdb2526e88e366dc27b3a4e711b7aca76bd 100644 (file)
@@ -15,6 +15,7 @@ import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.google.common.collect.ImmutableSet;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -26,10 +27,8 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
@@ -50,7 +49,6 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
-import org.opendaylight.yangtools.yang2sources.plugin.Util.ContextHolder;
 
 @RunWith(MockitoJUnitRunner.class)
 public class UtilTest {
@@ -139,10 +137,10 @@ public class UtilTest {
         final File testYang1 = new File(getClass().getResource("/test.yang").toURI());
         final File testYang2 = new File(getClass().getResource("/test2.yang").toURI());
         final SchemaContext context = YangParserTestUtils.parseYangSources(testYang1, testYang2);
-        final Map<Module, String> yangModules = new HashMap<>();
-        final Util.ContextHolder cxH = new ContextHolder(context, yangModules.keySet(), yangModules);
+        final Set<Module> yangModules = new HashSet<>();
+        final ContextHolder cxH = new ContextHolder(context, yangModules, ImmutableSet.of());
         assertEquals(context, cxH.getContext());
-        assertEquals(yangModules.keySet(), cxH.getYangModules());
+        assertEquals(yangModules, cxH.getYangModules());
     }
 
     private URL makeMetaInf() throws Exception {
index df7cce503dd4ff7bcee96998c2da80d2edd5c6fe..041b24198bda0a818bd949e1229504d935434b95 100644 (file)
@@ -75,6 +75,6 @@ public class YangToSourcesMojoTest {
         Mockito.when(mvnProject.getBuild()).thenReturn(build);
         final boolean dependencies = true;
         this.proc = new YangToSourcesProcessor(file, ImmutableList.of(excludedYang), codeGenerators,
-                mvnProject, dependencies, new YangProvider());
+                mvnProject, dependencies, YangProvider.getInstance());
     }
 }
index 93c64972842b7da9c8801dd1d9a8753540b9ac40..a3ca3f0c05e91bf75aa0447124298762bb09e935 100644 (file)
@@ -54,7 +54,7 @@ public class YangToSourcesProcessorTest {
         Mockito.when(mvnProject.getBuild()).thenReturn(build);
         final boolean dependencies = true;
         final YangToSourcesProcessor proc = new YangToSourcesProcessor(file, ImmutableList.of(excludedYang),
-            codeGenerators, mvnProject, dependencies, new YangProvider());
+            codeGenerators, mvnProject, dependencies, YangProvider.getInstance());
         Assert.assertNotNull(proc);
         proc.execute();
     }
index cf5e75f8c03180981102bdfe8af29a659ada94de..1e1b3882e3764f191505665dd76f56e4d0291db0 100644 (file)
@@ -253,18 +253,6 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
         return sc;
     }
 
-    @Beta
-    public SchemaContext trySchemaContext() throws SchemaResolutionException {
-        return trySchemaContext(StatementParserMode.DEFAULT_MODE);
-    }
-
-    @Beta
-    public SchemaContext trySchemaContext(final StatementParserMode statementParserMode)
-            throws SchemaResolutionException {
-        final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
-        return factory.createSchemaContext(ImmutableSet.copyOf(requiredSources), statementParserMode).checkedGet();
-    }
-
     @Override
     public synchronized CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(
             final SourceIdentifier sourceIdentifier) {
@@ -288,6 +276,23 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
         return ImmutableSet.copyOf(texts.keySet());
     }
 
+    @Beta
+    public synchronized Collection<YangTextSchemaSource> getSourceTexts(final SourceIdentifier sourceIdentifier) {
+        return ImmutableSet.copyOf(texts.get(sourceIdentifier));
+    }
+
+    @Beta
+    public SchemaContext trySchemaContext() throws SchemaResolutionException {
+        return trySchemaContext(StatementParserMode.DEFAULT_MODE);
+    }
+
+    @Beta
+    public SchemaContext trySchemaContext(final StatementParserMode statementParserMode)
+            throws SchemaResolutionException {
+        final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+        return factory.createSchemaContext(ImmutableSet.copyOf(requiredSources), statementParserMode).checkedGet();
+    }
+
     @Override
     public void close() {
         transReg.close();