diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-06-24 13:48:47 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-06-24 13:48:47 +0200 |
commit | 1f1876624de0ca909a366fa16db97a34a686ae42 (patch) | |
tree | ce136cb3df899dfafd118335bb51db51fb2c3c34 /bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java | |
parent | 2635e09140e047b9b7b078d844082f3444d76f78 (diff) |
Implement goal for generating OSGi manifest for test bundles
Introduce an abstract class containing behaviour that is shared with
existing manifest goal.
Diffstat (limited to 'bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java')
-rw-r--r-- | bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java | 222 |
1 files changed, 15 insertions, 207 deletions
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()); - } - } |