[KARAF-4553] Allow karaf boot starters to define maven plugins to call
diff --git a/samples/blueprint/service-provider/pom.xml b/samples/blueprint/service-provider/pom.xml index 08b0912..3f0cbf2 100644 --- a/samples/blueprint/service-provider/pom.xml +++ b/samples/blueprint/service-provider/pom.xml
@@ -18,6 +18,9 @@ <groupId>org.apache.karaf.boot</groupId> <artifactId>karaf-boot-sample-service-provider-blueprint</artifactId> <version>1.0.0-SNAPSHOT</version> + <properties> + <scanPath>sample</scanPath> + </properties> <dependencies> <dependency> @@ -36,24 +39,6 @@ <extensions>true</extensions> </plugin> <plugin> - <groupId>org.apache.aries.blueprint</groupId> - <artifactId>blueprint-maven-plugin</artifactId> - <version>1.3.0</version> - <executions> - <execution> - <goals> - <goal>blueprint-generate</goal> - </goals> - <phase>process-classes</phase> - </execution> - </executions> - <configuration> - <scanPaths> - <scanPath>sample</scanPath> - </scanPaths> - </configuration> - </plugin> - <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version>
diff --git a/starters/karaf-boot-starter-blueprint/src/main/resources/karaf-boot/plugins.xml b/starters/karaf-boot-starter-blueprint/src/main/resources/karaf-boot/plugins.xml new file mode 100644 index 0000000..75a2f8a --- /dev/null +++ b/starters/karaf-boot-starter-blueprint/src/main/resources/karaf-boot/plugins.xml
@@ -0,0 +1,19 @@ +<plugin> + <groupId>org.apache.aries.blueprint</groupId> + <artifactId>blueprint-maven-plugin</artifactId> + <version>1.5.0-SNAPSHOT</version> + <executions> + <execution> + <goals> + <goal>blueprint-generate</goal> + </goals> + </execution> + </executions> + <configuration> + <project>${project}</project> + <generatedFileName>autowire.xml</generatedFileName> + <scanPaths> + <scanPath>${scanPath}</scanPath> + </scanPaths> + </configuration> +</plugin>
diff --git a/tools/karaf-boot-maven-plugin/pom.xml b/tools/karaf-boot-maven-plugin/pom.xml index 89b3a5c..bed2067 100644 --- a/tools/karaf-boot-maven-plugin/pom.xml +++ b/tools/karaf-boot-maven-plugin/pom.xml
@@ -67,6 +67,13 @@ <artifactId>plexus-build-api</artifactId> <version>0.0.7</version> </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> </dependencies> <build>
diff --git a/tools/karaf-boot-maven-plugin/src/main/java/org/apache/karaf/boot/maven/GenerateMojo.java b/tools/karaf-boot-maven-plugin/src/main/java/org/apache/karaf/boot/maven/GenerateMojo.java index b6573f5..64a63f6 100644 --- a/tools/karaf-boot-maven-plugin/src/main/java/org/apache/karaf/boot/maven/GenerateMojo.java +++ b/tools/karaf-boot-maven-plugin/src/main/java/org/apache/karaf/boot/maven/GenerateMojo.java
@@ -11,6 +11,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; +import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -23,12 +24,8 @@ import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.BuildPluginManager; -import org.apache.maven.plugin.InvalidPluginDescriptorException; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.PluginDescriptorParsingException; -import org.apache.maven.plugin.PluginNotFoundException; -import org.apache.maven.plugin.PluginResolutionException; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugins.annotations.Component; @@ -38,24 +35,13 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.xbean.finder.ClassFinder; +import org.codehaus.plexus.util.xml.Xpp3Dom; import org.codehaus.plexus.util.xml.Xpp3DomBuilder; import org.sonatype.plexus.build.incremental.BuildContext; @Mojo(name = "generate", threadSafe = true, defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, inheritByDefault = false) public class GenerateMojo extends AbstractMojo { - private final class BuildStreamFactory implements StreamFactory { - @Override - public OutputStream create(File file) { - try { - file.getParentFile().mkdirs(); - return buildContext.newFileOutputStream(file); - } catch (IOException e) { - throw new RuntimeException("Error creating file " + file, e); - } - } - } - @Parameter(defaultValue = "${project}", required = true, readonly = true) private MavenProject mavenProject; @@ -74,51 +60,97 @@ public void execute() throws MojoExecutionException { try { File buildDir = new File(project.getBuild().getDirectory()); - File generatedDir = new File(buildDir, "generated-resources"); - Resource resource = new Resource(); - resource.setDirectory(generatedDir.getPath()); - project.addResource(resource); - ClassFinder finder = createProjectScopeFinder(); - List<Class<? extends BootPlugin>> plugins = finder.findImplementations(BootPlugin.class); - Map<String, List<String>> combined = new HashMap<String, List<String>>(); - for (Class<? extends BootPlugin> pluginClass : plugins) { - BootPlugin plugin = pluginClass.newInstance(); - Class<? extends Annotation> annotation = plugin.getAnnotation(); - List<Class<?>> classes = finder.findAnnotatedClasses(annotation); - if (!classes.isEmpty()) { - Map<String, List<String>> headers = plugin.enhance(classes, generatedDir, new BuildStreamFactory()); - combine(combined, headers); - } - } - Map<String, List<String>> headers = new HashMap<String, List<String>>(); - headers.put("Import-Package", Arrays.asList("*")); - combine(combined, headers); - File bndInst = new File(buildDir, "org.apache.karaf.boot.bnd"); - writeBndFile(bndInst, combined); + File generatedDir = createGeneratedDir(buildDir); + + URLClassLoader loader = projectClassLoader(); + handleBootPlugins(loader, buildDir, generatedDir); + handleMavenPlugins(loader); - InputStream is = this.getClass().getResourceAsStream("/configuration.xml"); - MojoExecution execution = new MojoExecution(getBundleMojo(), Xpp3DomBuilder.build(is, "utf-8")); - pluginManager.executeMojo(mavenSession, execution); + runMavenBundlePlugin(); } catch (Exception e) { throw new MojoExecutionException("karaf-boot-maven-plugin failed", e); } } - private MojoDescriptor getBundleMojo() throws PluginNotFoundException, PluginResolutionException, - PluginDescriptorParsingException, InvalidPluginDescriptorException { - getLog().info("Invoking maven-bundle-plugin"); - Plugin felixBundlePlugin = new Plugin(); - felixBundlePlugin.setGroupId("org.apache.felix"); - felixBundlePlugin.setArtifactId("maven-bundle-plugin"); - felixBundlePlugin.setVersion("3.0.0"); - felixBundlePlugin.setInherited(true); - felixBundlePlugin.setExtensions(true); - PluginDescriptor felixBundlePluginDescriptor = pluginManager.loadPlugin(felixBundlePlugin, mavenProject.getRemotePluginRepositories(), mavenSession.getRepositorySession()); - MojoDescriptor felixBundleMojoDescriptor = felixBundlePluginDescriptor.getMojo("bundle"); - return felixBundleMojoDescriptor; + private void handleMavenPlugins(URLClassLoader loader) throws Exception { + Enumeration<URL> resources = loader.getResources("karaf-boot/plugins.xml"); + while (resources.hasMoreElements()) { + URL res = resources.nextElement(); + executePluginDef(res.openStream()); + } } + private void executePluginDef(InputStream is) throws Exception { + Xpp3Dom pluginDef = Xpp3DomBuilder.build(is, "utf-8"); + Plugin plugin = loadPlugin(pluginDef); + Xpp3Dom config = pluginDef.getChild("configuration"); + PluginDescriptor pluginDesc = pluginManager.loadPlugin(plugin, + mavenProject.getRemotePluginRepositories(), + mavenSession.getRepositorySession()); + Xpp3Dom executions = pluginDef.getChild("executions"); + + for ( Xpp3Dom execution : executions.getChildren()) { + Xpp3Dom goals = execution.getChild("goals"); + for (Xpp3Dom goal : goals.getChildren()) { + MojoDescriptor desc = pluginDesc.getMojo(goal.getValue()); + pluginManager.executeMojo(mavenSession, new MojoExecution(desc, config)); + } + } + } + + Plugin loadPlugin(Xpp3Dom pluginDef) { + String groupId = pluginDef.getChild("groupId").getValue(); + String artifactId = pluginDef.getChild("artifactId").getValue(); + String version = pluginDef.getChild("version").getValue(); + Plugin plugin = new Plugin(); + plugin.setGroupId(groupId); + plugin.setArtifactId(artifactId); + plugin.setVersion(version); + return plugin; + } + + private File createGeneratedDir(File buildDir) { + File generatedDir = new File(buildDir, "generated-resources"); + Resource resource = new Resource(); + resource.setDirectory(generatedDir.getPath()); + project.addResource(resource); + return generatedDir; + } + + private void handleBootPlugins(URLClassLoader loader, File buildDir, File generatedDir) + throws MalformedURLException, InstantiationException, IllegalAccessException, IOException { + ClassFinder finder = new ClassFinder(loader, Arrays.asList(loader.getURLs())); + List<Class<? extends BootPlugin>> plugins = finder.findImplementations(BootPlugin.class); + Map<String, List<String>> headers = new HashMap<String, List<String>>(); + for (Class<? extends BootPlugin> pluginClass : plugins) { + applyBootPlugin(generatedDir, finder, headers, pluginClass); + } + addImportDefault(headers); + File bndInst = new File(buildDir, "org.apache.karaf.boot.bnd"); + writeBndFile(bndInst, headers); + } + + private void applyBootPlugin(File generatedDir, ClassFinder finder, Map<String, List<String>> combined, + Class<? extends BootPlugin> pluginClass) + throws InstantiationException, IllegalAccessException { + BootPlugin plugin = pluginClass.newInstance(); + Class<? extends Annotation> annotation = plugin.getAnnotation(); + List<Class<?>> classes = finder.findAnnotatedClasses(annotation); + if (!classes.isEmpty()) { + Map<String, List<String>> headers = plugin.enhance(classes, generatedDir, new BuildStreamFactory()); + combine(combined, headers); + } + } + + private void addImportDefault(Map<String, List<String>> combined) { + Map<String, List<String>> headers = new HashMap<String, List<String>>(); + headers.put("Import-Package", Arrays.asList("*")); + combine(combined, headers); + } + + + private void writeBndFile(File bndInst, Map<String, List<String>> combined) throws IOException { try ( OutputStream os = buildContext.newFileOutputStream(bndInst); @@ -142,19 +174,47 @@ } } - private ClassFinder createProjectScopeFinder() throws MalformedURLException { + private URLClassLoader projectClassLoader() throws MalformedURLException { List<URL> urls = new ArrayList<URL>(); - urls.add(new File(project.getBuild().getOutputDirectory()).toURI().toURL()); - for (Object artifactO : project.getArtifacts()) { - Artifact artifact = (Artifact) artifactO; + for (Artifact artifact : project.getArtifacts()) { File file = artifact.getFile(); if (file != null) { urls.add(file.toURI().toURL()); } } - ClassLoader loader = new URLClassLoader(urls.toArray(new URL[urls.size()]), getClass().getClassLoader()); - return new ClassFinder(loader, urls); + URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[urls.size()]), getClass().getClassLoader()); + return loader; } + private void runMavenBundlePlugin() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/configuration.xml"); + MojoExecution execution = new MojoExecution(getMavenBundleMojo(), Xpp3DomBuilder.build(is, "utf-8")); + getLog().info("Invoking maven-bundle-plugin"); + pluginManager.executeMojo(mavenSession, execution); + } + + private MojoDescriptor getMavenBundleMojo() throws Exception { + Plugin plugin = new Plugin(); + plugin.setGroupId("org.apache.felix"); + plugin.setArtifactId("maven-bundle-plugin"); + plugin.setVersion("3.0.0"); + plugin.setInherited(true); + plugin.setExtensions(true); + PluginDescriptor desc = pluginManager.loadPlugin(plugin, mavenProject.getRemotePluginRepositories(), mavenSession.getRepositorySession()); + return desc.getMojo("bundle"); + } + + + private final class BuildStreamFactory implements StreamFactory { + @Override + public OutputStream create(File file) { + try { + file.getParentFile().mkdirs(); + return buildContext.newFileOutputStream(file); + } catch (IOException e) { + throw new RuntimeException("Error creating file " + file, e); + } + } + } }
diff --git a/tools/karaf-boot-maven-plugin/src/test/java/org/apache/karaf/boot/maven/PluginLoaderTest.java b/tools/karaf-boot-maven-plugin/src/test/java/org/apache/karaf/boot/maven/PluginLoaderTest.java new file mode 100644 index 0000000..ab362d0 --- /dev/null +++ b/tools/karaf-boot-maven-plugin/src/test/java/org/apache/karaf/boot/maven/PluginLoaderTest.java
@@ -0,0 +1,25 @@ +package org.apache.karaf.boot.maven; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.maven.model.Plugin; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.Xpp3DomBuilder; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.junit.Assert; +import org.junit.Test; + +public class PluginLoaderTest { + + @Test + public void testLoadXml() throws XmlPullParserException, IOException { + InputStream is = this.getClass().getResourceAsStream("/plugins.xml"); + Xpp3Dom pluginDef = Xpp3DomBuilder.build(is, "utf-8"); + Plugin plugin = new GenerateMojo().loadPlugin(pluginDef); + Assert.assertEquals("org.apache.aries.blueprint", plugin.getGroupId()); + Assert.assertEquals("blueprint-maven-plugin", plugin.getArtifactId()); + Assert.assertEquals("1.4.0", plugin.getVersion()); + } + +}
diff --git a/tools/karaf-boot-maven-plugin/src/test/resources/plugins.xml b/tools/karaf-boot-maven-plugin/src/test/resources/plugins.xml new file mode 100644 index 0000000..b03a2f2 --- /dev/null +++ b/tools/karaf-boot-maven-plugin/src/test/resources/plugins.xml
@@ -0,0 +1,17 @@ +<plugin> + <groupId>org.apache.aries.blueprint</groupId> + <artifactId>blueprint-maven-plugin</artifactId> + <version>1.4.0</version> + <executions> + <execution> + <goals> + <goal>blueprint-generate</goal> + </goals> + </execution> + </executions> + <configuration> + <scanPaths> + <scanPath>${scanPath}</scanPath> + </scanPaths> + </configuration> +</plugin>