summaryrefslogtreecommitdiffstats
path: root/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2020-06-24 13:48:47 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2020-06-24 13:48:47 +0200
commit1f1876624de0ca909a366fa16db97a34a686ae42 (patch)
treece136cb3df899dfafd118335bb51db51fb2c3c34 /bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/GenerateOsgiManifestMojo.java
parent2635e09140e047b9b7b078d844082f3444d76f78 (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.java222
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());
- }
-
}