Author: cziegeler
Date: Thu Jul  6 14:09:13 2017
New Revision: 1801057

URL: http://svn.apache.org/viewvc?rev=1801057&view=rev
Log:
Update scanner framework to scan features and applications

Added:
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java
   (with props)
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
   (with props)
Modified:
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Analyser.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/AnalyserTaskContext.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundleExportsImports.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForInitialContent.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForResources.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ArtifactScanner.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ExtensionScanner.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FeatureDescriptor.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java
    
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Scanner.java
    
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Capability.java
    
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/KeyValueMap.java
    
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Requirement.java

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Analyser.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Analyser.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Analyser.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Analyser.java
 Thu Jul  6 14:09:13 2017
@@ -21,18 +21,12 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.Set;
 
 import org.apache.sling.feature.Application;
-import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.scanner.ArtifactDescriptor;
-import org.apache.sling.feature.scanner.BundleDescriptor;
-import org.apache.sling.feature.scanner.PackageInfo;
+import org.apache.sling.feature.scanner.ApplicationDescriptor;
 import org.apache.sling.feature.scanner.Scanner;
-import org.apache.sling.feature.support.ArtifactManager;
-import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,32 +34,29 @@ public class Analyser {
 
     private final AnalyserTask[] tasks;
 
-    private final ArtifactManager artifactManager;
-
     private final Scanner scanner;
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    public Analyser(final ArtifactManagerConfig amConfig,
+    public Analyser(final Scanner scanner,
             final AnalyserTask...tasks)
     throws IOException {
         this.tasks = tasks;
-        this.artifactManager = ArtifactManager.getArtifactManager(amConfig);
-        this.scanner = new Scanner(amConfig);
+        this.scanner = scanner;
     }
 
-    public Analyser(final ArtifactManagerConfig amConfig,
+    public Analyser(final Scanner scanner,
             final String... taskIds)
     throws IOException {
-        this(amConfig, getTasks(taskIds));
+        this(scanner, getTasks(taskIds));
         if ( this.tasks.length != taskIds.length ) {
             throw new IOException("Couldn't find all tasks " + taskIds);
         }
     }
 
-    public Analyser(final ArtifactManagerConfig amConfig)
+    public Analyser(final Scanner scanner)
     throws IOException {
-        this(amConfig, getTasks((String[])null));
+        this(scanner, getTasks((String[])null));
     }
 
     private static AnalyserTask[] getTasks(final String... taskIds) {
@@ -84,18 +75,7 @@ public class Analyser {
     throws Exception {
         logger.info("Starting application analyzer...");
 
-        // get framework properties and update application
-        final KeyValueMap frameworkProps = scanner.getFrameworkProperties(app);
-        for(final Map.Entry<String, String>entry : frameworkProps) {
-            if ( app.getFrameworkProperties().get(entry.getKey()) == null ) {
-                app.getFrameworkProperties().put(entry.getKey(), 
entry.getValue());
-            }
-        }
-
-        final List<PackageInfo> systemPackages = 
scanner.calculateSystemPackages(app);
-
-        final List<BundleDescriptor> bundleInfos = scanner.getBundleInfos(app);
-        final List<ArtifactDescriptor> artifactInfos = 
scanner.getArtifactInfos(app);
+        final ApplicationDescriptor appDesc = scanner.scan(app);
 
         final List<String> warnings = new ArrayList<>();
         final List<String> errors = new ArrayList<>();
@@ -111,18 +91,8 @@ public class Analyser {
                 }
 
                 @Override
-                public List<BundleDescriptor> getBundleInfos() {
-                    return bundleInfos;
-                }
-
-                @Override
-                public List<ArtifactDescriptor> getArtifactInfos() {
-                    return artifactInfos;
-                }
-
-                @Override
-                public List<PackageInfo> getSystemPackages() {
-                    return systemPackages;
+                public ApplicationDescriptor getDescriptor() {
+                    return appDesc;
                 }
 
                 @Override

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/AnalyserTaskContext.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/AnalyserTaskContext.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/AnalyserTaskContext.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/AnalyserTaskContext.java
 Thu Jul  6 14:09:13 2017
@@ -16,12 +16,8 @@
  */
 package org.apache.sling.feature.analyser;
 
-import java.util.List;
-
 import org.apache.sling.feature.Application;
-import org.apache.sling.feature.scanner.ArtifactDescriptor;
-import org.apache.sling.feature.scanner.BundleDescriptor;
-import org.apache.sling.feature.scanner.PackageInfo;
+import org.apache.sling.feature.scanner.ApplicationDescriptor;
 
 public interface AnalyserTaskContext {
 
@@ -32,22 +28,9 @@ public interface AnalyserTaskContext {
     Application getApplication();
 
     /**
-     * The list of system packages exported by the framework itself
-     * @return Unmodifiable list of system package.
-     */
-    List<PackageInfo> getSystemPackages();
-
-    /**
-     * Get the list of bundle infos.
-     * @return The unmodifiable list of bundle infos
-     */
-    List<BundleDescriptor> getBundleInfos();
-
-    /**
-     * Get the list artifact infos
-     * @return The unmodifiable list of artifact infos
+     * The application descriptor
      */
-    List<ArtifactDescriptor> getArtifactInfos();
+    ApplicationDescriptor getDescriptor();
 
     /**
      * This method is invoked by a {@link AnalyserTask} to report

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
 Thu Jul  6 14:09:13 2017
@@ -21,10 +21,11 @@ import java.io.FileReader;
 import java.io.IOException;
 
 import org.apache.sling.feature.Application;
-import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.analyser.Analyser;
 import org.apache.sling.feature.json.ApplicationJSONReader;
+import org.apache.sling.feature.scanner.Scanner;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
+import org.apache.sling.feature.support.FeatureUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,14 +59,12 @@ public class Main {
             System.exit(1);
         }
         if ( app.getFramework() == null ) {
-            // use hard coded Apache Felix
-            app.setFramework(new ArtifactId("org.apache.felix",
-                    "org.apache.felix.framework",
-                    "5.6.4", null, null));
+            app.setFramework(FeatureUtil.getFelixFrameworkId(null));
         }
 
         try {
-            final Analyser analyser = new Analyser(new 
ArtifactManagerConfig());
+            final Scanner scanner = new Scanner(new ArtifactManagerConfig());
+            final Analyser analyser = new Analyser(scanner);
             analyser.analyse(app);
         } catch ( final Exception e) {
             logger.error("Unable to analyse application: {}", f, e);

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundleExportsImports.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundleExportsImports.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundleExportsImports.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundleExportsImports.java
 Thu Jul  6 14:09:13 2017
@@ -70,7 +70,7 @@ public class CheckBundleExportsImports i
     }
 
     private void checkForVersionOnExportedPackages(final AnalyserTaskContext 
ctx, final Map<BundleDescriptor, Report> reports) {
-        for(final BundleDescriptor info : ctx.getBundleInfos()) {
+        for(final BundleDescriptor info : 
ctx.getDescriptor().getBundleDescriptors()) {
             if ( info.getExportedPackages() != null ) {
                 for(final PackageInfo i : info.getExportedPackages()) {
                     if ( i.getPackageVersion().compareTo(Version.emptyVersion) 
== 0 ) {
@@ -82,7 +82,7 @@ public class CheckBundleExportsImports i
     }
 
     private void checkForVersionOnImportingPackages(final AnalyserTaskContext 
ctx, final Map<BundleDescriptor, Report> reports) {
-        for(final BundleDescriptor info : ctx.getBundleInfos()) {
+        for(final BundleDescriptor info : 
ctx.getDescriptor().getBundleDescriptors()) {
             if ( info.getImportedPackages() != null ) {
                 for(final PackageInfo i : info.getImportedPackages()) {
                     if ( i.getVersion() == null ) {
@@ -106,7 +106,7 @@ public class CheckBundleExportsImports i
         checkForVersionOnImportingPackages(ctx, reports);
 
         final SortedMap<Integer, List<BundleDescriptor>> bundlesMap = new 
TreeMap<>();
-        for(final BundleDescriptor bi : ctx.getBundleInfos()) {
+        for(final BundleDescriptor bi : 
ctx.getDescriptor().getBundleDescriptors()) {
             List<BundleDescriptor> list = 
bundlesMap.get(bi.getBundleStartLevel());
             if ( list == null ) {
                 list = new ArrayList<>();
@@ -116,7 +116,7 @@ public class CheckBundleExportsImports i
         }
 
         // create a synthetic bundle info for the system bundle
-        final BundleDescriptor system = new BundleDescriptor(new 
Artifact(ctx.getApplication().getFramework()), ctx.getSystemPackages());
+        final BundleDescriptor system = new BundleDescriptor(new 
Artifact(ctx.getApplication().getFramework()), 
ctx.getDescriptor().getFrameworkDescriptor().getExportedPackages());
 
         // add all system packages
         final List<BundleDescriptor> exportingBundles = new ArrayList<>();

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForInitialContent.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForInitialContent.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForInitialContent.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForInitialContent.java
 Thu Jul  6 14:09:13 2017
@@ -51,7 +51,7 @@ public class CheckBundlesForInitialConte
     @Override
     public void execute(final AnalyserTaskContext ctx) {
         // check for initial content
-        for(final BundleDescriptor info : ctx.getBundleInfos()) {
+        for(final BundleDescriptor info : 
ctx.getDescriptor().getBundleDescriptors()) {
             final List<String> initialContent = 
extractInitialContent(info.getManifest());
 
             if ( !initialContent.isEmpty() ) {

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForResources.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForResources.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForResources.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/tasks/CheckBundlesForResources.java
 Thu Jul  6 14:09:13 2017
@@ -51,7 +51,7 @@ public class CheckBundlesForResources im
     @Override
     public void execute(final AnalyserTaskContext ctx) {
         // check for initial content
-        for(final BundleDescriptor info : ctx.getBundleInfos()) {
+        for(final BundleDescriptor info : 
ctx.getDescriptor().getBundleDescriptors()) {
             final List<String> bundleResources = 
extractBundleResources(info.getManifest());
             if ( !bundleResources.isEmpty() ) {
                 ctx.reportWarning("Found bundle resources in " + 
info.getArtifact() + " : " + bundleResources);

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ArtifactScanner.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ArtifactScanner.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ArtifactScanner.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ArtifactScanner.java
 Thu Jul  6 14:09:13 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.feature.scanner;
 
+import java.io.File;
 import java.io.IOException;
 
 import org.apache.sling.feature.Artifact;
@@ -34,8 +35,9 @@ public interface ArtifactScanner  {
     /**
      * Try to scan the artifact
      * @param artifact The artifact
+     * @param file The artifact file
      * @return An artifact info or {@code null} if the scanner can't process 
the artifact
      * @throws IOException If an error occurs while scanning the  artifact or 
the artifact is invalid
      */
-    ArtifactDescriptor scan(Artifact artifact) throws IOException;
+    ArtifactDescriptor scan(Artifact artifact, File file) throws IOException;
 }
\ No newline at end of file

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/BundleDescriptor.java
 Thu Jul  6 14:09:13 2017
@@ -18,9 +18,9 @@ package org.apache.sling.feature.scanner
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.jar.Manifest;
 
 import org.apache.sling.feature.Artifact;
@@ -41,13 +41,13 @@ public class BundleDescriptor extends Ar
     private final int startLevel;
 
     /** Information about exported packages. */
-    private final List<PackageInfo> exportedPackages = new ArrayList<>();
+    private final Set<PackageInfo> exportedPackages = new HashSet<>();
 
     /** Information about imported packages. */
-    private final List<PackageInfo> importedPackages = new ArrayList<>();
+    private final Set<PackageInfo> importedPackages = new HashSet<>();
 
     /** Information about dynamic imported packages. */
-    private final List<PackageInfo> dynamicImportedPackages = new 
ArrayList<>();
+    private final Set<PackageInfo> dynamicImportedPackages = new HashSet<>();
 
     /** Manifest */
     private final Manifest manifest;
@@ -66,7 +66,7 @@ public class BundleDescriptor extends Ar
     }
 
     public BundleDescriptor(final Artifact artifact,
-            final List<PackageInfo> pcks) throws IOException {
+            final Set<PackageInfo> pcks) throws IOException {
         super(artifact, null);
         this.startLevel = 0;
 
@@ -100,8 +100,9 @@ public class BundleDescriptor extends Ar
         return startLevel;
     }
 
-    public List<PackageInfo> getExportedPackages() {
-        return Collections.unmodifiableList(this.exportedPackages);
+    @Override
+    public Set<PackageInfo> getExportedPackages() {
+        return Collections.unmodifiableSet(this.exportedPackages);
     }
 
     @Override
@@ -133,13 +134,13 @@ public class BundleDescriptor extends Ar
     }
 
     @Override
-    public List<PackageInfo> getImportedPackages() {
-        return Collections.unmodifiableList(this.importedPackages);
+    public Set<PackageInfo> getImportedPackages() {
+        return Collections.unmodifiableSet(this.importedPackages);
     }
 
     @Override
-    public List<PackageInfo> getDynamicImportedPackages() {
-        return Collections.unmodifiableList(this.dynamicImportedPackages);
+    public Set<PackageInfo> getDynamicImportedPackages() {
+        return Collections.unmodifiableSet(this.dynamicImportedPackages);
     }
 
     protected void analyze() throws IOException {

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Descriptor.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Descriptor.java
 Thu Jul  6 14:09:13 2017
@@ -17,7 +17,7 @@
 package org.apache.sling.feature.scanner;
 
 import java.util.Collections;
-import java.util.List;
+import java.util.Set;
 
 import org.apache.sling.feature.Capability;
 import org.apache.sling.feature.Requirement;
@@ -27,27 +27,31 @@ import org.apache.sling.feature.Requirem
  */
 public class Descriptor  {
 
-    public List<PackageInfo> getImportedPackages() {
-        return Collections.emptyList();
+    public Set<PackageInfo> getExportedPackages() {
+        return Collections.emptySet();
     }
 
-    public List<PackageInfo> getDynamicImportedPackages() {
-        return Collections.emptyList();
+    public Set<PackageInfo> getImportedPackages() {
+        return Collections.emptySet();
+    }
+
+    public Set<PackageInfo> getDynamicImportedPackages() {
+        return Collections.emptySet();
     }
 
     /**
      * Return the list of requirements.
      * @return The list of requirements. The list might be empty.
      */
-    public List<Requirement> getRequirements() {
-        return Collections.emptyList();
+    public Set<Requirement> getRequirements() {
+        return Collections.emptySet();
     }
 
     /**
      * Return the list of capabilities.
      * @return The list of capabilities. The list might be empty.
      */
-    public List<Capability> getCapabilities() {
-        return Collections.emptyList();
+    public Set<Capability> getCapabilities() {
+        return Collections.emptySet();
     }
 }
\ No newline at end of file

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ExtensionScanner.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ExtensionScanner.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ExtensionScanner.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/ExtensionScanner.java
 Thu Jul  6 14:09:13 2017
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.support.ArtifactManager;
 
 /**
  * The extension scanner scans an extension.
@@ -36,8 +37,11 @@ public interface ExtensionScanner  {
      * Try to scan the extension and return a descriptor
      * @param extension The extension
      * @param descs A list of scanned artifact descriptors if the extension is 
of type artifacts, {@code null} otherwise.
+     * @param manager Artifact manager
      * @return The descriptor or {@code null} if the scanner does not know the 
extension
      * @throws IOException If an error occurs while scanning the extension or 
the extension is invalid
      */
-    Descriptor scan(Extension extension, List<ArtifactDescriptor> descs) 
throws IOException;
+    Descriptor scan(Extension extension,
+            List<ArtifactDescriptor> descs,
+            ArtifactManager manager) throws IOException;
 }
\ No newline at end of file

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FeatureDescriptor.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FeatureDescriptor.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FeatureDescriptor.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FeatureDescriptor.java
 Thu Jul  6 14:09:13 2017
@@ -16,11 +16,62 @@
  */
 package org.apache.sling.feature.scanner;
 
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.sling.feature.Capability;
+import org.apache.sling.feature.Requirement;
+
 /**
  * Information about a feature.
  * This is the aggregated information.
  */
 public class FeatureDescriptor extends Descriptor {
 
+    private final Set<Requirement> requirements = new HashSet<>();
+
+    private final Set<Capability> capabilities = new HashSet<>();
+
+    private final Set<PackageInfo> exports = new HashSet<>();
+
+    private final Set<PackageInfo> imports = new HashSet<>();
+
+    private final Set<PackageInfo> dynamicImports = new HashSet<>();
+
+    private final Set<BundleDescriptor> bundles = new HashSet<>();
+
+    private final Set<ArtifactDescriptor> artifacts = new HashSet<>();
+
+    public Set<PackageInfo> getExportedPackages() {
+        return this.exports;
+    }
+
+    public Set<BundleDescriptor> getBundleDescriptors() {
+        return this.bundles;
+    }
+
+    public Set<ArtifactDescriptor> getArtifactDescriptors() {
+        return this.artifacts;
+    }
+
+    @Override
+    public Set<PackageInfo> getImportedPackages() {
+        return this.imports;
+    }
+
+    @Override
+    public Set<PackageInfo> getDynamicImportedPackages() {
+        return this.dynamicImports;
+    }
+
+    @Override
+    public Set<Requirement> getRequirements() {
+        return this.requirements;
+    }
+
+    @Override
+    public Set<Capability> getCapabilities() {
+        return this.capabilities;
+    }
 
 }
\ No newline at end of file

Added: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java?rev=1801057&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java
 Thu Jul  6 14:09:13 2017
@@ -0,0 +1,41 @@
+/*
+ * 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 java.io.File;
+import java.io.IOException;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.KeyValueMap;
+
+/**
+ * The framework scanner scans the framework
+ */
+public interface FrameworkScanner  {
+
+    /**
+     * Try to scan the artifact
+     * @param framework The framework artifact id
+     * @param file The framework artifact
+     * @param frameworkProps framework properties to launch the framework
+     * @return A descriptor or {@code null}
+     * @throws IOException If an error occurs while scanning the platform or 
the artifact is invalid
+     */
+    Descriptor scan(ArtifactId framework,
+            File platformFile,
+            KeyValueMap frameworkProps) throws IOException;
+}
\ No newline at end of file

Propchange: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/FrameworkScanner.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/PackageInfo.java
 Thu Jul  6 14:09:13 2017
@@ -55,4 +55,39 @@ public class PackageInfo {
     public String toString() {
         return "Package " + name + ";version=" + version;
     }
+
+    @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;
+    }
+
 }

Modified: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Scanner.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Scanner.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Scanner.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/Scanner.java
 Thu Jul  6 14:09:13 2017
@@ -17,36 +17,99 @@
 package org.apache.sling.feature.scanner;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
+import java.util.ServiceLoader;
 
-import org.apache.sling.commons.osgi.ManifestHeader;
 import org.apache.sling.feature.Application;
 import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
-import org.osgi.framework.Constants;
 
+/**
+ * The scanner is a service that scans items and provides descriptions for 
these.
+ * The following items can be scanned individually
+ * <ul>
+ *   <li>A bundle artifact
+ *   <li>An artifact (requires {@link ArtifactScannner}s)
+ *   <li>An extension (requires {@link ExtensionScanner}s)
+ *   <li>A feature (requires {@link ArtifactScannner}s and {@link 
ExtensionScanner}s)
+ *   <li>A framework (requires {@link FrameworkScanner}s
+ *   <li>An application (requires all scanner types)
+ * </ul>
+ */
 public class Scanner {
 
     private final ArtifactManager artifactManager;
 
-    public Scanner(final ArtifactManagerConfig amConfig)
+    private final List<ArtifactScanner> artifactScanners;
+
+    private final List<ExtensionScanner> extensionScanners;
+
+    private final List<FrameworkScanner> frameworkScanners;
+
+    /**
+     * Create a new scanner
+     *
+     * @param amConfig The artifact manager configuration
+     * @param artifactScanners A list of artifact scanners
+     * @param extensionScanners A list of extension scanners
+     * @param frameworkScanners A list of framework scanners
+     * @throws IOException If something goes wrong
+     */
+    public Scanner(final ArtifactManagerConfig amConfig,
+            final List<ArtifactScanner> artifactScanners,
+            final List<ExtensionScanner> extensionScanners,
+            final List<FrameworkScanner> frameworkScanners)
     throws IOException {
         this.artifactManager = ArtifactManager.getArtifactManager(amConfig);
+        this.artifactScanners = artifactScanners;
+        this.extensionScanners = extensionScanners;
+        this.frameworkScanners = frameworkScanners;
+    }
+
+    /**
+     * Create a new scanner and use the service loader to find the scanners
+     *
+     * @param amConfig The artifact manager configuration
+     * @throws IOException If something goes wrong
+     */
+    public Scanner(final ArtifactManagerConfig amConfig)
+    throws IOException {
+        this(amConfig, getServices(ArtifactScanner.class),
+                getServices(ExtensionScanner.class),
+                getServices(FrameworkScanner.class));
+    }
+
+    /**
+     * Get services from the service loader
+     *
+     * @param clazz The service class
+     * @return The list of services might be empty.
+     */
+    private static <T> List<T> getServices(final Class<T> clazz) {
+        final ServiceLoader<T> loader = ServiceLoader.load(clazz);
+        final List<T> list = new ArrayList<>();
+        for(final T task : loader) {
+            list.add(task);
+        }
+        return list;
     }
 
+    /**
+     * Scan an artifact.
+     *
+     * @param artifact The artifact
+     * @return The artifact descriptor.
+     * @throws IOException If something goes wrong or no scanner could handle 
the artifact
+     */
     public ArtifactDescriptor scan(final Artifact artifact) throws IOException 
{
         final File file = 
artifactManager.getArtifactHandler(artifact.getId().toMvnUrl()).getFile();
         if ( file == null ) {
@@ -55,240 +118,156 @@ public class Scanner {
 
         ArtifactDescriptor info = null;
 
-        info = new ArtifactDescriptor(artifact, file);
+        for(final ArtifactScanner scanner : this.artifactScanners ) {
+            info = scanner.scan(artifact, file);
+            if ( info != null ) {
+                break;
+            }
+        }
 
+        if ( info == null ) {
+            throw new IOException("No artifact scanner found for " + 
artifact.getId().toMvnId());
+        }
         return info;
     }
 
-    public BundleDescriptor scanBundle(final Artifact artifact, final int 
startLevel) throws IOException {
-        final File file = 
artifactManager.getArtifactHandler(artifact.getId().toMvnUrl()).getFile();
+    /**
+     * Scan a bundle
+     *
+     * @param bundle The bundle artifact
+     * @param startLevel The start level of the bundle
+     * @return The bundle descriptor
+     * @throws IOException If something goes wrong or the provided artifact is 
not a bundle.
+     */
+    public BundleDescriptor scan(final Artifact bundle, final int startLevel) 
throws IOException {
+        final File file = 
artifactManager.getArtifactHandler(bundle.getId().toMvnUrl()).getFile();
         if ( file == null ) {
-            throw new IOException("Unable to find file for " + 
artifact.getId());
+            throw new IOException("Unable to find file for " + bundle.getId());
         }
 
-        return new BundleDescriptor(artifact, file, startLevel);
+        return new BundleDescriptor(bundle, file, startLevel);
     }
 
-    public FeatureDescriptor scanFeature(final Feature feature) throws 
IOException {
-        return null; // TBD
-    }
-
-    public List<BundleDescriptor> getBundleInfos(final Application app)  
throws Exception {
-        final List<BundleDescriptor> bundleInfos = new ArrayList<>();
-
-        for(final Map.Entry<Integer, List<Artifact>> entry : 
app.getBundles().getBundlesByStartLevel().entrySet()) {
+    /**
+     * Get all bundle descriptors for a feature / application
+     * @param bundles The bundles
+     * @param desc The descriptor
+     * @throws IOException If something goes wrong or no suitable scanner is 
found.
+     */
+    private void getBundleInfos(final Bundles bundles, final FeatureDescriptor 
desc)
+    throws IOException {
+        for(final Map.Entry<Integer, List<Artifact>> entry : 
bundles.getBundlesByStartLevel().entrySet()) {
             for(final Artifact bundle : entry.getValue() ) {
-                bundleInfos.add(scanBundle(bundle, entry.getKey()));
+                final BundleDescriptor bundleDesc = scan(bundle, 
entry.getKey());
+                desc.getBundleDescriptors().add(bundleDesc);
+                // aggregate
+                desc.getRequirements().addAll(bundleDesc.getRequirements());
+                desc.getCapabilities().addAll(bundleDesc.getCapabilities());
+                
desc.getExportedPackages().addAll(bundleDesc.getExportedPackages());
+                
desc.getImportedPackages().addAll(bundleDesc.getImportedPackages());
+                
desc.getDynamicImportedPackages().addAll(bundleDesc.getDynamicImportedPackages());
             }
         }
 
-        return bundleInfos;
+        // TBD remove all import packages / dynamic import packages which are 
resolved by this bundle set
+        // same with requirements
     }
 
-    public List<ArtifactDescriptor> getArtifactInfos(final Application app)  
throws Exception {
-        final List<ArtifactDescriptor> artifactInfos = new ArrayList<>();
-
-        for(final Extension ext : app.getExtensions()) {
+    private void scan(final Extensions extensions, final FeatureDescriptor 
desc)
+    throws IOException {
+        for(final Extension ext : extensions) {
+            final List<ArtifactDescriptor> infos;
             if ( ext.getType() == ExtensionType.ARTIFACTS ) {
+                infos = new ArrayList<>();
                 for(final Artifact artifact : ext.getArtifacts()) {
-                    artifactInfos.add(scan(artifact));
+                    final ArtifactDescriptor artifactDesc = scan(artifact);
+                    infos.add(artifactDesc);
+                    desc.getArtifactDescriptors().add(artifactDesc);
+                    // aggregate
+                    
desc.getRequirements().addAll(artifactDesc.getRequirements());
+                    
desc.getCapabilities().addAll(artifactDesc.getCapabilities());
+                    
desc.getExportedPackages().addAll(artifactDesc.getExportedPackages());
+                    
desc.getImportedPackages().addAll(artifactDesc.getImportedPackages());
+                    
desc.getDynamicImportedPackages().addAll(artifactDesc.getDynamicImportedPackages());
                 }
+            } else {
+                infos = null;
             }
-        }
-
-        return artifactInfos;
-    }
-
-    public List<PackageInfo> calculateSystemPackages(final Application app) {
-        final String system = 
app.getFrameworkProperties().get(Constants.FRAMEWORK_SYSTEMPACKAGES);
-        final String extra = 
app.getFrameworkProperties().get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
-        final List<PackageInfo> packages = new ArrayList<>();
-        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);
+            Descriptor extDesc = null;
+            for(final ExtensionScanner scanner : this.extensionScanners) {
+                extDesc = scanner.scan(ext, infos, this.artifactManager);
+                if ( extDesc != null ) {
+                    break;
                 }
             }
-        }
-        return packages;
-    }
-
-    private static final String DEFAULT_PROPERTIES = "default.properties";
-
-    public KeyValueMap getFrameworkProperties(final Application app)
-    throws IOException {
-        final File framework = 
this.artifactManager.getArtifactHandler(app.getFramework().toMvnUrl()).getFile();
-
-        final Map<String, Properties> propsMap = new HashMap<>();
-        try (final ZipInputStream zis = new ZipInputStream(new 
FileInputStream(framework)) ) {
-            boolean done = false;
-            while ( !done ) {
-                final ZipEntry entry = zis.getNextEntry();
-                if ( entry == null ) {
-                    done = true;
-                } else {
-                    final String entryName = entry.getName();
-                    if ( entryName.endsWith(".properties") ) {
-                        final Properties props = new Properties();
-                        props.load(zis);
-
-                        propsMap.put(entryName, props);
-                    }
-                    zis.closeEntry();
-                }
+            if ( extDesc == null ) {
+                throw new IOException("No extension scanner found for 
extension named " + ext.getName() + " of type " + ext.getType().name());
             }
+            desc.getRequirements().addAll(extDesc.getRequirements());
+            desc.getCapabilities().addAll(extDesc.getCapabilities());
+            desc.getExportedPackages().addAll(extDesc.getExportedPackages());
+            desc.getImportedPackages().addAll(extDesc.getImportedPackages());
+            
desc.getDynamicImportedPackages().addAll(extDesc.getDynamicImportedPackages());
         }
+        // TBD remove all import packages / dynamic import packages which are 
resolved by this bundle set
+        // same with requirements
+    }
 
-        final Properties defaultMap = propsMap.get(DEFAULT_PROPERTIES);
-        if ( defaultMap == null ) {
-            throw new IOException("Unable to find " + DEFAULT_PROPERTIES + " 
in framework " + app.getFramework());
-        }
+    /**
+     * Scan a feature
+     *
+     * @param feature The feature
+     * @return The feature descriptor
+     * @throws IOException If something goes wrong or a scanner is missing
+     */
+    public FeatureDescriptor scan(final Feature feature) throws IOException {
+        final FeatureDescriptor desc = new FeatureDescriptor();
 
-        final KeyValueMap frameworkProps = new KeyValueMap();
-        // replace variables
-        defaultMap.put("java.specification.version",
-                System.getProperty("java.specification.version", "1.8"));
-        for(final Object name : defaultMap.keySet()) {
-            final String value = (String)defaultMap.get(name);
-            final String substValue = substVars(value, name.toString(), null, 
defaultMap);
-            frameworkProps.put(name.toString(), substValue);
-        }
+        getBundleInfos(feature.getBundles(), desc);
 
-        return frameworkProps;
+        scan(feature.getExtensions(), desc);
+        return desc;
     }
 
-    private static final String DELIM_START = "${";
-    private static final String DELIM_STOP  = "}";
-
     /**
-     * <p>
-     * This method performs property variable substitution on the
-     * specified value. If the specified value contains the syntax
-     * <tt>${&lt;prop-name&gt;}</tt>, where <tt>&lt;prop-name&gt;</tt>
-     * refers to either a configuration property or a system property,
-     * then the corresponding property value is substituted for the variable
-     * placeholder. Multiple variable place holders may exist in the
-     * specified value as well as nested variable place holders, which
-     * are substituted from inner most to outer most. Configuration
-     * properties override system properties.
-     * </p>
-     * @param val The string on which to perform property substitution.
-     * @param currentKey The key of the property being evaluated used to
-     *        detect cycles.
-     * @param cycleMap Map of variable references used to detect nested cycles.
-     * @param configProps Set of configuration properties.
-     * @return The value of the specified string after system property 
substitution.
-     * @throws IllegalArgumentException If there was a syntax error in the
-     *         property placeholder syntax or a recursive variable reference.
-    **/
-    public static String substVars(String val, String currentKey,
-        Map<String, String> cycleMap, Properties configProps)
-        throws IllegalArgumentException
-    {
-        // If there is currently no cycle map, then create
-        // one for detecting cycles for this invocation.
-        if (cycleMap == null)
-        {
-            cycleMap = new HashMap<>();
-        }
+     * Scan an application
+     *
+     * @param app The application
+     * @return The application descriptor
+     * @throws IOException If something goes wrong or a scanner is missing
+     */
+    public ApplicationDescriptor scan(final Application app) throws 
IOException {
+        final ApplicationDescriptor desc = new ApplicationDescriptor();
 
-        // Put the current key in the cycle map.
-        cycleMap.put(currentKey, currentKey);
+        getBundleInfos(app.getBundles(), desc);
+        scan(app.getExtensions(), desc);
 
-        // Assume we have a value that is something like:
-        // "leading ${foo.${bar}} middle ${baz} trailing"
+        // framework
+        final File file = 
artifactManager.getArtifactHandler(app.getFramework().toMvnUrl()).getFile();
+        if ( file == null ) {
+            throw new IOException("Unable to find file for " + 
app.getFramework());
+        }
 
-        // Find the first ending '}' variable delimiter, which
-        // will correspond to the first deepest nested variable
-        // placeholder.
-        int stopDelim = -1;
-        int startDelim = -1;
-
-        do
-        {
-            stopDelim = val.indexOf(DELIM_STOP, stopDelim + 1);
-            // If there is no stopping delimiter, then just return
-            // the value since there is no variable declared.
-            if (stopDelim < 0)
-            {
-                return val;
-            }
-            // Try to find the matching start delimiter by
-            // looping until we find a start delimiter that is
-            // greater than the stop delimiter we have found.
-            startDelim = val.indexOf(DELIM_START);
-            // If there is no starting delimiter, then just return
-            // the value since there is no variable declared.
-            if (startDelim < 0)
-            {
-                return val;
-            }
-            while (stopDelim >= 0)
-            {
-                int idx = val.indexOf(DELIM_START, startDelim + 
DELIM_START.length());
-                if ((idx < 0) || (idx > stopDelim))
-                {
-                    break;
-                }
-                else if (idx < stopDelim)
-                {
-                    startDelim = idx;
-                }
+        Descriptor fwk = null;
+        for(final FrameworkScanner scanner : this.frameworkScanners) {
+            fwk = scanner.scan(app.getFramework(), file, 
app.getFrameworkProperties());
+            if ( fwk != null ) {
+                break;
             }
         }
-        while ((startDelim > stopDelim) && (stopDelim >= 0));
-
-        // At this point, we have found a variable placeholder so
-        // we must perform a variable substitution on it.
-        // Using the start and stop delimiter indices, extract
-        // the first, deepest nested variable placeholder.
-        String variable =
-            val.substring(startDelim + DELIM_START.length(), stopDelim);
-
-        // Verify that this is not a recursive variable reference.
-        if (cycleMap.get(variable) != null)
-        {
-            throw new IllegalArgumentException(
-                "recursive variable reference: " + variable);
+        if ( fwk == null ) {
+            throw new IOException("No scanner found for framework " + 
app.getFramework().toMvnId());
         }
 
-        // Get the value of the deepest nested variable placeholder.
-        // Try to configuration properties first.
-        String substValue = (configProps != null)
-            ? configProps.getProperty(variable, null)
-            : null;
-        if (substValue == null)
-        {
-            // Ignore unknown property values.
-            substValue = System.getProperty(variable, "");
-        }
+        // aggregate
+        desc.getRequirements().addAll(fwk.getRequirements());
+        desc.getCapabilities().addAll(fwk.getCapabilities());
+        desc.getExportedPackages().addAll(fwk.getExportedPackages());
+        desc.getImportedPackages().addAll(fwk.getImportedPackages());
+        
desc.getDynamicImportedPackages().addAll(fwk.getDynamicImportedPackages());
 
-        // Remove the found variable from the cycle map, since
-        // it may appear more than once in the value and we don't
-        // want such situations to appear as a recursive reference.
-        cycleMap.remove(variable);
-
-        // Append the leading characters, the substituted value of
-        // the variable, and the trailing characters to get the new
-        // value.
-        val = val.substring(0, startDelim)
-            + substValue
-            + val.substring(stopDelim + DELIM_STOP.length(), val.length());
-
-        // Now perform substitution again, since there could still
-        // be substitutions to make.
-        val = substVars(val, currentKey, cycleMap, configProps);
+        desc.setFrameworkDescriptor(fwk);
 
-        // Return the value.
-        return val;
+        return desc;
     }
 }

Added: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java?rev=1801057&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
 Thu Jul  6 14:09:13 2017
@@ -0,0 +1,254 @@
+/*
+ * 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 java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.sling.commons.osgi.ManifestHeader;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.scanner.Descriptor;
+import org.apache.sling.feature.scanner.FrameworkScanner;
+import org.apache.sling.feature.scanner.PackageInfo;
+import org.osgi.framework.Constants;
+
+public class FelixFrameworkScanner implements FrameworkScanner {
+
+
+    @Override
+    public Descriptor scan(final ArtifactId framework,
+            final File platformFile,
+            final KeyValueMap frameworkProps)
+    throws IOException {
+        final KeyValueMap fwkProps = getFrameworkProperties(frameworkProps, 
platformFile);
+        if ( fwkProps == null ) {
+            return null;
+        }
+        final Set<PackageInfo> pcks = calculateSystemPackages(fwkProps);
+        return new Descriptor() {
+
+            @Override
+            public Set<PackageInfo> getExportedPackages() {
+                return pcks;
+            }
+        };
+    }
+
+    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;
+    }
+
+    private static final String DEFAULT_PROPERTIES = "default.properties";
+
+    private KeyValueMap getFrameworkProperties(final KeyValueMap appProps, 
final File framework)
+    throws IOException {
+        final Map<String, Properties> propsMap = new HashMap<>();
+        try (final ZipInputStream zis = new ZipInputStream(new 
FileInputStream(framework)) ) {
+            boolean done = false;
+            while ( !done ) {
+                final ZipEntry entry = zis.getNextEntry();
+                if ( entry == null ) {
+                    done = true;
+                } else {
+                    final String entryName = entry.getName();
+                    if ( entryName.endsWith(".properties") ) {
+                        final Properties props = new Properties();
+                        props.load(zis);
+
+                        propsMap.put(entryName, props);
+                    }
+                    zis.closeEntry();
+                }
+            }
+        }
+
+        final Properties defaultMap = propsMap.get(DEFAULT_PROPERTIES);
+        if ( defaultMap == null ) {
+            return null;
+        }
+
+        final KeyValueMap frameworkProps = new KeyValueMap();
+        frameworkProps.putAll(appProps);
+
+        // replace variables
+        defaultMap.put("java.specification.version",
+                System.getProperty("java.specification.version", "1.8"));
+        for(final Object name : defaultMap.keySet()) {
+            if ( frameworkProps.get(name.toString()) == null ) {
+                final String value = (String)defaultMap.get(name);
+                final String substValue = substVars(value, name.toString(), 
null, defaultMap);
+                frameworkProps.put(name.toString(), substValue);
+            }
+        }
+
+        return frameworkProps;
+    }
+
+    private static final String DELIM_START = "${";
+    private static final String DELIM_STOP  = "}";
+
+    /**
+     * <p>
+     * This method performs property variable substitution on the
+     * specified value. If the specified value contains the syntax
+     * <tt>${&lt;prop-name&gt;}</tt>, where <tt>&lt;prop-name&gt;</tt>
+     * refers to either a configuration property or a system property,
+     * then the corresponding property value is substituted for the variable
+     * placeholder. Multiple variable place holders may exist in the
+     * specified value as well as nested variable place holders, which
+     * are substituted from inner most to outer most. Configuration
+     * properties override system properties.
+     * </p>
+     * @param val The string on which to perform property substitution.
+     * @param currentKey The key of the property being evaluated used to
+     *        detect cycles.
+     * @param cycleMap Map of variable references used to detect nested cycles.
+     * @param configProps Set of configuration properties.
+     * @return The value of the specified string after system property 
substitution.
+     * @throws IllegalArgumentException If there was a syntax error in the
+     *         property placeholder syntax or a recursive variable reference.
+     **/
+    private static String substVars(String val, String currentKey,
+        Map<String, String> cycleMap, Properties configProps)
+        throws IllegalArgumentException
+    {
+        // If there is currently no cycle map, then create
+        // one for detecting cycles for this invocation.
+        if (cycleMap == null)
+        {
+            cycleMap = new HashMap<>();
+        }
+
+        // Put the current key in the cycle map.
+        cycleMap.put(currentKey, currentKey);
+
+        // Assume we have a value that is something like:
+        // "leading ${foo.${bar}} middle ${baz} trailing"
+
+        // Find the first ending '}' variable delimiter, which
+        // will correspond to the first deepest nested variable
+        // placeholder.
+        int stopDelim = -1;
+        int startDelim = -1;
+
+        do
+        {
+            stopDelim = val.indexOf(DELIM_STOP, stopDelim + 1);
+            // If there is no stopping delimiter, then just return
+            // the value since there is no variable declared.
+            if (stopDelim < 0)
+            {
+                return val;
+            }
+            // Try to find the matching start delimiter by
+            // looping until we find a start delimiter that is
+            // greater than the stop delimiter we have found.
+            startDelim = val.indexOf(DELIM_START);
+            // If there is no starting delimiter, then just return
+            // the value since there is no variable declared.
+            if (startDelim < 0)
+            {
+                return val;
+            }
+            while (stopDelim >= 0)
+            {
+                int idx = val.indexOf(DELIM_START, startDelim + 
DELIM_START.length());
+                if ((idx < 0) || (idx > stopDelim))
+                {
+                    break;
+                }
+                else if (idx < stopDelim)
+                {
+                    startDelim = idx;
+                }
+            }
+        }
+        while ((startDelim > stopDelim) && (stopDelim >= 0));
+
+        // At this point, we have found a variable placeholder so
+        // we must perform a variable substitution on it.
+        // Using the start and stop delimiter indices, extract
+        // the first, deepest nested variable placeholder.
+        String variable =
+            val.substring(startDelim + DELIM_START.length(), stopDelim);
+
+        // Verify that this is not a recursive variable reference.
+        if (cycleMap.get(variable) != null)
+        {
+            throw new IllegalArgumentException(
+                "recursive variable reference: " + variable);
+        }
+
+        // Get the value of the deepest nested variable placeholder.
+        // Try to configuration properties first.
+        String substValue = (configProps != null)
+            ? configProps.getProperty(variable, null)
+            : null;
+        if (substValue == null)
+        {
+            // Ignore unknown property values.
+            substValue = System.getProperty(variable, "");
+        }
+
+        // Remove the found variable from the cycle map, since
+        // it may appear more than once in the value and we don't
+        // want such situations to appear as a recursive reference.
+        cycleMap.remove(variable);
+
+        // Append the leading characters, the substituted value of
+        // the variable, and the trailing characters to get the new
+        // value.
+        val = val.substring(0, startDelim)
+            + substValue
+            + val.substring(stopDelim + DELIM_STOP.length(), val.length());
+
+        // Now perform substitution again, since there could still
+        // be substitutions to make.
+        val = substVars(val, currentKey, cycleMap, configProps);
+
+        // Return the value.
+        return val;
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Modified: 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Capability.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Capability.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Capability.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Capability.java
 Thu Jul  6 14:09:13 2017
@@ -70,4 +70,41 @@ public class Capability {
     public KeyValueMap getDirectives() {
         return directives;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((attributes == null) ? 0 : 
attributes.hashCode());
+        result = prime * result + ((directives == null) ? 0 : 
directives.hashCode());
+        result = prime * result + ((namespace == null) ? 0 : 
namespace.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;
+        Capability other = (Capability) obj;
+        if (attributes == null) {
+            if (other.attributes != null)
+                return false;
+        } else if (!attributes.equals(other.attributes))
+            return false;
+        if (directives == null) {
+            if (other.directives != null)
+                return false;
+        } else if (!directives.equals(other.directives))
+            return false;
+        if (namespace == null) {
+            if (other.namespace != null)
+                return false;
+        } else if (!namespace.equals(other.namespace))
+            return false;
+        return true;
+    }
 }

Modified: 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/KeyValueMap.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/KeyValueMap.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/KeyValueMap.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/KeyValueMap.java
 Thu Jul  6 14:09:13 2017
@@ -97,4 +97,29 @@ public class KeyValueMap
     public void clear() {
         this.properties.clear();
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((properties == null) ? 0 : 
properties.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;
+        KeyValueMap other = (KeyValueMap) obj;
+        if (properties == null) {
+            if (other.properties != null)
+                return false;
+        } else if (!properties.equals(other.properties))
+            return false;
+        return true;
+    }
 }

Modified: 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Requirement.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Requirement.java?rev=1801057&r1=1801056&r2=1801057&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Requirement.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Requirement.java
 Thu Jul  6 14:09:13 2017
@@ -70,4 +70,41 @@ public class Requirement {
     public KeyValueMap getDirectives() {
         return directives;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((attributes == null) ? 0 : 
attributes.hashCode());
+        result = prime * result + ((directives == null) ? 0 : 
directives.hashCode());
+        result = prime * result + ((namespace == null) ? 0 : 
namespace.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;
+        Requirement other = (Requirement) obj;
+        if (attributes == null) {
+            if (other.attributes != null)
+                return false;
+        } else if (!attributes.equals(other.attributes))
+            return false;
+        if (directives == null) {
+            if (other.directives != null)
+                return false;
+        } else if (!directives.equals(other.directives))
+            return false;
+        if (namespace == null) {
+            if (other.namespace != null)
+                return false;
+        } else if (!namespace.equals(other.namespace))
+            return false;
+        return true;
+    }
 }


Reply via email to