diff options
Diffstat (limited to 'bundle-plugin/src/main/java/com')
3 files changed, 305 insertions, 207 deletions
diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AbstractGenerateOsgiManifestMojo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AbstractGenerateOsgiManifestMojo.java new file mode 100644 index 00000000000..d648d9ca258 --- /dev/null +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AbstractGenerateOsgiManifestMojo.java @@ -0,0 +1,210 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.plugin.mojo; + +import com.yahoo.container.plugin.classanalysis.Analyze; +import com.yahoo.container.plugin.classanalysis.ClassFileMetaData; +import com.yahoo.container.plugin.classanalysis.ExportPackageAnnotation; +import com.yahoo.container.plugin.classanalysis.PackageTally; +import com.yahoo.container.plugin.osgi.ExportPackageParser; +import com.yahoo.container.plugin.osgi.ExportPackages; +import com.yahoo.container.plugin.osgi.ImportPackages; +import com.yahoo.container.plugin.util.Strings; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.yahoo.container.plugin.util.IO.withFileOutputStream; +import static java.util.stream.Collectors.toList; + +/** + * @author bjorncs + */ +abstract class AbstractGenerateOsgiManifestMojo extends AbstractMojo { + + @Parameter(defaultValue = "${project}") + MavenProject project; + + /** + * If set to true, the artifact's version is used as default package version for ExportPackages. + * Packages from included (compile scoped) artifacts will use the version for their own artifact. + * If the package is exported with an explicit version in package-info.java, that version will be + * used regardless of this parameter. + */ + @Parameter(alias = "UseArtifactVersionForExportPackages", defaultValue = "false") + boolean useArtifactVersionForExportPackages; + + @Parameter(alias = "Bundle-Version", defaultValue = "${project.version}") + String bundleVersion; + + // TODO: default should include groupId, but that will require a lot of changes both by us and users. + @Parameter(alias = "Bundle-SymbolicName", defaultValue = "${project.artifactId}") + String bundleSymbolicName; + + @Parameter(alias = "Import-Package") + String importPackage; + + Map<String, String> generateManifestContent( + Collection<Artifact> jarArtifactsToInclude, + Map<String, ImportPackages.Import> calculatedImports, + PackageTally pluginPackageTally) { + + Map<String, Optional<String>> manualImports = getManualImports(); + for (String packageName : manualImports.keySet()) { + calculatedImports.remove(packageName); + } + Collection<ImportPackages.Import> imports = calculatedImports.values(); + + Map<String, String> ret = new HashMap<>(); + String importPackage = Stream.concat(manualImports.entrySet().stream().map(e -> asOsgiImport(e.getKey(), e.getValue())), + imports.stream().map(ImportPackages.Import::asOsgiImport)).sorted() + .collect(Collectors.joining(",")); + + String exportPackage = osgiExportPackages(pluginPackageTally.exportedPackages()).stream().sorted() + .collect(Collectors.joining(",")); + + ret.put("Created-By", "vespa container maven plugin"); + ret.put("Bundle-ManifestVersion", "2"); + ret.put("Bundle-Name", project.getName()); + ret.put("Bundle-SymbolicName", bundleSymbolicName); + ret.put("Bundle-Version", asBundleVersion(bundleVersion)); + ret.put("Bundle-Vendor", "Yahoo!"); + addIfNotEmpty(ret, "Bundle-ClassPath", bundleClassPath(jarArtifactsToInclude)); + addIfNotEmpty(ret, "Import-Package", importPackage); + addIfNotEmpty(ret, "Export-Package", exportPackage); + + return ret; + } + + PackageTally definedPackages(Collection<Artifact> jarArtifacts) { + List<PackageTally> tallies = new ArrayList<>(); + for (var artifact : jarArtifacts) { + try { + tallies.add(definedPackages(new JarFile(artifact.getFile()), artifactVersionOrNull(artifact.getVersion()))); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return PackageTally.combine(tallies); + } + + ArtifactVersion artifactVersionOrNull(String version) { + return useArtifactVersionForExportPackages ? new DefaultArtifactVersion(version) : null; + } + + static void createManifestFile(Path outputDirectory, Map<String, String> manifestContent) { + Manifest manifest = new Manifest(); + Attributes mainAttributes = manifest.getMainAttributes(); + + mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + manifestContent.forEach(mainAttributes::putValue); + + withFileOutputStream(outputDirectory.resolve(JarFile.MANIFEST_NAME).toFile(), out -> { + manifest.write(out); + return null; + }); + } + + static void addIfNotEmpty(Map<String, String> map, String key, String value) { + if (value != null && ! value.isEmpty()) { + map.put(key, value); + } + } + + private Collection<String> osgiExportPackages(Map<String, ExportPackageAnnotation> exportedPackages) { + return exportedPackages.entrySet().stream().map(entry -> entry.getKey() + ";version=" + entry.getValue().osgiVersion()) + .collect(Collectors.toList()); + } + + private static String asOsgiImport(String packageName, Optional<String> version) { + return version + .map(s -> packageName + ";version=" + ("\"" + s + "\"")) + .orElse(packageName); + } + + private static String bundleClassPath(Collection<Artifact> artifactsToInclude) { + return Stream.concat(Stream.of("."), artifactsToInclude.stream() + .map(artifact -> "dependencies/" + artifact.getFile().getName())) + .collect(Collectors.joining(",")); + } + + private Map<String, Optional<String>> getManualImports() { + try { + if (importPackage == null || importPackage.isBlank()) return Map.of(); + Map<String, Optional<String>> ret = new HashMap<>(); + List<ExportPackages.Export> imports = ExportPackageParser.parseExports(importPackage); + for (ExportPackages.Export imp : imports) { + Optional<String> version = getVersionThrowOthers(imp.getParameters()); + imp.getPackageNames().forEach(pn -> ret.put(pn, version)); + } + return ret; + } catch (Exception e) { + throw new RuntimeException("Error in Import-Package:" + importPackage, e); + } + } + + private static String asBundleVersion(String projectVersion) { + if (projectVersion == null) { + throw new IllegalArgumentException("Missing project version."); + } + + String[] parts = projectVersion.split("-", 2); + List<String> numericPart = Stream.of(parts[0].split("\\.")).map(s -> Strings.replaceEmptyString(s, "0")).limit(3) + .collect(toList()); + while (numericPart.size() < 3) { + numericPart.add("0"); + } + + return String.join(".", numericPart); + } + + private static Optional<String> getVersionThrowOthers(List<ExportPackages.Parameter> parameters) { + if (parameters.size() == 1 && "version".equals(parameters.get(0).getName())) { + return Optional.of(parameters.get(0).getValue()); + } else if (parameters.size() == 0) { + return Optional.empty(); + } else { + List<String> paramNames = parameters.stream().map(ExportPackages.Parameter::getName).collect(Collectors.toList()); + throw new RuntimeException("A single, optional version parameter expected, but got " + paramNames); + } + } + + private static PackageTally definedPackages(JarFile jarFile, ArtifactVersion version) throws MojoExecutionException { + List<ClassFileMetaData> analyzedClasses = new ArrayList<>(); + for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) { + JarEntry entry = entries.nextElement(); + if (! entry.isDirectory() && entry.getName().endsWith(".class")) { + analyzedClasses.add(analyzeClass(jarFile, entry, version)); + } + } + return PackageTally.fromAnalyzedClassFiles(analyzedClasses); + } + + private static ClassFileMetaData analyzeClass(JarFile jarFile, JarEntry entry, ArtifactVersion version) throws MojoExecutionException { + try { + return Analyze.analyzeClass(jarFile.getInputStream(entry), version); + } catch (Exception e) { + throw new MojoExecutionException( + String.format("While analyzing the class '%s' in jar file '%s'", entry.getName(), jarFile.getName()), e); + } + } + +} diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java index 41420b38360..3020184fd35 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java @@ -4,36 +4,23 @@ package com.yahoo.container.plugin.mojo; import com.google.common.collect.Sets; import com.yahoo.container.plugin.classanalysis.Analyze; import com.yahoo.container.plugin.classanalysis.ClassFileMetaData; -import com.yahoo.container.plugin.classanalysis.ExportPackageAnnotation; import com.yahoo.container.plugin.classanalysis.PackageTally; -import com.yahoo.container.plugin.osgi.ExportPackageParser; import com.yahoo.container.plugin.osgi.ExportPackages; import com.yahoo.container.plugin.osgi.ExportPackages.Export; import com.yahoo.container.plugin.osgi.ImportPackages.Import; -import com.yahoo.container.plugin.util.Strings; import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.versioning.ArtifactVersion; -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; 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 java.io.File; -import java.util.ArrayList; +import java.nio.file.Paths; import java.util.Collection; -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.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.Manifest; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,7 +28,6 @@ import static com.yahoo.container.plugin.bundle.AnalyzeBundle.exportedPackagesAg import static com.yahoo.container.plugin.osgi.ExportPackages.exportsByPackageName; import static com.yahoo.container.plugin.osgi.ImportPackages.calculateImports; import static com.yahoo.container.plugin.util.Files.allDescendantFiles; -import static com.yahoo.container.plugin.util.IO.withFileOutputStream; /** @@ -49,19 +35,7 @@ import static com.yahoo.container.plugin.util.IO.withFileOutputStream; * @author ollivir */ @Mojo(name = "generate-osgi-manifest", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true) -public class GenerateOsgiManifestMojo extends AbstractMojo { - - @Parameter(defaultValue = "${project}") - private MavenProject project = null; - - /** - * If set to true, the artifact's version is used as default package version for ExportPackages. - * Packages from included (compile scoped) artifacts will use the version for their own artifact. - * If the package is exported with an explicit version in package-info.java, that version will be - * used regardless of this parameter. - */ - @Parameter(alias = "UseArtifactVersionForExportPackages", defaultValue = "false") - private boolean useArtifactVersionForExportPackages; +public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { @Parameter private String discApplicationClass = null; @@ -69,22 +43,12 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { @Parameter private String discPreInstallBundle = null; - @Parameter(alias = "Bundle-Version", defaultValue = "${project.version}") - private String bundleVersion = null; - - // TODO: default should include groupId, but that will require a lot of changes both by us and users. - @Parameter(alias = "Bundle-SymbolicName", defaultValue = "${project.artifactId}") - private String bundleSymbolicName = null; - @Parameter(alias = "Bundle-Activator") private String bundleActivator = null; @Parameter(alias = "X-JDisc-Privileged-Activator") private String jdiscPrivilegedActivator = null; - @Parameter(alias = "Import-Package") - private String importPackage = null; - @Parameter(alias = "WebInfUrl") private String webInfUrl = null; @@ -127,19 +91,25 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { includedPackages.definedPackages(), exportsByPackageName(exportedPackagesFromProvidedJars)); - Map<String, Optional<String>> manualImports = emptyToNone(importPackage).map(GenerateOsgiManifestMojo::getManualImports) - .orElseGet(HashMap::new); - for (String packageName : manualImports.keySet()) { - calculatedImports.remove(packageName); - } - createManifestFile(new File(project.getBuild().getOutputDirectory()), manifestContent(project, - artifactSet.getJarArtifactsToInclude(), manualImports, calculatedImports.values(), includedPackages)); + + Map<String, String> manifestContent = generateManifestContent(artifactSet.getJarArtifactsToInclude(), calculatedImports, includedPackages); + addAdditionalManifestProperties(manifestContent); + createManifestFile(Paths.get(project.getBuild().getOutputDirectory()), manifestContent); } catch (Exception e) { throw new MojoExecutionException("Failed generating osgi manifest", e); } } + private void addAdditionalManifestProperties(Map<String, String> manifestContent) { + addIfNotEmpty(manifestContent, "Bundle-Activator", bundleActivator); + addIfNotEmpty(manifestContent, "X-JDisc-Privileged-Activator", jdiscPrivilegedActivator); + addIfNotEmpty(manifestContent, "Main-Class", mainClass); + addIfNotEmpty(manifestContent, "X-JDisc-Application", discApplicationClass); + addIfNotEmpty(manifestContent, "X-JDisc-Preinstall-Bundle", trimWhitespace(Optional.ofNullable(discPreInstallBundle))); + addIfNotEmpty(manifestContent, "WebInfUrl", webInfUrl); + } + private void logDebugPackageSets(List<Export> exportedPackagesFromProvidedJars, PackageTally includedPackages) { if (getLog().isDebugEnabled()) { getLog().debug("Referenced packages = " + includedPackages.referencedPackages()); @@ -197,101 +167,10 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { } } - private Collection<String> osgiExportPackages(Map<String, ExportPackageAnnotation> exportedPackages) { - return exportedPackages.entrySet().stream().map(entry -> entry.getKey() + ";version=" + entry.getValue().osgiVersion()) - .collect(Collectors.toList()); - } - private static String trimWhitespace(Optional<String> lines) { return Stream.of(lines.orElse("").split(",")).map(String::trim).collect(Collectors.joining(",")); } - private Map<String, String> manifestContent(MavenProject project, Collection<Artifact> jarArtifactsToInclude, - Map<String, Optional<String>> manualImports, Collection<Import> imports, PackageTally pluginPackageTally) { - Map<String, String> ret = new HashMap<>(); - String importPackage = Stream.concat(manualImports.entrySet().stream().map(e -> asOsgiImport(e.getKey(), e.getValue())), - imports.stream().map(Import::asOsgiImport)).sorted() - .collect(Collectors.joining(",")); - - String exportPackage = osgiExportPackages(pluginPackageTally.exportedPackages()).stream().sorted() - .collect(Collectors.joining(",")); - - ret.put("Created-By", "vespa container maven plugin"); - ret.put("Bundle-ManifestVersion", "2"); - addIfNotEmpty(ret, "Bundle-Name", project.getName()); - addIfNotEmpty(ret, "Bundle-SymbolicName", bundleSymbolicName); - addIfNotEmpty(ret, "Bundle-Version", asBundleVersion(bundleVersion)); - ret.put("Bundle-Vendor", "Yahoo!"); - addIfNotEmpty(ret, "Bundle-ClassPath", bundleClassPath(jarArtifactsToInclude)); - addIfNotEmpty(ret, "Bundle-Activator", bundleActivator); - addIfNotEmpty(ret, "X-JDisc-Privileged-Activator", jdiscPrivilegedActivator); - addIfNotEmpty(ret, "Main-Class", mainClass); - addIfNotEmpty(ret, "X-JDisc-Application", discApplicationClass); - addIfNotEmpty(ret, "X-JDisc-Preinstall-Bundle", trimWhitespace(Optional.ofNullable(discPreInstallBundle))); - addIfNotEmpty(ret, "WebInfUrl", webInfUrl); - addIfNotEmpty(ret, "Import-Package", importPackage); - addIfNotEmpty(ret, "Export-Package", exportPackage); - - return ret; - } - - private static void addIfNotEmpty(Map<String, String> map, String key, String value) { - if (value != null && ! value.isEmpty()) { - map.put(key, value); - } - } - - private static String asOsgiImport(String packageName, Optional<String> version) { - return version.map(s -> packageName + ";version=" + quote(s)).orElse(packageName); - } - - private static String quote(String s) { - return "\"" + s + "\""; - } - - private static void createManifestFile(File outputDirectory, Map<String, String> manifestContent) { - Manifest manifest = toManifest(manifestContent); - - withFileOutputStream(new File(outputDirectory, JarFile.MANIFEST_NAME), outputStream -> { - manifest.write(outputStream); - return null; - }); - } - - private static Manifest toManifest(Map<String, String> manifestContent) { - Manifest manifest = new Manifest(); - Attributes mainAttributes = manifest.getMainAttributes(); - - mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); - manifestContent.forEach(mainAttributes::putValue); - - return manifest; - } - - private static String bundleClassPath(Collection<Artifact> artifactsToInclude) { - return Stream.concat(Stream.of("."), artifactsToInclude.stream().map(GenerateOsgiManifestMojo::dependencyPath)) - .collect(Collectors.joining(",")); - } - - private static String dependencyPath(Artifact artifact) { - return "dependencies/" + artifact.getFile().getName(); - } - - private static String asBundleVersion(String projectVersion) { - if (projectVersion == null) { - throw new IllegalArgumentException("Missing project version."); - } - - String[] parts = projectVersion.split("-", 2); - List<String> numericPart = Stream.of(parts[0].split("\\.")).map(s -> Strings.replaceEmptyString(s, "0")).limit(3) - .collect(Collectors.toList()); - while (numericPart.size() < 3) { - numericPart.add("0"); - } - - return String.join(".", numericPart); - } - private void warnOnUnsupportedArtifacts(Collection<Artifact> nonJarArtifacts) { List<Artifact> unsupportedArtifacts = nonJarArtifacts.stream().filter(a -> ! a.getType().equals("pom")) .collect(Collectors.toList()); @@ -301,10 +180,6 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { artifact.getId(), artifact.getType()))); } - private ArtifactVersion artifactVersionOrNull(String version) { - return useArtifactVersionForExportPackages ? new DefaultArtifactVersion(version) : null; - } - private PackageTally getProjectClassesTally() { File outputDirectory = new File(project.getBuild().getOutputDirectory()); @@ -315,71 +190,4 @@ public class GenerateOsgiManifestMojo extends AbstractMojo { return PackageTally.fromAnalyzedClassFiles(analyzedClasses); } - - private PackageTally definedPackages(Collection<Artifact> jarArtifacts) { - List<PackageTally> tallies = new ArrayList<>(); - for (var artifact : jarArtifacts) { - try { - tallies.add(definedPackages(new JarFile(artifact.getFile()), artifactVersionOrNull(artifact.getVersion()))); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - return PackageTally.combine(tallies); - } - - private static PackageTally definedPackages(JarFile jarFile, ArtifactVersion version) throws MojoExecutionException { - List<ClassFileMetaData> analyzedClasses = new ArrayList<>(); - for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) { - JarEntry entry = entries.nextElement(); - if (! entry.isDirectory() && entry.getName().endsWith(".class")) { - analyzedClasses.add(analyzeClass(jarFile, entry, version)); - } - } - return PackageTally.fromAnalyzedClassFiles(analyzedClasses); - } - - private static ClassFileMetaData analyzeClass(JarFile jarFile, JarEntry entry, ArtifactVersion version) throws MojoExecutionException { - try { - return Analyze.analyzeClass(jarFile.getInputStream(entry), version); - } catch (Exception e) { - throw new MojoExecutionException( - String.format("While analyzing the class '%s' in jar file '%s'", entry.getName(), jarFile.getName()), e); - } - } - - private static Map<String, Optional<String>> getManualImports(String importPackage) { - try { - Map<String, Optional<String>> ret = new HashMap<>(); - List<Export> imports = parseImportPackages(importPackage); - for (Export imp : imports) { - Optional<String> version = getVersionThrowOthers(imp.getParameters()); - imp.getPackageNames().forEach(pn -> ret.put(pn, version)); - } - - return ret; - } catch (Exception e) { - throw new RuntimeException("Error in Import-Package:" + importPackage, e); - } - } - - private static Optional<String> getVersionThrowOthers(List<ExportPackages.Parameter> parameters) { - if (parameters.size() == 1 && "version".equals(parameters.get(0).getName())) { - return Optional.of(parameters.get(0).getValue()); - } else if (parameters.size() == 0) { - return Optional.empty(); - } else { - List<String> paramNames = parameters.stream().map(ExportPackages.Parameter::getName).collect(Collectors.toList()); - throw new RuntimeException("A single, optional version parameter expected, but got " + paramNames); - } - } - - private static List<Export> parseImportPackages(String importPackages) { - return ExportPackageParser.parseExports(importPackages); - } - - private static Optional<String> emptyToNone(String str) { - return Optional.ofNullable(str).map(String::trim).filter(s -> ! s.isEmpty()); - } - } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateTestBundleOsgiManifestMojo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateTestBundleOsgiManifestMojo.java new file mode 100644 index 00000000000..811aff87b7e --- /dev/null +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateTestBundleOsgiManifestMojo.java @@ -0,0 +1,80 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.plugin.mojo; + +import com.yahoo.container.plugin.classanalysis.Analyze; +import com.yahoo.container.plugin.classanalysis.ClassFileMetaData; +import com.yahoo.container.plugin.classanalysis.PackageTally; +import com.yahoo.container.plugin.osgi.ExportPackages.Export; +import com.yahoo.container.plugin.osgi.ImportPackages; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static com.yahoo.container.plugin.bundle.AnalyzeBundle.exportedPackagesAggregated; +import static com.yahoo.container.plugin.mojo.TestBundleUtils.outputDirectory; +import static com.yahoo.container.plugin.osgi.ExportPackages.exportsByPackageName; +import static com.yahoo.container.plugin.osgi.ImportPackages.calculateImports; +import static com.yahoo.container.plugin.util.Files.allDescendantFiles; +import static java.util.stream.Collectors.toList; + +/** + * @author bjorncs + */ +@Mojo(name = "generate-test-bundle-osgi-manifest", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true) +public class GenerateTestBundleOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { + + @Parameter + private String testProvidedArtifacts; + + public void execute() throws MojoExecutionException { + try { + Artifacts.ArtifactSet artifactSet = Artifacts.getArtifacts(project, true, testProvidedArtifacts); + + List<File> providedJars = artifactSet.getJarArtifactsProvided().stream() + .map(Artifact::getFile) + .collect(toList()); + + List<Export> exportedPackagesFromProvidedJars = exportedPackagesAggregated(providedJars); + + PackageTally projectPackages = getProjectMainAndTestClassesTally(); + + PackageTally jarArtifactsToInclude = definedPackages(artifactSet.getJarArtifactsToInclude()); + + PackageTally includedPackages = projectPackages.combine(jarArtifactsToInclude); + + Map<String, ImportPackages.Import> calculatedImports = calculateImports(includedPackages.referencedPackages(), + includedPackages.definedPackages(), + exportsByPackageName(exportedPackagesFromProvidedJars)); + + Map<String, String> manifestContent = generateManifestContent(artifactSet.getJarArtifactsToInclude(), calculatedImports, includedPackages); + addAdditionalManifestProperties(manifestContent); + createManifestFile(outputDirectory(project), manifestContent); + + } catch (Exception e) { + throw new MojoExecutionException("Failed generating osgi manifest", e); + } + } + + private void addAdditionalManifestProperties(Map<String, String> manifestContent) { + manifestContent.put("X-JDisc-Test-Bundle-Version", "1.0"); + } + + private PackageTally getProjectMainAndTestClassesTally() { + List<ClassFileMetaData> analyzedClasses = + Stream.concat( + allDescendantFiles(new File(project.getBuild().getOutputDirectory())), + allDescendantFiles(new File(project.getBuild().getTestOutputDirectory()))) + .filter(file -> file.getName().endsWith(".class")) + .map(classFile -> Analyze.analyzeClass(classFile, null)) + .collect(toList()); + return PackageTally.fromAnalyzedClassFiles(analyzedClasses); + } + +} |