diff options
Diffstat (limited to 'bundle-plugin/src')
11 files changed, 221 insertions, 59 deletions
diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/bundle/AnalyzeBundle.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/bundle/AnalyzeBundle.java index 2b5941cc5aa..af6c82023ab 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/bundle/AnalyzeBundle.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/bundle/AnalyzeBundle.java @@ -7,12 +7,14 @@ import com.yahoo.container.plugin.util.JarFiles; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.jar.Manifest; +import java.util.stream.Collectors; /** * Static utilities for analyzing jar files. @@ -34,20 +36,42 @@ public class AnalyzeBundle { } static List<Export> exportedPackages(File jarFile) { + var manifest = getOsgiManifest(jarFile); + if (manifest == null) return Collections.emptyList(); try { - Optional<Manifest> jarManifest = JarFiles.getManifest(jarFile); - if (jarManifest.isPresent()) { - Manifest manifest = jarManifest.get(); - if (isOsgiManifest(manifest)) { - return parseExports(manifest); - } - } - return Collections.emptyList(); + return parseExports(manifest); } catch (Exception e) { throw new RuntimeException(String.format("Invalid manifest in bundle '%s'", jarFile.getPath()), e); } } + public static List<String> publicApiPackagesAggregated(Collection<File> jarFiles) { + return jarFiles.stream() + .map(AnalyzeBundle::publicApiPackages) + .flatMap(List::stream) + .distinct() + .toList(); + } + + static List<String> publicApiPackages(File jarFile) { + var manifest = getOsgiManifest(jarFile); + if (manifest == null) return Collections.emptyList(); + return getMainAttributeValue(manifest, "X-JDisc-PublicApi-Package") + .map(s -> Arrays.asList(s.split(","))) + .orElseGet(ArrayList::new); + } + + private static Manifest getOsgiManifest(File jarFile) { + Optional<Manifest> jarManifest = JarFiles.getManifest(jarFile); + if (jarManifest.isPresent()) { + Manifest manifest = jarManifest.get(); + if (isOsgiManifest(manifest)) { + return manifest; + } + } + return null; + } + public static Optional<String> bundleSymbolicName(File jarFile) { return JarFiles.getManifest(jarFile).flatMap(AnalyzeBundle::getBundleSymbolicName); } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java index 46a35b07ea7..e57af606b3a 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java @@ -1,6 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.plugin.classanalysis; +import com.yahoo.api.annotations.PublicApi; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; import org.apache.maven.artifact.versioning.ArtifactVersion; @@ -28,6 +29,7 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { private String name = null; private final Set<String> imports = new HashSet<>(); private Optional<ExportPackageAnnotation> exportPackageAnnotation = Optional.empty(); + private boolean isPublicApi = false; private final Optional<ArtifactVersion> defaultExportPackageVersion; @@ -159,6 +161,9 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (ExportPackage.class.getName().equals(Type.getType(desc).getClassName())) { return visitExportPackage(); + } if (PublicApi.class.getName().equals(Type.getType(desc).getClassName())) { + isPublicApi = true; + return null; } else { if (visible) { addImportWithTypeDesc(desc); @@ -169,7 +174,8 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { ClassFileMetaData result() { assert (!imports.contains("int")); - return new ClassFileMetaData(name, imports, exportPackageAnnotation); + var packageInfo = new PackageInfo(Packages.packageName(name), exportPackageAnnotation, isPublicApi); + return new ClassFileMetaData(name, imports, packageInfo); } } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java index 5601430a27f..7e2f59c1e4d 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java @@ -14,12 +14,12 @@ public class ClassFileMetaData { private final String name; private final Set<String> referencedClasses; - private final Optional<ExportPackageAnnotation> exportPackage; + private final PackageInfo packageInfo; - public ClassFileMetaData(String name, Set<String> referencedClasses, Optional<ExportPackageAnnotation> exportPackage) { + public ClassFileMetaData(String name, Set<String> referencedClasses, PackageInfo packageInfo) { this.name = name; this.referencedClasses = referencedClasses; - this.exportPackage = exportPackage; + this.packageInfo = packageInfo; } public String getName() { @@ -30,8 +30,16 @@ public class ClassFileMetaData { return referencedClasses; } + public PackageInfo packageInfo() { + return packageInfo; + } + public Optional<ExportPackageAnnotation> getExportPackage() { - return exportPackage; + return packageInfo.exportPackage(); + } + + public boolean isPublicApi() { + return packageInfo.isPublicApi(); } } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ExportPackageAnnotation.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ExportPackageAnnotation.java index 7f3fb9522f7..517a59a5a06 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ExportPackageAnnotation.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ExportPackageAnnotation.java @@ -26,7 +26,7 @@ public class ExportPackageAnnotation { requireNonNegative(major, "major"); requireNonNegative(minor, "minor"); requireNonNegative(micro, "micro"); - if (QUALIFIER_PATTERN.matcher(qualifier).matches() == false) { + if (! QUALIFIER_PATTERN.matcher(qualifier).matches()) { throw new IllegalArgumentException( exportPackageError(String.format("qualifier must follow the format (alpha|digit|'_'|'-')* but was '%s'.", qualifier))); } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java new file mode 100644 index 00000000000..c19320b8e98 --- /dev/null +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java @@ -0,0 +1,16 @@ +package com.yahoo.container.plugin.classanalysis; + +import java.util.Optional; + +/** + * The package + * + * @author gjoranv + */ +record PackageInfo(String name, Optional<ExportPackageAnnotation> exportPackage, boolean isPublicApi) { + + PackageInfo hasExportPackageOrElse(PackageInfo other) { + return exportPackage().isPresent() ? this : other; + } + +} diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java index e2de90a6463..51fba228b41 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java @@ -17,16 +17,17 @@ import java.util.stream.Collectors; * @author ollivir */ public class PackageTally { - private final Map<String, Optional<ExportPackageAnnotation>> definedPackagesMap; + + private final Map<String, PackageInfo> definedPackages; private final Set<String> referencedPackagesUnfiltered; - PackageTally(Map<String, Optional<ExportPackageAnnotation>> definedPackagesMap, Set<String> referencedPackagesUnfiltered) { - this.definedPackagesMap = definedPackagesMap; + PackageTally(Map<String, PackageInfo> definedPackages, Set<String> referencedPackagesUnfiltered) { + this.definedPackages = definedPackages; this.referencedPackagesUnfiltered = referencedPackagesUnfiltered; } public Set<String> definedPackages() { - return definedPackagesMap.keySet(); + return definedPackages.keySet(); } public Set<String> referencedPackages() { @@ -35,12 +36,19 @@ public class PackageTally { public Map<String, ExportPackageAnnotation> exportedPackages() { Map<String, ExportPackageAnnotation> ret = new HashMap<>(); - definedPackagesMap.forEach((k, v) -> { - v.ifPresent(annotation -> ret.put(k, annotation)); + definedPackages.forEach((pkg, pkgInfo) -> { + pkgInfo.exportPackage().ifPresent(a -> ret.put(pkg, a)); }); return ret; } + public Set<String> publicApiPackages() { + return definedPackages.values().stream() + .filter(PackageInfo::isPublicApi) + .map(PackageInfo::name) + .collect(Collectors.toSet()); + } + /** * Returns the set of packages that is referenced from this tally, but not included in the given set of available packages. * @@ -58,36 +66,37 @@ public class PackageTally { * Represents the classes for two package tallies that are deployed as a single unit. * <p> * ExportPackageAnnotations from this has precedence over the other. + * TODO: Add unit test and try using Map.merge (as in the functions below). Can't see how Maps.combine is any different. */ public PackageTally combine(PackageTally other) { - Map<String, Optional<ExportPackageAnnotation>> map = Maps.combine(this.definedPackagesMap, other.definedPackagesMap, - (l, r) -> l.isPresent() ? l : r); + var definedPkgs = Maps.combine(this.definedPackages, other.definedPackages, PackageInfo::hasExportPackageOrElse); Set<String> referencedPkgs = new HashSet<>(this.referencedPackagesUnfiltered); referencedPkgs.addAll(other.referencedPackagesUnfiltered); - return new PackageTally(map, referencedPkgs); + return new PackageTally(definedPkgs, referencedPkgs); } public static PackageTally combine(Collection<PackageTally> packageTallies) { - Map<String, Optional<ExportPackageAnnotation>> map = new HashMap<>(); + var definedPkgs = new HashMap<String, PackageInfo>(); Set<String> referencedPkgs = new HashSet<>(); - for (PackageTally pt : packageTallies) { - pt.definedPackagesMap.forEach((k, v) -> map.merge(k, v, (l, r) -> l.isPresent() ? l : r)); - referencedPkgs.addAll(pt.referencedPackagesUnfiltered); + for (PackageTally tally : packageTallies) { + tally.definedPackages.forEach((pkg, info) -> definedPkgs.merge(pkg, info, PackageInfo::hasExportPackageOrElse)); + referencedPkgs.addAll(tally.referencedPackagesUnfiltered); } - return new PackageTally(map, referencedPkgs); + return new PackageTally(definedPkgs, referencedPkgs); } public static PackageTally fromAnalyzedClassFiles(Collection<ClassFileMetaData> analyzedClassFiles) { - Map<String, Optional<ExportPackageAnnotation>> map = new HashMap<>(); - Set<String> referencedPkgs = new HashSet<>(); + var definedPkgs = new HashMap<String, PackageInfo>(); + var referencedPkgs = new HashSet<String>(); - for (ClassFileMetaData metaData : analyzedClassFiles) { - String packageName = Packages.packageName(metaData.getName()); - map.merge(packageName, metaData.getExportPackage(), (l, r) -> l.isPresent() ? l : r); - metaData.getReferencedClasses().forEach(className -> referencedPkgs.add(Packages.packageName(className))); + for (ClassFileMetaData classData : analyzedClassFiles) { + var pkgName = classData.packageInfo().name(); + definedPkgs.merge(pkgName, classData.packageInfo(), PackageInfo::hasExportPackageOrElse); + classData.getReferencedClasses().forEach(className -> referencedPkgs.add(Packages.packageName(className))); } - return new PackageTally(map, referencedPkgs); + return new PackageTally(definedPkgs, referencedPkgs); } + } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Packages.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Packages.java index 9eef8a55c01..48a128c2f0d 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Packages.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/Packages.java @@ -1,8 +1,13 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.plugin.classanalysis; +import com.yahoo.container.plugin.osgi.ImportPackages; + import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Utility methods related to packages. @@ -31,6 +36,22 @@ public class Packages { } } + /** + * Returns the imported Vespa packages that don't exist in the given set of allowed packages. + */ + public static List<String> disallowedVespaImports(Map<String, ImportPackages.Import> imports, List<String> allowed) { + if (imports == null || imports.isEmpty()) return List.of(); + + var publicApi = allowed == null ? Set.of() : new HashSet<>(allowed); + + Set<String> yahooImports = imports.keySet().stream() + .filter(pkg -> pkg.startsWith("com.yahoo") || pkg.startsWith("ai.vespa.")) + .collect(Collectors.toSet()); + + List<String> disallowedImports = yahooImports.stream().collect(Collectors.groupingBy(publicApi::contains)).get(false); + return disallowedImports == null ? List.of() : disallowedImports; + } + public static PackageMetaData analyzePackages(Set<ClassFileMetaData> allClasses) { Set<String> definedPackages = new HashSet<>(); Set<String> referencedPackages = new HashSet<>(); diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AssembleContainerPluginMojo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AssembleContainerPluginMojo.java index a1d3cd13b3a..bb2d61932f3 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AssembleContainerPluginMojo.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/mojo/AssembleContainerPluginMojo.java @@ -25,7 +25,7 @@ import java.util.jar.JarFile; */ @Mojo(name = "assemble-container-plugin", requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true) public class AssembleContainerPluginMojo extends AbstractAssembleBundleMojo { - private static enum Dependencies { + private enum Dependencies { WITH, WITHOUT } 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 f5d3259c537..d217273e42b 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 @@ -26,6 +26,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static com.yahoo.container.plugin.bundle.AnalyzeBundle.exportedPackagesAggregated; +import static com.yahoo.container.plugin.bundle.AnalyzeBundle.publicApiPackagesAggregated; +import static com.yahoo.container.plugin.classanalysis.Packages.disallowedVespaImports; 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; @@ -38,6 +40,14 @@ import static com.yahoo.container.plugin.util.Files.allDescendantFiles; @Mojo(name = "generate-osgi-manifest", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true) public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { + private enum BundleType { + CORE, // up to container-dev + INTERNAL, // other vespa bundles (need not be set for groupId 'com.yahoo.vespa') + USER + } + + private static final String VESPA_GROUP_ID = "com.yahoo.vespa"; + @Parameter private String discApplicationClass = null; @@ -56,6 +66,19 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { @Parameter(alias = "Main-Class") private String mainClass = null; + @Parameter(alias = "Bundle-Type") + private BundleType bundleType = BundleType.USER; + + @Parameter(defaultValue = "false") + private boolean suppressWarningMissingImportPackages; + @Parameter(defaultValue = "false") + private boolean suppressWarningPublicApi; + @Parameter(defaultValue = "false") + private boolean suppressWarningOverlappingPackages; + + @Parameter(defaultValue = "false") + private boolean failOnWarnings; + @Parameter(defaultValue = "false") private boolean buildLegacyVespaPlatformBundle; @@ -69,10 +92,12 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { if (! isContainerDiscArtifact(project.getArtifact())) throwIfInternalContainerArtifactsAreIncluded(artifactSet.getJarArtifactsToInclude()); - List<Export> exportedPackagesFromProvidedJars = exportedPackagesAggregated( - artifactSet.getJarArtifactsProvided().stream().map(Artifact::getFile).toList()); + List<Artifact> providedJarArtifacts = artifactSet.getJarArtifactsProvided(); + List<File> providedJarFiles = providedJarArtifacts.stream().map(Artifact::getFile).toList(); + List<Export> exportedPackagesFromProvidedJars = exportedPackagesAggregated(providedJarFiles); + List<String> publicApiPackagesFromProvidedJars = publicApiPackagesAggregated(providedJarFiles); - // Packages from Export-Package headers in provided scoped jars + // Packages from Export-Package/PublicApi headers in provided scoped jars Set<String> exportedPackagesFromProvidedDeps = ExportPackages.packageNames(exportedPackagesFromProvidedJars); // Packaged defined in this project's code @@ -86,12 +111,12 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { logDebugPackageSets(exportedPackagesFromProvidedJars, includedPackages); - if (hasJdiscCoreProvided(artifactSet.getJarArtifactsProvided())) { + if (hasJdiscCoreProvided(providedJarArtifacts)) { // jdisc_core being provided guarantees that log output does not contain its exported packages logMissingPackages(exportedPackagesFromProvidedDeps, projectPackages, compileJarsPackages, includedPackages); - } else { - getLog().warn("This project does not have jdisc_core as provided dependency, so the " + - "generated 'Import-Package' OSGi header may be missing important packages."); + } else if (! suppressWarningMissingImportPackages) { + warnOrThrow(("This project does not have '%s' as provided dependency, so the generated 'Import-Package' " + + "OSGi header may be missing important packages.").formatted(wantedProvidedDependency())); } logOverlappingPackages(projectPackages, exportedPackagesFromProvidedDeps); logUnnecessaryPackages(compileJarsPackages, exportedPackagesFromProvidedDeps); @@ -100,9 +125,12 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { includedPackages.definedPackages(), exportsByPackageName(exportedPackagesFromProvidedJars)); + List<String> nonPublicApiUsed = disallowedVespaImports(calculatedImports, publicApiPackagesFromProvidedJars); + logNonPublicApiUsage(nonPublicApiUsed); Map<String, String> manifestContent = generateManifestContent(artifactSet.getJarArtifactsToInclude(), calculatedImports, includedPackages); - addAdditionalManifestProperties(manifestContent); + addAdditionalManifestProperties(manifestContent, includedPackages); + addManifestPropertiesForUserBundles(manifestContent, nonPublicApiUsed); createManifestFile(Paths.get(project.getBuild().getOutputDirectory()), manifestContent); } catch (Exception e) { @@ -110,7 +138,21 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { } } - private void addAdditionalManifestProperties(Map<String, String> manifestContent) { + private String wantedProvidedDependency() { + return switch (effectiveBundleType()) { + case CORE -> "jdisc_core"; + case INTERNAL -> "container-dev"; + case USER -> "container"; + }; + } + + private BundleType effectiveBundleType() { + if (bundleType != BundleType.USER) return bundleType; + return isVespaInternalGroupId(project.getGroupId()) ? BundleType.INTERNAL : BundleType.USER; + } + + private void addAdditionalManifestProperties(Map<String, String> manifestContent, PackageTally includedPackages) { + addIfNotEmpty(manifestContent, "X-JDisc-PublicApi-Package", publicApi(includedPackages)); addIfNotEmpty(manifestContent, "Bundle-Activator", bundleActivator); addIfNotEmpty(manifestContent, "X-JDisc-Privileged-Activator", jdiscPrivilegedActivator); addIfNotEmpty(manifestContent, "Main-Class", mainClass); @@ -119,6 +161,20 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { addIfNotEmpty(manifestContent, "WebInfUrl", webInfUrl); } + private void addManifestPropertiesForUserBundles(Map<String, String> manifestContent, List<String> nonPublicApiUsed) { + if (effectiveBundleType() != BundleType.USER) return; + addIfNotEmpty(manifestContent, "X-JDisc-Non-PublicApi-Import-Package", String.join(",", nonPublicApiUsed)); + } + + private void logNonPublicApiUsage(List<String> nonPublicApiUsed) { + if (suppressWarningPublicApi || effectiveBundleType() != BundleType.USER || nonPublicApiUsed.isEmpty()) return; + warnOrThrow("This project uses packages that are not part of Vespa's public api: %s".formatted(nonPublicApiUsed)); + } + + private static String publicApi(PackageTally tally) { + return tally.publicApiPackages().stream().sorted().collect(Collectors.joining(",")); + } + private void logDebugPackageSets(List<Export> exportedPackagesFromProvidedJars, PackageTally includedPackages) { if (getLog().isDebugEnabled()) { getLog().debug("Referenced packages = " + includedPackages.referencedPackages()); @@ -154,10 +210,12 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { private void logOverlappingPackages(PackageTally projectPackages, Set<String> exportedPackagesFromProvidedDeps) { + if (suppressWarningOverlappingPackages) return; + Set<String> overlappingProjectPackages = Sets.intersection(projectPackages.definedPackages(), exportedPackagesFromProvidedDeps); if (! overlappingProjectPackages.isEmpty()) { - getLog().warn("This project defines packages that are also defined in provided scoped dependencies " + - "(overlapping packages are strongly discouraged): " + overlappingProjectPackages); + warnOrThrow("This project defines packages that are also defined in provided scoped dependencies " + + "(overlapping packages are strongly discouraged): " + overlappingProjectPackages); } } @@ -184,9 +242,8 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { List<Artifact> unsupportedArtifacts = nonJarArtifacts.stream().filter(a -> ! a.getType().equals("pom")) .toList(); - unsupportedArtifacts.forEach(artifact -> getLog() - .warn(String.format("Unsupported artifact '%s': Type '%s' is not supported. Please file a feature request.", - artifact.getId(), artifact.getType()))); + unsupportedArtifacts.forEach(artifact -> warnOrThrow(String.format("Unsupported artifact '%s': Type '%s' is not supported. Please file a feature request.", + artifact.getId(), artifact.getType()))); } private void throwIfInternalContainerArtifactsAreIncluded(Collection<Artifact> includedArtifacts) throws MojoExecutionException { @@ -201,12 +258,18 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { } } + private boolean isVespaInternalGroupId(String groupId) { + return groupId.equals(VESPA_GROUP_ID) + || groupId.equals(VESPA_GROUP_ID + ".hosted") + || groupId.equals(VESPA_GROUP_ID + ".hosted.controller"); + } + private boolean isJdiscComponentArtifact(Artifact a) { - return a.getArtifactId().equals("component") && a.getGroupId().equals("com.yahoo.vespa"); + return a.getArtifactId().equals("component") && a.getGroupId().equals(VESPA_GROUP_ID); } private boolean isContainerDiscArtifact(Artifact a) { - return a.getArtifactId().equals("container-disc") && a.getGroupId().equals("com.yahoo.vespa"); + return a.getArtifactId().equals("container-disc") && a.getGroupId().equals(VESPA_GROUP_ID); } private PackageTally getProjectClassesTally() { @@ -219,4 +282,13 @@ public class GenerateOsgiManifestMojo extends AbstractGenerateOsgiManifestMojo { return PackageTally.fromAnalyzedClassFiles(analyzedClasses); } + + private void warnOrThrow(String... messages){ + String message = String.join("\n", messages); + if (failOnWarnings) { + throw new RuntimeException(message); + } + getLog().warn(message); + } + } diff --git a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java index 9a7aade7ffb..11fe4a14d74 100644 --- a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java +++ b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java @@ -3,28 +3,27 @@ package com.yahoo.container.plugin.classanalysis; import com.yahoo.container.plugin.classanalysis.sampleclasses.Base; import com.yahoo.container.plugin.classanalysis.sampleclasses.ClassAnnotation; -import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.Derived; import com.yahoo.container.plugin.classanalysis.sampleclasses.DummyAnnotation; -import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleDummyAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.Fields; import com.yahoo.container.plugin.classanalysis.sampleclasses.Interface1; import com.yahoo.container.plugin.classanalysis.sampleclasses.Interface2; -import com.yahoo.container.plugin.classanalysis.sampleclasses.RecordWithOverride; -import com.yahoo.container.plugin.classanalysis.sampleclasses.SwitchStatement; +import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleAnnotation; +import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleDummyAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.MethodAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.MethodInvocation; +import com.yahoo.container.plugin.classanalysis.sampleclasses.RecordWithOverride; +import com.yahoo.container.plugin.classanalysis.sampleclasses.SwitchStatement; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; import org.junit.jupiter.api.Test; import javax.security.auth.login.LoginException; -import java.awt.Image; +import java.awt.*; import java.awt.image.ImagingOpException; import java.awt.image.Kernel; import java.util.List; import java.util.Optional; -import java.util.Set; import static com.yahoo.container.plugin.classanalysis.TestUtilities.analyzeClass; import static com.yahoo.container.plugin.classanalysis.TestUtilities.classFile; @@ -133,7 +132,12 @@ public class AnalyzeClassTest { @Test void export_annotations_are_processed() { assertEquals(Optional.of(new ExportPackageAnnotation(3, 1, 4, "TEST_QUALIFIER-2")), - Analyze.analyzeClass(classFile("com.yahoo.container.plugin.classanalysis.sampleclasses.package-info")).getExportPackage()); + Analyze.analyzeClass(classFile("com.yahoo.container.plugin.classanalysis.sampleclasses.package-info")).getExportPackage()); + } + + @Test + void publicApi_annotations_are_processed() { + assertTrue(Analyze.analyzeClass(classFile("com.yahoo.container.plugin.classanalysis.sampleclasses.package-info")).isPublicApi()); } @Test diff --git a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java index d0d1db97c26..5f69032db17 100644 --- a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java +++ b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java @@ -1,6 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. @ExportPackage(version = @Version(major = 3, minor = 1, micro = 4, qualifier = "TEST_QUALIFIER-2")) +@PublicApi package com.yahoo.container.plugin.classanalysis.sampleclasses; +import com.yahoo.api.annotations.PublicApi; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; |