X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fsal%2Fyang-prototype%2Fcode-generator%2Fmaven-yang-plugin%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fyang2sources%2Fplugin%2FYangToSourcesMojo.java;h=f5ac8f904c2475ff569d162496eb00b5ff4cdb8b;hb=1069fd445de35caa94d8cf6021e4e54399bdf5f7;hp=18e7b4cca74c67e5653809e86be6b767a82d86de;hpb=071db48e47fa3dd83da3933f1b35c3ca0d42f550;p=controller.git 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 18e7b4cca7..f5ac8f904c 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,27 +7,45 @@ */ 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.Enumeration; +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; import org.apache.maven.plugins.annotations.LifecyclePhase; 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.model.parser.impl.YangModelParserImpl; +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 @@ -42,10 +60,11 @@ import com.google.common.collect.Maps; * * */ -@Mojo(name = "generate-sources", defaultPhase = LifecyclePhase.GENERATE_SOURCES) +@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 @@ -63,12 +82,26 @@ public final class YangToSourcesMojo extends AbstractMojo { @Parameter(required = true) private String yangFilesRootDir; - private final YangModelParser parser; + /** + * 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(property = "project", required = true, readonly = true) + protected MavenProject project; + + private transient final YangModelParser parser; @VisibleForTesting - YangToSourcesMojo(CodeGeneratorArg[] codeGeneratorArgs, - YangModelParser parser, String yangFilesRootDir) { + YangToSourcesMojo(ResourceProviderArg[] resourceProviderArgs, + CodeGeneratorArg[] codeGeneratorArgs, YangModelParser parser, + String yangFilesRootDir) { super(); + this.resourceProviders = resourceProviderArgs; this.codeGenerators = codeGeneratorArgs; this.yangFilesRootDir = yangFilesRootDir; this.parser = parser; @@ -76,13 +109,16 @@ public final class YangToSourcesMojo extends AbstractMojo { public YangToSourcesMojo() { super(); - parser = new YangModelParserImpl(); + parser = new YangParserImpl(); } @Override public void execute() throws MojoExecutionException, MojoFailureException { SchemaContext context = processYang(); generateSources(context); + generateResources(); + + closeResources(); } /** @@ -90,16 +126,21 @@ public final class YangToSourcesMojo extends AbstractMojo { */ private SchemaContext processYang() throws MojoExecutionException { try { - Collection yangFiles = Util.listFiles(yangFilesRootDir); - + Collection yangFiles = Util + .listFilesAsStream(yangFilesRootDir); + yangFiles.addAll(getFilesFromDependenciesAsStream()); + if (yangFiles.isEmpty()) { getLog().warn( - Util.message("No %s file found in %s", LOG_PREFIX, - Util.YANG_SUFFIX, yangFilesRootDir)); + Util.message( + "No %s file found in %s or in dependencies", + LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir)); return null; - } - - Set parsedYang = parser.parseYangModels(new ArrayList(yangFiles)); + } + + Set parsedYang = parser + .parseYangModelsFromStreams(new ArrayList( + yangFiles)); SchemaContext resolveSchemaContext = parser .resolveSchemaContext(parsedYang); getLog().info( @@ -116,6 +157,168 @@ public final class YangToSourcesMojo extends AbstractMojo { } } + 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 */ @@ -128,12 +331,9 @@ public final class YangToSourcesMojo extends AbstractMojo { } 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( @@ -160,22 +360,83 @@ public final class YangToSourcesMojo extends AbstractMojo { * Instantiate generator from class and call required method */ private void generateSourcesWithOneGenerator(SchemaContext context, - CodeGeneratorArg codeGenerator) throws ClassNotFoundException, - InstantiationException, IllegalAccessException { + CodeGeneratorArg codeGeneratorCfg) throws ClassNotFoundException, + InstantiationException, IllegalAccessException, IOException { - codeGenerator.check(); + codeGeneratorCfg.check(); CodeGenerator g = Util.getInstance( - codeGenerator.getCodeGeneratorClass(), CodeGenerator.class); + codeGeneratorCfg.getCodeGeneratorClass(), CodeGenerator.class); getLog().info( Util.message("Code generator instantiated from %s", LOG_PREFIX, - codeGenerator.getCodeGeneratorClass())); + codeGeneratorCfg.getCodeGeneratorClass())); - Collection generated = g.generateSources(context, - codeGenerator.getOutputBaseDir()); + File outputDir = codeGeneratorCfg.getOutputBaseDir(); + if (project != null && outputDir != null) { + project.addCompileSourceRoot(outputDir.getPath()); + } + Collection generated = g.generateSources(context, outputDir); getLog().info( Util.message("Sources generated by %s: %s", LOG_PREFIX, - codeGenerator.getCodeGeneratorClass(), generated)); + codeGeneratorCfg.getCodeGeneratorClass(), generated)); + } + + /** + * 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); + } + return yangsFromDependencies; + } + + /** + * 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); + } + } } }