This is an automated email from the ASF dual-hosted git repository. pauls pushed a commit to branch SLING-8481 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git
commit 91ec325ae56993b204b9bf06f11dd1046a354453 Author: Karl Pauls <[email protected]> AuthorDate: Thu Oct 8 14:12:22 2020 +0200 SLING-8481: add a caching extension for meta-data. --- .../org/apache/sling/feature/scanner/Scanner.java | 54 ++++++++++++--- .../feature/scanner/impl/BundleDescriptorImpl.java | 22 +++++-- .../scanner/impl/BundleDescriptorImplTest.java | 26 ++++++-- src/test/resources/metadata-feature.json | 76 ++++++++++++++++++++++ 4 files changed, 158 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/apache/sling/feature/scanner/Scanner.java b/src/main/java/org/apache/sling/feature/scanner/Scanner.java index 7373240..578010e 100644 --- a/src/main/java/org/apache/sling/feature/scanner/Scanner.java +++ b/src/main/java/org/apache/sling/feature/scanner/Scanner.java @@ -16,14 +16,12 @@ */ package org.apache.sling.feature.scanner; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.TreeMap; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.jar.Manifest; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -38,6 +36,9 @@ import org.apache.sling.feature.scanner.impl.FeatureDescriptorImpl; import org.apache.sling.feature.scanner.spi.ExtensionScanner; import org.apache.sling.feature.scanner.spi.FrameworkScanner; +import javax.json.JsonObject; +import javax.json.JsonValue; + /** * The scanner is a service that scans items and provides descriptions for * these. The following items can be scanned individually @@ -141,11 +142,14 @@ public class Scanner { BundleDescriptor desc = (BundleDescriptor) this.cache.get(key); if (desc == null) { final URL file = artifactProvider.provide(bundle.getId()); - if (file == null) { + if (bundle.getMetadata().containsKey("bundle-manifest")) { + Manifest mf = new Manifest(new ByteArrayInputStream(bundle.getMetadata().get("bundle-manifest").getBytes("UTF-8"))); + desc = new BundleDescriptorImpl(bundle, file, mf, startLevel); + } else if (file != null) { + desc = new BundleDescriptorImpl(bundle, file, startLevel); + } else { throw new IOException("Unable to find file for " + bundle.getId()); } - - desc = new BundleDescriptorImpl(bundle, file, startLevel); this.cache.put(key, desc); } return desc; @@ -176,6 +180,9 @@ public class Scanner { private void scanExtensions(final Feature f, final ContainerDescriptor desc) throws IOException { for (final Extension ext : f.getExtensions()) { + if (ext.getName().equals("analyser-metadata")) { + continue; + } ContainerDescriptor extDesc = null; for(final ExtensionScanner scanner : this.extensionScanners) { extDesc = scanner.scan(f, ext, this.artifactProvider); @@ -222,6 +229,7 @@ public class Scanner { if (desc == null) { desc = new FeatureDescriptorImpl(feature); + populateCache(feature); getBundleInfos(feature.getBundles(), desc); scanExtensions(feature, desc); @@ -234,6 +242,36 @@ public class Scanner { return desc; } + + private void populateCache(Feature feature) throws IOException { + Extension extension = feature.getExtensions().getByName("analyser-metadata"); + if (extension != null) { + JsonObject json = extension.getJSONStructure().asJsonObject(); + for (Map.Entry<String, JsonValue> entry : json.entrySet()) { + ArtifactId id = ArtifactId.fromMvnId(entry.getKey()); + if (feature.getBundles().containsExact(id)) { + Artifact bundle = feature.getBundles().getExact(id); + final String key = id.toMvnId().concat(":") + .concat(String.valueOf(bundle.getStartOrder())).concat(":") + .concat(Stream.of(bundle.getFeatureOrigins()).map(ArtifactId::toMvnId).collect(Collectors.joining(","))); + if (this.cache.get(key) == null) { + JsonObject headers = entry.getValue().asJsonObject(); + if (headers.containsKey("manifest")) { + final URL file = artifactProvider.provide(id); + Manifest manifest = new Manifest(); + JsonObject manifestHeaders = headers.getJsonObject("manifest"); + for (String name : manifestHeaders.keySet()) { + manifest.getMainAttributes().putValue(name, manifestHeaders.getString(name)); + } + BundleDescriptor desc = new BundleDescriptorImpl(bundle, file, manifest, bundle.getStartOrder()); + this.cache.put(key, desc); + } + } + } + } + } + } + /** * Scan a framework * diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java b/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java index 74cf932..641d269 100644 --- a/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java +++ b/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java @@ -62,19 +62,31 @@ public class BundleDescriptorImpl /** The corresponding artifact from the feature. */ private final Artifact artifact; + private static Manifest getManifest(URL file) throws IOException { + try (JarFile jarFile = IOUtils.getJarFileFromURL(file, true, null)) { + return jarFile.getManifest(); + } + } + public BundleDescriptorImpl(final Artifact a, final URL file, final int startLevel) throws IOException { + this(a, file, getManifest(file), startLevel); + } + + public BundleDescriptorImpl(final Artifact a, + final URL file, + final Manifest manifest, + final int startLevel) throws IOException { super(a.getId().toMvnId()); this.artifact = a; - this.artifactFile = file; this.startLevel = startLevel; - try (final JarFile jarFile = IOUtils.getJarFileFromURL(this.artifactFile, true, null)) { - this.manifest = jarFile.getManifest(); - } - if ( this.manifest == null ) { + this.artifactFile = file; + if ( manifest == null ) { throw new IOException("File has no manifest"); } + this.manifest = new Manifest(manifest); + this.analyze(); this.lock(); } diff --git a/src/test/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImplTest.java b/src/test/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImplTest.java index 1bdc342..c56d9c3 100644 --- a/src/test/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImplTest.java +++ b/src/test/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImplTest.java @@ -16,13 +16,7 @@ */ package org.apache.sling.feature.scanner.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.*; import java.net.URL; import java.util.Set; import java.util.jar.JarOutputStream; @@ -30,10 +24,16 @@ import java.util.jar.Manifest; import org.apache.sling.feature.Artifact; import org.apache.sling.feature.ArtifactId; +import org.apache.sling.feature.Feature; +import org.apache.sling.feature.io.json.FeatureJSONReader; +import org.apache.sling.feature.scanner.FeatureDescriptor; import org.apache.sling.feature.scanner.PackageInfo; +import org.apache.sling.feature.scanner.Scanner; import org.junit.Test; import org.osgi.framework.Version; +import static org.junit.Assert.*; + public class BundleDescriptorImplTest { @@ -61,6 +61,18 @@ public class BundleDescriptorImplTest assertPackageInfo(infos,"org.apache.felix", Version.parseVersion("2.0")); } + @Test + public void testBundleManifest() throws Exception { + Feature feature = FeatureJSONReader.read(new InputStreamReader(getClass().getResourceAsStream("/metadata-feature.json")), null); + Scanner scanner = new Scanner(artifactId -> null); + FeatureDescriptor descriptor = scanner.scan(feature); + assertEquals(feature.getBundles().size(), descriptor.getBundleDescriptors().size()); + assertNull(descriptor.getBundleDescriptors().iterator().next().getArtifactFile()); + assertEquals("2.0", descriptor.getBundleDescriptors().stream() + .filter(b -> b.getBundleSymbolicName().equals("log4j.over.slf4j")).findFirst().get() + .getManifest().getMainAttributes().getValue("Manifest-Version")); + } + private File createBundle(String manifest) throws IOException { File f = File.createTempFile("bundle", ".jar"); diff --git a/src/test/resources/metadata-feature.json b/src/test/resources/metadata-feature.json new file mode 100644 index 0000000..f0aa623 --- /dev/null +++ b/src/test/resources/metadata-feature.json @@ -0,0 +1,76 @@ +{ + "id": "org.acme:acmefeature:slingosgifeature:metadata-feature:0.0.1", + "bundles": [ + "org.slf4j:jcl-over-slf4j:1.7.25", + "org.slf4j:log4j-over-slf4j:1.7.25", + "org.slf4j:slf4j-api:1.7.25" + ], + "analyser-metadata:JSON|false": { + "org.slf4j:jcl-over-slf4j:1.7.25": { + "manifest" : { + "Manifest-Version": "1.0", + "Archiver-Version": "Plexus Archiver", + "Created-By": "Apache Maven", + "Built-By": "ceki", + "Build-Jdk": "1.7.0_17", + "Bundle-Description": "JCL 1.2 implemented over SLF4J", + "Bundle-Version": "1.7.25", + "Implementation-Version": "1.7.25", + "X-Compile-Source-JDK": "1.5", + "X-Compile-Target-JDK": "1.5", + "Implementation-Title": "jcl-over-slf4j", + "Bundle-ManifestVersion": "2", + "Bundle-SymbolicName": "jcl.over.slf4j", + "Bundle-Name": "jcl-over-slf4j", + "Bundle-Vendor": "SLF4J.ORG", + "Bundle-RequiredExecutionEnvironment": "J2SE-1.5", + "Export-Package": "org.apache.commons.logging;version=1.2, org.apache.commons.logging.impl;version=1.2", + "Import-Package": "org.slf4j;version=1.7.25, org.slf4j.spi;version=1.7.25" + } + }, + "org.slf4j:log4j-over-slf4j:1.7.25": { + "manifest" : { + "Manifest-Version": "2.0", + "Archiver-Version": "Plexus Archiver", + "Created-By": "Apache Maven", + "Built-By": "ceki", + "Build-Jdk": "1.7.0_17", + "Bundle-Description": "Log4j implemented over SLF4J", + "Bundle-Version": "1.7.25", + "Implementation-Version": "1.7.25", + "X-Compile-Source-JDK": "1.5", + "X-Compile-Target-JDK": "1.5", + "Implementation-Title": "log4j-over-slf4j", + "Bundle-ManifestVersion": "2", + "Bundle-SymbolicName": "log4j.over.slf4j", + "Bundle-Name": "log4j-over-slf4j", + "Bundle-Vendor": "SLF4J.ORG", + "Bundle-RequiredExecutionEnvironment": "J2SE-1.5", + "Export-Package": "org.apache.log4j;version=1.2.17,org.apache.log4j.helpers;version=1.2.17,org.apache.log4j.spi;version=1.2.17,org.apache.log4j.xml;version=1.2.17", + "Import-Package": "org.slf4j;version=1.6.0,org.slf4j.helpers;version=1.6.0,org.slf4j.spi;version=1.6.0" + } + }, + "org.slf4j:slf4j-api:1.7.25": { + "manifest" : { + "Manifest-Version": "1.0", + "Archiver-Version": "Plexus Archiver", + "Created-By": "Apache Maven", + "Built-By": "ceki", + "Build-Jdk": "1.7.0_17", + "Bundle-Description": "The slf4j API", + "Bundle-Version": "1.7.25", + "Implementation-Version": "1.7.25", + "X-Compile-Source-JDK": "1.5", + "X-Compile-Target-JDK": "1.5", + "Implementation-Title": "slf4j-api", + "Bundle-ManifestVersion": "2", + "Bundle-SymbolicName": "slf4j.api", + "Bundle-Name": "slf4j-api", + "Bundle-Vendor": "SLF4J.ORG", + "Bundle-RequiredExecutionEnvironment": "J2SE-1.5", + "Export-Package": "org.slf4j;version=1.7.25, org.slf4j.spi;version=1.7.25, org.slf4j.helpers;version=1.7.25, org.slf4j.event;version=1.7.25", + "Import-Package": "org.slf4j.impl;version=1.6.0" + } + } + } +} \ No newline at end of file
