You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by da...@apache.org on 2018/04/27 09:53:42 UTC

[sling-org-apache-sling-feature-analyser] 26/28: Use felix utils ResourceBuilder and Parser instead of the ManifestParser and ManifestUtil. As with that the feature-support module is empty, remove it.

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

davidb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git

commit d19b39dff76689d6af15fea159f4c8980fb5c19d
Author: Karl Pauls <kp...@adobe.com>
AuthorDate: Thu Apr 26 12:00:25 2018 +0200

    Use felix utils ResourceBuilder and Parser instead of the ManifestParser and ManifestUtil. As with that the feature-support module is empty, remove it.
---
 pom.xml                                            |   8 +-
 .../task/impl/CheckBundleExportsImports.java       |   2 +-
 .../task/impl/CheckRequirementsCapabilities.java   |  35 ++++---
 .../sling/feature/scanner/BundleDescriptor.java    |   1 -
 .../apache/sling/feature/scanner/Descriptor.java   |   1 -
 .../apache/sling/feature/scanner/PackageInfo.java  | 110 +++++++++++++++++++++
 .../feature/scanner/impl/BundleDescriptorImpl.java |  77 ++++++++++++---
 .../scanner/impl/FelixFrameworkScanner.java        |  76 +++++++-------
 .../scanner/impl/BundleDescriptorImplTest.java     |  73 ++++++++++++++
 .../scanner/impl/FelixFrameworkScannerTest.java    |  21 ++++
 10 files changed, 331 insertions(+), 73 deletions(-)

diff --git a/pom.xml b/pom.xml
index a2bca4b..0241695 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,7 +56,7 @@
                         <outputDirectory>${project.build.directory}/classes</outputDirectory>
                         <overWriteReleases>false</overWriteReleases>
                         <overWriteSnapshots>true</overWriteSnapshots>
-                        <includeArtifactIds>org.apache.felix.converter,org.apache.sling.feature,org.apache.sling.feature.support,org.apache.sling.commons.johnzon,org.apache.sling.commons.osgi,osgi.core,slf4j-api,slf4j-simple</includeArtifactIds>
+                        <includeArtifactIds>org.apache.felix.converter,org.apache.sling.feature,org.apache.sling.commons.johnzon,org.apache.sling.commons.osgi,osgi.core,slf4j-api,slf4j-simple</includeArtifactIds>
                     </configuration>
                 </execution>
             </executions>
@@ -126,12 +126,6 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.feature.support</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.osgi</artifactId>
             <version>2.4.0</version>
             <scope>provided</scope>
diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java
index 0fc5a00..6a44c97 100644
--- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java
+++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java
@@ -29,7 +29,7 @@ import java.util.TreeMap;
 import org.apache.sling.feature.analyser.task.AnalyserTask;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
 import org.apache.sling.feature.scanner.BundleDescriptor;
-import org.apache.sling.feature.support.util.PackageInfo;
+import org.apache.sling.feature.scanner.PackageInfo;
 import org.osgi.framework.Version;
 
 public class CheckBundleExportsImports implements AnalyserTask {
diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java
index daa0a91..bd1732f 100644
--- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java
+++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java
@@ -22,6 +22,7 @@ import org.apache.sling.feature.analyser.task.AnalyserTask;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
 import org.apache.sling.feature.scanner.ArtifactDescriptor;
 import org.apache.sling.feature.scanner.BundleDescriptor;
+import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Requirement;
 
 import java.util.ArrayList;
@@ -69,22 +70,30 @@ public class CheckRequirementsCapabilities implements AnalyserTask {
                 if (info.getRequirements() != null)
                 {
                     for (Requirement requirement : info.getRequirements()) {
-                        List<ArtifactDescriptor> candidates = getCandidates(artifacts, requirement);
+                        if (!BundleRevision.PACKAGE_NAMESPACE.equals(requirement.getNamespace()))
+                        {
+                            List<ArtifactDescriptor> candidates = getCandidates(artifacts, requirement);
 
-                        if (candidates.isEmpty()) {
-                            if ( "osgi.service".equals(requirement.getNamespace())  ){
-                                // osgi.service is special - we don't provide errors or warnings in this case
-                                continue;
+                            if (candidates.isEmpty())
+                            {
+                                if ("osgi.service".equals(requirement.getNamespace()))
+                                {
+                                    // osgi.service is special - we don't provide errors or warnings in this case
+                                    continue;
+                                }
+                                if (!RequirementImpl.isOptional(requirement))
+                                {
+                                    ctx.reportError(String.format(format, info.getArtifact().getId().getArtifactId(), info.getArtifact().getId().getVersion(), requirement.toString(), entry.getKey(), "no artifact is providing a matching capability in this start level."));
+                                }
+                                else
+                                {
+                                    ctx.reportWarning(String.format(format, info.getArtifact().getId().getArtifactId(), info.getArtifact().getId().getVersion(), requirement.toString(), entry.getKey(), "while the requirement is optional no artifact is providing a matching capability in this start level."));
+                                }
                             }
-                            if (!RequirementImpl.isOptional(requirement)) {
-                                ctx.reportError(String.format(format, info.getArtifact().getId().getArtifactId(), info.getArtifact().getId().getVersion(), requirement.toString(), entry.getKey(), "no artifact is providing a matching capability in this start level."));
+                            else if (candidates.size() > 1)
+                            {
+                                ctx.reportWarning(String.format(format, info.getArtifact().getId().getArtifactId(), info.getArtifact().getId().getVersion(), requirement.toString(), entry.getKey(), "there is more than one matching capability in this start level."));
                             }
-                            else {
-                                ctx.reportWarning(String.format(format, info.getArtifact().getId().getArtifactId(), info.getArtifact().getId().getVersion(), requirement.toString(), entry.getKey(), "while the requirement is optional no artifact is providing a matching capability in this start level."));
-                            }
-                        }
-                        else if ( candidates.size() > 1 ) {
-                            ctx.reportWarning(String.format(format, info.getArtifact().getId().getArtifactId(), info.getArtifact().getId().getVersion(), requirement.toString(), entry.getKey(), "there is more than one matching capability in this start level."));
                         }
                     }
                 }
diff --git a/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java b/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
index 748bec9..52f3a71 100644
--- a/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
+++ b/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
@@ -19,7 +19,6 @@ package org.apache.sling.feature.scanner;
 import java.util.jar.Manifest;
 
 import org.apache.sling.feature.scanner.impl.BundleDescriptorImpl;
-import org.apache.sling.feature.support.util.PackageInfo;
 
 /**
  * Information about a bundle
diff --git a/src/main/java/org/apache/sling/feature/scanner/Descriptor.java b/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
index a97cda0..2b5fc1b 100644
--- a/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
+++ b/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
@@ -20,7 +20,6 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.apache.sling.feature.support.util.PackageInfo;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 
diff --git a/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java b/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java
new file mode 100644
index 0000000..bb7081b
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java
@@ -0,0 +1,110 @@
+/*
+ * 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.scanner;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.VersionRange;
+
+public class PackageInfo implements Comparable<PackageInfo> {
+
+    private final boolean optional;
+    private final String name;
+    private final String version;
+
+    public PackageInfo(final String name, final String version, final boolean optional) {
+        this.name = name;
+        this.version = version;
+        this.optional = optional;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public boolean isOptional() {
+        return optional;
+    }
+
+    public Version getPackageVersion() {
+        if (this.version == null)
+            return null;
+
+        return new Version(this.version);
+    }
+
+    public VersionRange getPackageVersionRange() {
+        if (this.version == null)
+            return null;
+
+        return new VersionRange(this.version);
+    }
+
+    @Override
+    public String toString() {
+        return "Package " + name
+                + ";version=" + version
+                + (this.optional ? " (optional)" : "");
+    }
+
+    @Override
+    public int compareTo(final PackageInfo o) {
+        int result = this.name.compareTo(o.name);
+        if ( result == 0 ) {
+            result = this.version.compareTo(o.version);
+        }
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + (optional ? 1231 : 1237);
+        result = prime * result + ((version == null) ? 0 : version.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        PackageInfo other = (PackageInfo) obj;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (optional != other.optional)
+            return false;
+        if (version == null) {
+            if (other.version != null)
+                return false;
+        } else if (!version.equals(other.version))
+            return false;
+        return true;
+    }
+
+}
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 2f2c54b..d93b89c 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
@@ -18,14 +18,21 @@ package org.apache.sling.feature.scanner.impl;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
+import java.util.jar.JarFile;
 import java.util.jar.Manifest;
+import java.util.stream.Collectors;
 
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.felix.utils.resource.ResourceBuilder;
+import org.apache.felix.utils.resource.ResourceImpl;
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.scanner.BundleDescriptor;
-import org.apache.sling.feature.support.util.ManifestParser;
-import org.apache.sling.feature.support.util.ManifestUtil;
-import org.apache.sling.feature.support.util.PackageInfo;
+import org.apache.sling.feature.scanner.PackageInfo;
 import org.osgi.framework.Constants;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
@@ -60,8 +67,9 @@ public class BundleDescriptorImpl
         this.artifact = a;
         this.artifactFile = file;
         this.startLevel = startLevel;
-
-        this.manifest = ManifestUtil.getManifest(file);
+        try (final JarFile jarFile = new JarFile(this.artifactFile) ) {
+            this.manifest = jarFile.getManifest();
+        }
         if ( this.manifest == null ) {
             throw new IOException("File has no manifest");
         }
@@ -142,13 +150,14 @@ public class BundleDescriptorImpl
                 this.symbolicName = newBundleName;
             }
 
-            this.getExportedPackages().addAll(ManifestUtil.extractExportedPackages(this.manifest));
-            this.getImportedPackages().addAll(ManifestUtil.extractImportedPackages(this.manifest));
-            this.getDynamicImportedPackages().addAll(ManifestUtil.extractDynamicImportedPackages(this.manifest));
+            this.getExportedPackages().addAll(extractExportedPackages(this.manifest));
+            this.getImportedPackages().addAll(extractImportedPackages(this.manifest));
+            this.getDynamicImportedPackages().addAll(extractDynamicImportedPackages(this.manifest));
             try {
-                ManifestParser parser = new ManifestParser(this.manifest);
-                this.getCapabilities().addAll(ManifestUtil.extractCapabilities(parser));
-                this.getRequirements().addAll(ManifestUtil.extractRequirements(parser));
+                ResourceImpl resource = ResourceBuilder.build(null, this.manifest.getMainAttributes().entrySet().stream()
+                    .collect(Collectors.toMap(entry -> entry.getKey().toString(), entry -> entry.getValue().toString())));
+                this.getCapabilities().addAll(resource.getCapabilities(null));
+                this.getRequirements().addAll(resource.getRequirements(null));
             } catch (Exception ex) {
                 throw new IOException(ex);
             }
@@ -156,4 +165,50 @@ public class BundleDescriptorImpl
             throw new IOException("Unable to get bundle symbolic name from artifact " + getArtifact().getId().toMvnId());
         }
     }
+
+    public static List<PackageInfo> extractPackages(final Manifest m,
+        final String headerName,
+        final String defaultVersion,
+        final boolean checkOptional) {
+        final String pckInfo = m.getMainAttributes().getValue(headerName);
+        if (pckInfo != null) {
+            final Clause[] clauses = Parser.parseHeader(pckInfo);
+
+            final List<PackageInfo> pcks = new ArrayList<>();
+            for(final Clause entry : clauses) {
+                Object versionObj = entry.getAttribute("version");
+                final String version;
+                if ( versionObj == null ) {
+                    version = defaultVersion;
+                } else {
+                    version = versionObj.toString();
+                }
+
+                boolean optional = false;
+                if ( checkOptional ) {
+                    final String resolution = entry.getDirective("resolution");
+                    optional = "optional".equalsIgnoreCase(resolution);
+                }
+                final PackageInfo pck = new PackageInfo(entry.getName(),
+                    version,
+                    optional);
+                pcks.add(pck);
+            }
+
+            return pcks;
+        }
+        return Collections.emptyList();
+    }
+
+    public static List<PackageInfo> extractExportedPackages(final Manifest m) {
+        return extractPackages(m, Constants.EXPORT_PACKAGE, "0.0.0", false);
+    }
+
+    public static List<PackageInfo> extractImportedPackages(final Manifest m) {
+        return extractPackages(m, Constants.IMPORT_PACKAGE, null, true);
+    }
+
+    public static List<PackageInfo> extractDynamicImportedPackages(final Manifest m) {
+        return extractPackages(m, Constants.DYNAMICIMPORT_PACKAGE, null, false);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java b/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
index 14644d2..2bb2cde 100644
--- a/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
+++ b/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
@@ -16,15 +16,12 @@
  */
 package org.apache.sling.feature.scanner.impl;
 
-import static org.apache.sling.feature.support.util.ManifestParser.convertProvideCapabilities;
-import static org.apache.sling.feature.support.util.ManifestParser.normalizeCapabilityClauses;
-import static org.apache.sling.feature.support.util.ManifestParser.parseStandardHeader;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
@@ -37,14 +34,14 @@ import java.util.zip.ZipInputStream;
 
 import org.apache.commons.lang.text.StrLookup;
 import org.apache.commons.lang.text.StrSubstitutor;
-import org.apache.sling.commons.osgi.ManifestHeader;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.felix.utils.resource.ResourceBuilder;
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.apache.sling.feature.scanner.spi.FrameworkScanner;
-import org.apache.sling.feature.support.util.PackageInfo;
-import org.osgi.framework.BundleException;
+import org.apache.sling.feature.scanner.PackageInfo;
 import org.osgi.framework.Constants;
 import org.osgi.resource.Capability;
 
@@ -61,7 +58,7 @@ public class FelixFrameworkScanner implements FrameworkScanner {
             return null;
         }
         final Set<PackageInfo> pcks = calculateSystemPackages(fwkProps);
-        final Set<Capability> capabilities = calculateSystemCapabilities(fwkProps);
+        final List<Capability> capabilities = calculateSystemCapabilities(fwkProps);
 
         final BundleDescriptor d = new BundleDescriptor() {
 
@@ -101,44 +98,45 @@ public class FelixFrameworkScanner implements FrameworkScanner {
         return d;
     }
 
-    private Set<Capability> calculateSystemCapabilities(final KeyValueMap fwkProps) {
-        return Stream.of(
+    private List<Capability> calculateSystemCapabilities(final KeyValueMap fwkProps) throws IOException
+    {
+         Map<String, String> mf = new HashMap<>();
+         mf.put(Constants.PROVIDE_CAPABILITY,
+                Stream.of(
                     fwkProps.get(Constants.FRAMEWORK_SYSTEMCAPABILITIES),
                     fwkProps.get(Constants.FRAMEWORK_SYSTEMCAPABILITIES_EXTRA)
                 )
                 .filter(Objects::nonNull)
-                .flatMap(header -> {
-                        try {
-                            return convertProvideCapabilities(normalizeCapabilityClauses(parseStandardHeader(header), "2"))
-                                    .stream();
-                        } catch (BundleException ex) {
-                            throw new RuntimeException(ex);
-                        }
-                    })
-                .collect(Collectors.toSet());
+                .collect(Collectors.joining(",")));
+         mf.put(Constants.EXPORT_PACKAGE, Stream.of(
+             fwkProps.get(Constants.FRAMEWORK_SYSTEMPACKAGES),
+             fwkProps.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA)
+             ).filter(Objects::nonNull)
+                 .collect(Collectors.joining(",")));
+         mf.put(Constants.BUNDLE_SYMBOLICNAME, Constants.SYSTEM_BUNDLE_SYMBOLICNAME);
+         mf.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+         try
+         {
+             return ResourceBuilder.build(null, mf).getCapabilities(null);
+         }
+         catch (Exception ex) {
+             throw new IOException(ex);
+         }
     }
 
     private Set<PackageInfo> calculateSystemPackages(final KeyValueMap fwkProps) {
-        final String system = fwkProps.get(Constants.FRAMEWORK_SYSTEMPACKAGES);
-        final String extra = fwkProps.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
-        final Set<PackageInfo> packages = new HashSet<>();
-        for(int i=0;i<2;i++) {
-            final String value = (i == 0 ? system : extra);
-            if ( value != null ) {
-                final ManifestHeader header = ManifestHeader.parse(value);
-                for(final ManifestHeader.Entry entry : header.getEntries()) {
-                    String version = entry.getAttributeValue("version");
-                    if ( version == null ) {
-                        version = "0.0.0";
-                    }
-
-                    final PackageInfo exportedPackageInfo = new PackageInfo(entry.getValue(),
-                            version, false);
-                    packages.add(exportedPackageInfo);
-                }
-            }
-        }
-        return packages;
+        return
+            Stream.of(
+                Parser.parseHeader(
+                    Stream.of(
+                        fwkProps.get(Constants.FRAMEWORK_SYSTEMPACKAGES),
+                        fwkProps.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA)
+                    ).filter(Objects::nonNull)
+                    .collect(Collectors.joining(","))
+                )
+            ).map(
+                clause -> new PackageInfo(clause.getName(), clause.getAttribute("version") != null ? clause.getAttribute("version") : "0.0.0", false))
+            .collect(Collectors.toSet());
     }
 
     private static final String DEFAULT_PROPERTIES = "default.properties";
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
new file mode 100644
index 0000000..a8d289c
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImplTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.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.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.scanner.PackageInfo;
+import org.junit.Test;
+import org.osgi.framework.Version;
+
+public class BundleDescriptorImplTest
+{
+
+    private void assertPackageInfo(Set<PackageInfo> infos, final String name, final Version version) {
+        for (PackageInfo info : infos)
+        {
+            if (name.equals(info.getName()) && version.equals(info.getPackageVersion()))
+            {
+                return;
+            }
+        }
+        fail();
+    }
+
+    @Test public void testExportPackage() throws Exception {
+        String bmf = "Bundle-SymbolicName: pkg.bundle\n"
+            + "Bundle-Version: 1\n"
+            + "Bundle-ManifestVersion: 2\n"
+            + "Export-Package: org.apache.sling;version=1.0,org.apache.felix;version=2.0\n";
+        File f = createBundle(bmf);
+        BundleDescriptorImpl bdf = new BundleDescriptorImpl(new Artifact(new ArtifactId("foo", "bar", "1.0", "bla", "bundle")), f, 1);
+        final Set<PackageInfo> infos = bdf.getExportedPackages();
+        assertEquals(2, infos.size());
+        assertPackageInfo(infos ,"org.apache.sling", Version.parseVersion("1.0"));
+        assertPackageInfo(infos,"org.apache.felix", Version.parseVersion("2.0"));
+    }
+
+    private File createBundle(String manifest) throws IOException
+    {
+        File f = File.createTempFile("bundle", ".jar");
+        f.deleteOnExit();
+        Manifest mf = new Manifest(new ByteArrayInputStream(manifest.getBytes("UTF-8")));
+        mf.getMainAttributes().putValue("Manifest-Version", "1.0");
+        JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf);
+        os.close();
+        return f;
+    }
+}
diff --git a/src/test/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScannerTest.java b/src/test/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScannerTest.java
index 7e0d02f..d5edc80 100644
--- a/src/test/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScannerTest.java
+++ b/src/test/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScannerTest.java
@@ -16,13 +16,18 @@
  */
 package org.apache.sling.feature.scanner.impl;
 
+import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.junit.Test;
 
 import java.io.File;
 import java.net.URL;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 public class FelixFrameworkScannerTest {
     @Test
@@ -46,4 +51,20 @@ public class FelixFrameworkScannerTest {
                 + "osgi.ee; osgi.ee=\"JavaSE/compact2\"; version:List<Version>=\"1.8\", "
                 + "osgi.ee; osgi.ee=\"JavaSE/compact3\"; version:List<Version>=\"1.8\" ", props.get("org.osgi.framework.system.capabilities"));
     }
+
+    @Test
+    public void testGetFrameworkExports() throws Exception {
+        URL url = getClass().getResource("/test-framework.jar");
+        File fwFile = new File(url.toURI());
+
+        FelixFrameworkScanner ffs = new FelixFrameworkScanner();
+
+        KeyValueMap kvmap = new KeyValueMap();
+        BundleDescriptor bundleDescriptor = ffs.scan(new ArtifactId("org.apache.felix",
+            "org.apache.felix.framework",
+            "5.6.10", null, null), fwFile, kvmap);
+
+        assertFalse(bundleDescriptor.getExportedPackages().isEmpty());
+        assertFalse(bundleDescriptor.getCapabilities().isEmpty());
+    }
 }

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.