X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fsal%2Fyang-prototype%2Fcode-generator%2Fmaven-yang-plugin%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fyang2sources%2Fplugin%2FYangToSourcesMojo.java;h=6e43b306cd44d82b1cdcaa32b5b54c976fc41a71;hp=f8117c077ed807a0f5ceafdad138e7dc5a808bb0;hb=e2dff6dc15408745a6f5988e6874be2a768c6c97;hpb=5f40ba7c5e58cda34092ff0262b1a5fe5a84a615 diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java index f8117c077e..6e43b306cd 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java @@ -7,26 +7,11 @@ */ package org.opendaylight.controller.yang2sources.plugin; -import java.io.Closeable; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; +import java.util.Arrays; import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import org.apache.commons.io.IOUtils; -import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -35,19 +20,11 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -import org.opendaylight.controller.yang.model.api.Module; import org.opendaylight.controller.yang.model.api.SchemaContext; -import org.opendaylight.controller.yang.model.parser.api.YangModelParser; -import org.opendaylight.controller.yang.parser.impl.YangParserImpl; import org.opendaylight.controller.yang2sources.plugin.ConfigArg.CodeGeneratorArg; -import org.opendaylight.controller.yang2sources.plugin.ConfigArg.ResourceProviderArg; import org.opendaylight.controller.yang2sources.spi.CodeGenerator; -import org.opendaylight.controller.yang2sources.spi.ResourceGenerator; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.io.Files; /** * Generate sources from yang files using user provided set of @@ -64,9 +41,6 @@ import com.google.common.io.Files; */ @Mojo(name = "generate-sources", defaultPhase = LifecyclePhase.GENERATE_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true) public final class YangToSourcesMojo extends AbstractMojo { - private static final String LOG_PREFIX = "yang-to-sources:"; - private static final String INPUT_RESOURCE_DIR = "META-INF/yang/"; - private static final String OUTPUT_RESOURCE_DIR = "/target/external-resources/"; /** * Classes implementing {@link CodeGenerator} interface. An instance will be @@ -74,397 +48,74 @@ public final class YangToSourcesMojo extends AbstractMojo { * CodeGenerator#generateSources(SchemaContext, File, Set * yangModulesNames)} will be called on every instance. */ - @Parameter(required = true) + @Parameter(required = false) private CodeGeneratorArg[] codeGenerators; /** * Source directory that will be recursively searched for yang files (ending * with .yang suffix). */ - @Parameter(required = true) - private String yangFilesRootDir; - - /** - * Classes implementing {@link ResourceGenerator} interface. An instance - * will be created out of every class using default constructor. Method - * {@link ResourceGenerator#generateResourceFiles(Collection, File)} will be - * called on every instance. - */ - @Parameter(required = true) - private ResourceProviderArg[] resourceProviders; + @Parameter(required = false) + private String yangFilesRootDir; // defaults to ${basedir}/src/main/yang @Parameter(property = "project", required = true, readonly = true) protected MavenProject project; - private transient final YangModelParser parser; + @Parameter(property = "inspectDependencies", required = true, readonly = true) + private boolean inspectDependencies; - @VisibleForTesting - YangToSourcesMojo(ResourceProviderArg[] resourceProviderArgs, - CodeGeneratorArg[] codeGeneratorArgs, YangModelParser parser, - String yangFilesRootDir) { - super(); - this.resourceProviders = resourceProviderArgs; - this.codeGenerators = codeGeneratorArgs; - this.yangFilesRootDir = yangFilesRootDir; - this.parser = parser; - } + private YangToSourcesProcessor yangToSourcesProcessor; public YangToSourcesMojo() { - super(); - parser = new YangParserImpl(); - } - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - ContextHolder context = processYang(); - generateSources(context); - generateResources(); - - closeResources(); - } - - /** - * Generate {@link SchemaContext} with {@link YangModelParserImpl} - */ - private ContextHolder processYang() throws MojoExecutionException { - try { - List yangFiles = Util - .listFilesAsStream(yangFilesRootDir); - Set yangModules = parser - .parseYangModelsFromStreams(yangFiles); - - List yangFilesFromDependencies = getFilesFromDependenciesAsStream(); - Set yangModulesFromDependencies = parser - .parseYangModelsFromStreams(yangFilesFromDependencies); - - Set parsedYang = new HashSet(yangModules); - parsedYang.addAll(yangModulesFromDependencies); - - if (yangFiles.isEmpty() && yangFilesFromDependencies.isEmpty()) { - getLog().warn( - Util.message( - "No %s file found in %s or in dependencies", - LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir)); - Set modules = Collections.emptySet(); - return new ContextHolder(null, modules); - } - - SchemaContext resolveSchemaContext = parser - .resolveSchemaContext(parsedYang); - getLog().info( - Util.message("%s files parsed from %s", LOG_PREFIX, - Util.YANG_SUFFIX, yangFiles)); - return new ContextHolder(resolveSchemaContext, yangModules); - - // MojoExecutionException is thrown since execution cannot continue - } catch (Exception e) { - String message = Util.message("Unable to parse %s files from %s", - LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir); - getLog().error(message, e); - throw new MojoExecutionException(message, e); - } - } - - private void generateResources() throws MojoExecutionException, - MojoFailureException { - if (resourceProviders.length == 0) { - getLog().warn( - Util.message("No resource provider classes provided", - LOG_PREFIX)); - return; - } - - Resource res = new Resource(); - String baseDirName = project.getBasedir().getAbsolutePath(); - res.setDirectory(baseDirName + OUTPUT_RESOURCE_DIR); - res.setTargetPath(INPUT_RESOURCE_DIR); - project.addResource(res); - - Map thrown = Maps.newHashMap(); - - Collection yangFiles = new ArrayList(); - - // load files from yang root - yangFiles.addAll(getFilesFromYangRoot()); - - // load files from dependencies - Collection filesFromDependencies = getFilesFromDependencies(); - yangFiles.addAll(filesFromDependencies); - - for (ResourceProviderArg resourceProvider : resourceProviders) { - try { - provideResourcesWithOneProvider(yangFiles, resourceProvider); - } catch (Exception e) { - // try other generators, exception will be thrown after - getLog().error( - Util.message( - "Unable to provide resources with %s resource provider", - LOG_PREFIX, - resourceProvider.getResourceProviderClass()), e); - thrown.put(resourceProvider.getResourceProviderClass(), e - .getClass().getCanonicalName()); - } - } - - if (!thrown.isEmpty()) { - String message = Util - .message( - "One or more code resource provider failed, including failed list(resourceProviderClass=exception) %s", - LOG_PREFIX, thrown.toString()); - getLog().error(message); - throw new MojoFailureException(message); - } - } - - private Collection getFilesFromYangRoot() { - Collection yangFilesLoaded = null; - - File rootDir = new File(yangFilesRootDir); - try { - if (rootDir.isAbsolute()) { - yangFilesLoaded = Util.listFiles(yangFilesRootDir); - } else { - String path = project.getBasedir().getAbsolutePath() - + File.separator + yangFilesRootDir; - yangFilesLoaded = Util.listFiles(path); - } - } catch (FileNotFoundException e) { - getLog().warn( - "yangFilesRootDir[" + rootDir.getAbsolutePath() - + "] does not exists."); - yangFilesLoaded = new ArrayList(); - } - - Collection yangFiles = new ArrayList(yangFilesLoaded); - - try { - for (File yangFile : yangFilesLoaded) { - InputStream is = new FileInputStream(yangFile); - yangFiles.add(createFileFromStream(is, - project.getBasedir().getAbsolutePath() - + OUTPUT_RESOURCE_DIR + yangFile.getName())); - resources.add(is); - } - } catch (IOException e) { - getLog().warn("Exception while loading yang files.", e); - } - return yangFiles; - } - - private Collection getFilesFromDependencies() { - Collection yangFiles = new ArrayList(); - - try { - List filesOnCp = Util.getClassPath(project); - List filter = Lists.newArrayList(".yang"); - for (File file : filesOnCp) { - ZipFile zip = new ZipFile(file); - Enumeration entries = zip.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String entryName = entry.getName(); - if (entryName.startsWith(INPUT_RESOURCE_DIR)) { - if (entry.isDirectory()) { - continue; - } - if (!Util.acceptedFilter(entryName, filter)) { - continue; - } - InputStream entryStream = zip.getInputStream(entry); - String newEntryName = entryName - .substring(INPUT_RESOURCE_DIR.length()); - File tmp = Files.createTempDir(); - File f = createFileFromStream(entryStream, - tmp.getAbsolutePath() + newEntryName); - yangFiles.add(f); - - resources.add(entryStream); - } - } - resources.add(zip); - } - } catch (Exception e) { - getLog().warn("Exception while loading external yang files.", e); - } - return yangFiles; - } - - private File createFileFromStream(InputStream is, String absoluteName) - throws IOException { - File f = new File(absoluteName); - if (!f.exists()) { - f.getParentFile().mkdirs(); - } - f.createNewFile(); - - FileOutputStream fos = new FileOutputStream(f); - IOUtils.copy(is, fos); - return f; - } - - /** - * Instantiate provider from class and call required method - */ - private void provideResourcesWithOneProvider(Collection yangFiles, - ResourceProviderArg resourceProvider) - throws ClassNotFoundException, InstantiationException, - IllegalAccessException { - - resourceProvider.check(); - - ResourceGenerator g = Util.getInstance( - resourceProvider.getResourceProviderClass(), - ResourceGenerator.class); - getLog().info( - Util.message("Resource provider instantiated from %s", - LOG_PREFIX, resourceProvider.getResourceProviderClass())); - - g.generateResourceFiles(yangFiles, resourceProvider.getOutputBaseDir()); - getLog().info( - Util.message("Resource provider %s call successful", - LOG_PREFIX, resourceProvider.getResourceProviderClass())); } - /** - * Call generate on every generator from plugin configuration - */ - private void generateSources(ContextHolder context) - throws MojoFailureException { - if (codeGenerators.length == 0) { - getLog().warn( - Util.message("No code generators provided", LOG_PREFIX)); - return; - } - - Map thrown = Maps.newHashMap(); - for (CodeGeneratorArg codeGenerator : codeGenerators) { - try { - generateSourcesWithOneGenerator(context, codeGenerator); - } catch (Exception e) { - // try other generators, exception will be thrown after - getLog().error( - Util.message( - "Unable to generate sources with %s generator", - LOG_PREFIX, - codeGenerator.getCodeGeneratorClass()), e); - thrown.put(codeGenerator.getCodeGeneratorClass(), e.getClass() - .getCanonicalName()); - } - } - - if (!thrown.isEmpty()) { - String message = Util - .message( - "One or more code generators failed, including failed list(generatorClass=exception) %s", - LOG_PREFIX, thrown.toString()); - getLog().error(message); - throw new MojoFailureException(message); - } + @VisibleForTesting + YangToSourcesMojo(YangToSourcesProcessor processor) { + this.yangToSourcesProcessor = processor; } - /** - * Instantiate generator from class and call required method - */ - private void generateSourcesWithOneGenerator(ContextHolder context, - CodeGeneratorArg codeGeneratorCfg) throws ClassNotFoundException, - InstantiationException, IllegalAccessException, IOException { - - codeGeneratorCfg.check(); + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + if (yangToSourcesProcessor == null) { + List codeGeneratorArgs = processCodeGenerators(codeGenerators); - CodeGenerator g = Util.getInstance( - codeGeneratorCfg.getCodeGeneratorClass(), CodeGenerator.class); - getLog().info( - Util.message("Code generator instantiated from %s", LOG_PREFIX, - codeGeneratorCfg.getCodeGeneratorClass())); + // defaults to ${basedir}/src/main/yang + File yangFilesRootFile = processYangFilesRootDir(yangFilesRootDir, + project.getBasedir()); - File outputDir = codeGeneratorCfg.getOutputBaseDir(); - if (project != null && outputDir != null) { - project.addCompileSourceRoot(outputDir.getPath()); + yangToSourcesProcessor = new YangToSourcesProcessor(getLog(), + yangFilesRootFile, codeGeneratorArgs, project, + inspectDependencies); } - Collection generated = g.generateSources(context.getContext(), - outputDir, context.getYangModules()); - getLog().info( - Util.message("Sources generated by %s: %s", LOG_PREFIX, - codeGeneratorCfg.getCodeGeneratorClass(), generated)); + yangToSourcesProcessor.execute(); } - /** - * Collection of resources which should be closed after use. - */ - private final List resources = new ArrayList(); - - /** - * Search for yang files in dependent projects. - * - * @return files found as List of InputStream - */ - private List getFilesFromDependenciesAsStream() { - final List yangsFromDependencies = new ArrayList(); - try { - List filesOnCp = Util.getClassPath(project); - - List filter = Lists.newArrayList(".yang"); - for (File file : filesOnCp) { - ZipFile zip = new ZipFile(file); - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String entryName = entry.getName(); - - if (entryName.startsWith(INPUT_RESOURCE_DIR)) { - if (entry.isDirectory()) { - continue; - } - if (!Util.acceptedFilter(entryName, filter)) { - continue; - } - - InputStream entryStream = zip.getInputStream(entry); - yangsFromDependencies.add(entryStream); - resources.add(entryStream); - } - - } - resources.add(zip); - } - } catch (Exception e) { - getLog().warn("Exception while searching yangs in dependencies", e); + private static List processCodeGenerators( + CodeGeneratorArg[] codeGenerators) { + List codeGeneratorArgs; + if (codeGenerators == null) { + codeGeneratorArgs = Collections.emptyList(); + } else { + codeGeneratorArgs = Arrays.asList(codeGenerators); } - return yangsFromDependencies; + return codeGeneratorArgs; } - /** - * Internal utility method for closing open resources. - */ - private void closeResources() { - for (Closeable resource : resources) { - try { - resource.close(); - } catch (IOException e) { - getLog().warn("Failed to close resources: " + resource, e); + private static File processYangFilesRootDir(String yangFilesRootDir, + File baseDir) { + File yangFilesRootFile; + if (yangFilesRootDir == null) { + yangFilesRootFile = new File(baseDir, "src" + File.separator + + "main" + File.separator + "yang"); + } else { + File file = new File(yangFilesRootDir); + if (file.isAbsolute()) { + yangFilesRootFile = file; + } else { + yangFilesRootFile = new File(baseDir, file.getPath()); } } + return yangFilesRootFile; } - - private class ContextHolder { - private final SchemaContext context; - private final Set yangModules; - - private ContextHolder(SchemaContext context, - Set yangModules) { - this.context = context; - this.yangModules = yangModules; - } - - public SchemaContext getContext() { - return context; - } - - public Set getYangModules() { - return yangModules; - } - } - }