You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2024/06/07 13:06:56 UTC

(sling-org-apache-sling-feature-analyser) branch issue/SKYOPS-12351 created (now 3884902)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a change to branch issue/SKYOPS-12351
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git


      at 3884902  SLING-12351 - Create a default implementation for generating the analyser-metadata extension

This branch includes the following new commits:

     new 3884902  SLING-12351 - Create a default implementation for generating the analyser-metadata extension

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(sling-org-apache-sling-feature-analyser) 01/01: SLING-12351 - Create a default implementation for generating the analyser-metadata extension

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch issue/SKYOPS-12351
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git

commit 38849023b2e976d91144b0c07d44079509094a43
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Fri Jun 7 15:06:42 2024 +0200

    SLING-12351 - Create a default implementation for generating the analyser-metadata extension
---
 pom.xml                                            |   1 +
 readme.md                                          |  35 ++++++
 .../extensions/AnalyserMetaDataHandler.java        | 136 +++++++++++++++++++++
 ...apache.sling.feature.builder.PostProcessHandler |   1 +
 .../extensions/AnalyserMetaDataHandlerTest.java    |  80 ++++++++++++
 .../analyse-metadata/feature-expected-output.json  |  97 +++++++++++++++
 .../resources/analyse-metadata/feature-input.json  |  52 ++++++++
 7 files changed, 402 insertions(+)

diff --git a/pom.xml b/pom.xml
index d8cd88c..146539e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,7 @@
                         <exclude>src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask</exclude>
                         <exclude>src/main/resources/META-INF/services/org.apache.sling.feature.scanner.spi.ExtensionScanner</exclude>
                         <exclude>src/main/resources/META-INF/services/org.apache.sling.feature.scanner.spi.FrameworkScanner</exclude>
+                        <exclude>src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler</exclude>
                         <exclude>src/test/resources/origins/**</exclude>
                         <exclude>src/test/resources/test-bundle-src/**</exclude>
                         <exclude>src/test/resources/**.xml</exclude>
diff --git a/readme.md b/readme.md
index 274db66..7530b1f 100644
--- a/readme.md
+++ b/readme.md
@@ -109,3 +109,38 @@ Checks the syntax of all repoinit sections.
 ## `requirements-capabilities`
 
 Checks bundle requirements/capabilities for consistency and completeness.
+
+# Extensions
+
+## `analyser-metadata`
+
+Generates additional metadata that will be recorded in the feature model definition. It is configured by defining an `analyser-metadata` section in the feature model definition. The section will be processed by the extension when the feature models are aggregated and will be replaced with the required entries for bundles matching the configuration.
+
+The section can have entries that match individual bundle names and entries that match based on regular expressions (if the key contains the "*" character).
+
+Each individual entry can contain the following keys:
+
+
+Configuration key | Allowed values | Description
+ ----- | ----- | -----
+`manifest` | `null` or Object | If null, the manifest is not generated. If an object, the values are copied over. If absent, the values are extracted from the OSGi bundle
+`report` | Object with keys `warning` and `error` | If any of the values are set to `false`, reporting is suppressed for those kind of occurences.
+
+A typical configuration for platform applications is:
+
+```javascript
+{
+    "analyser-metadata:JSON|true":
+    {
+      ".*" : {
+        "manifest": null,
+        "report": {
+          "error": false,
+          "warning": false
+        }
+      }
+    }
+}
+```
+
+This ensures that warnings related to the platform are not reported when the feature is aggregated with downstream (consumer) applications. The manifests should not be inlined under normal circumstances, since it greatly increases the size of the resulting features.
diff --git a/src/main/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataHandler.java b/src/main/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataHandler.java
new file mode 100644
index 0000000..830bc7b
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataHandler.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.feature.analyser.extensions;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.jar.JarFile;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionState;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.HandlerContext;
+import org.apache.sling.feature.builder.PostProcessHandler;
+import org.apache.sling.feature.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.JsonValue;
+
+public class AnalyserMetaDataHandler implements PostProcessHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(AnalyserMetaDataHandler.class);
+    
+    private static final String MANIFEST_KEY = "manifest";
+
+    @Override
+    public void postProcess(HandlerContext handlerContext, Feature feature, Extension extension) {
+        if (AnalyserMetaDataExtension.EXTENSION_NAME.equals(extension.getName())) {
+            LOG.debug("Handling analyser-metadata extension {}", extension);
+            JsonObject extensionJSONStructure = extension.getJSONStructure().asJsonObject();
+            JsonObjectBuilder result = Json.createObjectBuilder();
+            Map<String, JsonValue> directEntries = new HashMap<>();
+            Map<String, JsonValue> wildcardEntries = new LinkedHashMap<>();
+            extensionJSONStructure.entrySet().forEach(
+                    entry -> {
+                        if (entry.getKey().contains("*")) {
+                            wildcardEntries.put(entry.getKey(), entry.getValue());
+                        } else {
+                            directEntries.put(entry.getKey(), entry.getValue());
+                        }
+                    }
+            );
+
+            feature.getBundles().stream().forEach(
+                    bundle ->
+                        findFirst(directEntries, wildcardEntries, bundle.getId()).ifPresent(
+                             json -> {
+                                 if (nullManifest(json)) {
+                                     JsonObjectBuilder wrapper = Json.createObjectBuilder(json);
+                                     wrapper.remove(MANIFEST_KEY);
+                                     result.add(bundle.getId().toMvnId(), wrapper);
+                                 } else if (noManifest(json)) {
+                                     JsonObjectBuilder wrapper = Json.createObjectBuilder(json);
+                                     getManifest(handlerContext, bundle.getId()).ifPresent(manifest ->
+                                            wrapper.add(MANIFEST_KEY, manifest));
+                                     result.add(bundle.getId().toMvnId(), wrapper);
+                                 } else {
+                                     result.add(bundle.getId().toMvnId(), json);
+                                 }
+                             }
+                        )
+            );
+
+            feature.getExtensions().remove(extension);
+
+            // Mark the extension as optional now that we've processed it.
+            Extension newEx = new Extension(ExtensionType.JSON, extension.getName(), ExtensionState.OPTIONAL);
+            newEx.setJSONStructure(result.build());
+            feature.getExtensions().add(newEx);
+        }
+    }
+
+    private boolean noManifest(JsonObject object) {
+        return manifest(object, null) && !object.getBoolean("no-manifest", false);
+    }
+
+    private boolean nullManifest(JsonObject object) {
+        return manifest(object, JsonValue.NULL);
+    }
+
+    private boolean manifest(JsonObject object, Object match) {
+        return object.get(MANIFEST_KEY) == match;
+    }
+
+    private Optional<JsonObject> findFirst(Map<String, JsonValue> directValues, Map<String, JsonValue> wildcardValues, ArtifactId bundle) {
+        JsonValue direct = directValues.get(bundle.toMvnId());
+        if (direct != null && direct != JsonValue.NULL) {
+            return Optional.of(direct.asJsonObject());
+        }
+        return wildcardValues.entrySet().stream()
+                .filter(entry -> bundle.toMvnId().matches(entry.getKey()))
+                .filter(entry -> entry.getValue() != JsonValue.NULL)
+                .map(entry -> entry.getValue().asJsonObject())
+                .findFirst();
+    }
+
+    private Optional<JsonObject> getManifest(HandlerContext handlerContext, ArtifactId bundle) {
+        URL url = handlerContext.getArtifactProvider().provide(bundle);
+        try (JarFile jarFile = IOUtils.getJarFileFromURL(url, false, null)) {
+            return Optional.ofNullable(jarFile.getManifest())
+                    .map(manifest -> {
+                        JsonObjectBuilder manifestBuilder = Json.createObjectBuilder();
+                        manifest.getMainAttributes().entrySet().stream()
+                                .forEachOrdered(entry -> manifestBuilder.add(entry.getKey().toString(), (String) entry.getValue()));
+
+                        return manifestBuilder.build();
+                    });
+        } catch (IOException ex) {
+            LOG.error("Unable to parse manifest of: " + bundle, ex);
+            throw new UncheckedIOException(ex);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler b/src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler
new file mode 100644
index 0000000..84c826b
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.builder.PostProcessHandler
@@ -0,0 +1 @@
+org.apache.sling.feature.analyser.extensions.AnalyserMetaDataHandler
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataHandlerTest.java b/src/test/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataHandlerTest.java
new file mode 100644
index 0000000..9e4a668
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataHandlerTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.feature.analyser.extensions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UncheckedIOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.ArtifactProvider;
+import org.apache.sling.feature.builder.HandlerContext;
+import org.apache.sling.feature.io.json.FeatureJSONReader;
+import org.apache.sling.feature.io.json.FeatureJSONWriter;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class AnalyserMetaDataHandlerTest {
+
+    @Test
+    public void testMetaDataHandler() throws Exception {
+        URL url = getClass().getResource("/analyse-metadata/feature-input.json");
+
+        Feature feature;
+        try (Reader r = new InputStreamReader(url.openStream())) {
+            feature = FeatureJSONReader.read(r, url.toString());
+        }
+
+        assertNotNull(feature);
+
+        HandlerContext ctx = Mockito.mock(HandlerContext.class);
+        ArtifactProvider provider = artifactId -> {
+            try {
+                return new URL("https://repo1.maven.org/maven2/" + artifactId.toMvnPath());
+            } catch (MalformedURLException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+
+        Mockito.when(ctx.getArtifactProvider()).thenReturn(provider);
+
+        new AnalyserMetaDataHandler().
+            postProcess(ctx, feature, feature.getExtensions().getByName("analyser-metadata"));
+
+        URL expectedURL = getClass().getResource("/analyse-metadata/feature-expected-output.json");
+
+        Feature expected;
+        try (Reader r = new InputStreamReader(expectedURL.openStream())) {
+            expected = FeatureJSONReader.read(r, expectedURL.toString());
+        }
+
+        StringWriter featureWriter = new StringWriter();
+        StringWriter expectedWriter = new StringWriter();
+
+        FeatureJSONWriter.write(featureWriter, feature);
+        FeatureJSONWriter.write(expectedWriter, expected);
+
+        assertEquals(expectedWriter.toString(), featureWriter.toString());
+    }
+
+}
diff --git a/src/test/resources/analyse-metadata/feature-expected-output.json b/src/test/resources/analyse-metadata/feature-expected-output.json
new file mode 100644
index 0000000..871af93
--- /dev/null
+++ b/src/test/resources/analyse-metadata/feature-expected-output.json
@@ -0,0 +1,97 @@
+{
+  "id": "org.acme:acmefeature:slingosgifeature:metadata-feature:0.0.1",
+  "bundles": [
+    "org.apache.sling:org.apache.sling.commons.log:5.1.10",
+    "org.apache.sling:org.apache.sling.commons.logservice:1.0.6",
+    "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.apache.sling:org.apache.sling.commons.log:5.1.10": {
+      "manifest" : {
+        "Manifest-Version": "1.0",
+        "Bnd-LastModified": "1536309799779",
+        "Build-Jdk": "1.8.0_171",
+        "Built-By": "robert",
+        "Bundle-Activator": "org.apache.sling.commons.log.logback.internal.Activator",
+        "Bundle-Category": "sling",
+        "Bundle-ClassPath": ".,logback-core-1.2.3.jar,logback-classic-1.2.3.jar",
+        "Bundle-Description": "This bundle embeds Logback which provides the SLF4J logging API.    The embedding supports dynamic OSGi-configuration without    requiring to edit some global filesystem based XML file.",
+        "Bundle-DocURL": "http://sling.apache.org/site/logging.html",
+        "Bundle-License": "https://www.apache.org/licenses/LICENSE-2.0.txt",
+        "Bundle-ManifestVersion": "2",
+        "Bundle-Name": "Apache Sling Commons Log",
+        "Bundle-RequiredExecutionEnvironment": "JavaSE-1.8",
+        "Bundle-SymbolicName": "org.apache.sling.commons.log",
+        "Bundle-Vendor": "The Apache Software Foundation",
+        "Bundle-Version": "5.1.10",
+        "Created-By": "Apache Maven Bundle Plugin",
+        "DynamicImport-Package": "org.osgi.service.cm;version=1.2,org.osgi.service.event;version=1.2,javax.xml.transform,javax.xml.transform.sax,javax.xml.transform.stream",
+        "Embed-Dependency": "jul-to-slf4j;inline=\"org/slf4j/bridge/SLF4JBridgeHandler.class\",logback-core,logback-classic",
+        "Embedded-Artifacts": "logback-core-1.2.3.jar;g=\"ch.qos.logback\";a=\"logback-core\";v=\"1.2.3\",logback-classic-1.2.3.jar;g=\"ch.qos.logback\";a=\"logback-classic\";v=\"1.2.3\"",
+        "Export-Package": "org.apache.sling.commons.log.logback;version=\"1.0.1\";uses:=\"org.xml.sax\",org.apache.sling.commons.log.logback.webconsole;version=\"1.0.1\",org.slf4j.impl;version=\"1.7.21\";uses:=\"org.slf4j,org.slf4j.spi\",ch.qos.logback.classic;version=\"1.2.3\";uses:=\"ch.qos.logback.classic.spi,ch.qos.logback.classic.turbo,ch.qos.logback.core,ch.qos.logback.core.pattern,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.slf4j,org.slf4j.event,org.slf4j.spi\",ch.qos.l [...]
+        "Import-Package": "org.osgi.framework;version=\"1.3\",org.slf4j;version=\"[1.6,1.8)\",org.slf4j.spi;version=\"[1.6,1.8)\",javax.management;resolution:=optional,javax.naming;resolution:=optional,javax.sql;resolution:=optional,javax.xml.parsers;resolution:=optional,org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,sun.reflect;resolution:=optional,ch.qos.logback.classic;version=\"[1.2,2)\",ch.qos.logback.classic.boolex;version=\"[1.2,2)\",ch.qos.logback.class [...]
+        "Require-Capability": "osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=1.8))\""
+      }
+    },
+    "org.slf4j:jcl-over-slf4j:1.7.25": {
+      "report":{
+        "error":false,
+        "warning":false
+      }
+    },
+    "org.slf4j:log4j-over-slf4j:1.7.25": {
+      "report":{
+        "error":false,
+        "warning":false
+      },
+      "manifest" : {
+        "Manifest-Version": "1.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": {
+      "report":{
+        "error":false,
+        "warning":false
+      },
+      "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
diff --git a/src/test/resources/analyse-metadata/feature-input.json b/src/test/resources/analyse-metadata/feature-input.json
new file mode 100644
index 0000000..07617fc
--- /dev/null
+++ b/src/test/resources/analyse-metadata/feature-input.json
@@ -0,0 +1,52 @@
+{
+  "id": "org.acme:acmefeature:slingosgifeature:metadata-feature:0.0.1",
+  "bundles": [
+    "org.apache.sling:org.apache.sling.commons.log:5.1.10",
+    "org.apache.sling:org.apache.sling.commons.logservice:1.0.6",
+    "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|true": {
+    "org.slf4j:jcl.*" : {
+      "manifest" : null,
+      "report" : {
+        "error" : false,
+        "warning" : false
+      }
+    },
+    "org.slf4j:.*" : {
+      "report" : {
+        "error" : false,
+        "warning" : false
+      }
+    },
+    "org.apache.sling:org.apache.sling.commons.log:5.1.10": {
+      "manifest" : {
+        "Manifest-Version": "1.0",
+        "Bnd-LastModified": "1536309799779",
+        "Build-Jdk": "1.8.0_171",
+        "Built-By": "robert",
+        "Bundle-Activator": "org.apache.sling.commons.log.logback.internal.Activator",
+        "Bundle-Category": "sling",
+        "Bundle-ClassPath": ".,logback-core-1.2.3.jar,logback-classic-1.2.3.jar",
+        "Bundle-Description": "This bundle embeds Logback which provides the SLF4J logging API.    The embedding supports dynamic OSGi-configuration without    requiring to edit some global filesystem based XML file.",
+        "Bundle-DocURL": "http://sling.apache.org/site/logging.html",
+        "Bundle-License": "https://www.apache.org/licenses/LICENSE-2.0.txt",
+        "Bundle-ManifestVersion": "2",
+        "Bundle-Name": "Apache Sling Commons Log",
+        "Bundle-RequiredExecutionEnvironment": "JavaSE-1.8",
+        "Bundle-SymbolicName": "org.apache.sling.commons.log",
+        "Bundle-Vendor": "The Apache Software Foundation",
+        "Bundle-Version": "5.1.10",
+        "Created-By": "Apache Maven Bundle Plugin",
+        "DynamicImport-Package": "org.osgi.service.cm;version=1.2,org.osgi.service.event;version=1.2,javax.xml.transform,javax.xml.transform.sax,javax.xml.transform.stream",
+        "Embed-Dependency": "jul-to-slf4j;inline=\"org/slf4j/bridge/SLF4JBridgeHandler.class\",logback-core,logback-classic",
+        "Embedded-Artifacts": "logback-core-1.2.3.jar;g=\"ch.qos.logback\";a=\"logback-core\";v=\"1.2.3\",logback-classic-1.2.3.jar;g=\"ch.qos.logback\";a=\"logback-classic\";v=\"1.2.3\"",
+        "Export-Package": "org.apache.sling.commons.log.logback;version=\"1.0.1\";uses:=\"org.xml.sax\",org.apache.sling.commons.log.logback.webconsole;version=\"1.0.1\",org.slf4j.impl;version=\"1.7.21\";uses:=\"org.slf4j,org.slf4j.spi\",ch.qos.logback.classic;version=\"1.2.3\";uses:=\"ch.qos.logback.classic.spi,ch.qos.logback.classic.turbo,ch.qos.logback.core,ch.qos.logback.core.pattern,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.slf4j,org.slf4j.event,org.slf4j.spi\",ch.qos.l [...]
+        "Import-Package": "org.osgi.framework;version=\"1.3\",org.slf4j;version=\"[1.6,1.8)\",org.slf4j.spi;version=\"[1.6,1.8)\",javax.management;resolution:=optional,javax.naming;resolution:=optional,javax.sql;resolution:=optional,javax.xml.parsers;resolution:=optional,org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,sun.reflect;resolution:=optional,ch.qos.logback.classic;version=\"[1.2,2)\",ch.qos.logback.classic.boolex;version=\"[1.2,2)\",ch.qos.logback.class [...]
+        "Require-Capability": "osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=1.8))\""
+      }
+    }
+  }
+}
\ No newline at end of file