[ 
https://issues.apache.org/jira/browse/SLING-7521?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16386167#comment-16386167
 ] 

ASF GitHub Bot commented on SLING-7521:
---------------------------------------

bosschaert closed pull request #7: SLING-7521 Order bundles in the generated 
app based on feature order and start order
URL: https://github.com/apache/sling-whiteboard/pull/7
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/featuremodel/example/sling/oak.json 
b/featuremodel/example/sling/oak.json
index 1a1eed5..9a65d86 100644
--- a/featuremodel/example/sling/oak.json
+++ b/featuremodel/example/sling/oak.json
@@ -3,35 +3,35 @@
     "bundles": [
         {
             "id": "org.apache.felix/org.apache.felix.jaas/1.0.2",
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.jackrabbit/oak-blob/1.6.4",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/oak-commons/1.6.4",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/oak-core/1.6.4",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/oak-jcr/1.6.4", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/oak-lucene/1.6.4",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/oak-segment-tar/1.6.4",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.oak.server/1.1.4",
-            "startOrder" : 16
+            "start-order" : 16
         }
     ],
     "configurations": {
diff --git a/featuremodel/example/sling/sling.json 
b/featuremodel/example/sling/sling.json
index e3b5ff5..75fd227 100644
--- a/featuremodel/example/sling/sling.json
+++ b/featuremodel/example/sling/sling.json
@@ -3,415 +3,415 @@
     "bundles": [
         {
             "id": "commons-fileupload/commons-fileupload/1.3.2",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "commons-io/commons-io/2.5",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.aries.jmx/org.apache.aries.jmx.api/1.1.5",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.aries.jmx/org.apache.aries.jmx.core/1.1.7",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.aries.jmx/org.apache.aries.jmx.whiteboard/1.1.5",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.felix/org.apache.felix.bundlerepository/1.6.4",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.felix/org.apache.felix.inventory/1.0.4",
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.felix/org.apache.felix.prefs/1.1.0", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.felix/org.apache.felix.webconsole.plugins.ds/2.0.6", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.felix/org.apache.felix.webconsole.plugins.event/1.1.6", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.felix/org.apache.felix.webconsole.plugins.memoryusage/1.0.6", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.felix/org.apache.felix.webconsole.plugins.obr/1.0.4", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.felix/org.apache.felix.webconsole.plugins.packageadmin/1.0.4", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.felix/org.apache.felix.webconsole/4.3.4", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.johnzon/1.1.0", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.commons.log.webconsole/1.0.0", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.extensions.threaddump/0.2.2", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.extensions.webconsolebranding/1.0.2", 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.extensions.webconsolesecurityprovider/1.0.0",
 
-            "startOrder" : 5
+            "start-order" : 5
         },
         {
             "id": "org.apache.felix/org.apache.felix.http.sslfilter/1.2.2", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.felix/org.apache.felix.metatype/1.1.4", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.felix/org.apache.felix.scr/2.0.12", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.pdfbox/fontbox/2.0.7", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.pdfbox/jempbox/1.8.13", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.pdfbox/pdfbox/2.0.7", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.tika/tika-core/1.14", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "org.apache.tika/tika-parsers/1.14", 
-            "startOrder" : 10
+            "start-order" : 10
         },
         {
             "id": "com.google.guava/guava/15.0",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "io.dropwizard.metrics/metrics-core/3.2.3",
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-api/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-data/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-jcr-commons/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-jcr-rmi/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-spi-commons/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-spi/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.jackrabbit/jackrabbit-webdav/2.14.3", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.metrics/1.2.0", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.api/2.4.0", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.base/3.0.4", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.davex/1.3.8", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.jcr.jackrabbit.accessmanager/3.0.0", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.jcr.jackrabbit.usermanager/2.2.6", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.jcr-wrapper/2.0.0", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.registration/1.0.2", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.webconsole/1.0.2", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.webdav/2.3.8", 
-            "startOrder" : 15
+            "start-order" : 15
         },
         {
             "id": "commons-codec/commons-codec/1.9", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "commons-collections/commons-collections/3.2.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "commons-lang/commons-lang/2.6", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "javax.mail/mail/1.4.7", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.commons/commons-collections4/4.1", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.commons/commons-lang3/3.5", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.commons/commons-math/2.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.felix/org.apache.felix.http.whiteboard/3.0.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.geronimo.bundles/commons-httpclient/3.1_1", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.geronimo.bundles/jstl/1.2_1", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.httpcomponents/httpclient-osgi/4.4.1", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.httpcomponents/httpcore-osgi/4.4.1", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.servicemix.bundles/org.apache.servicemix.bundles.rhino/1.7.7.1_1", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.adapter/2.1.10", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.api/2.16.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.auth.core/1.4.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.auth.form/1.0.8", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.bundleresource.impl/2.2.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.commons.classloader/1.4.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.compiler/2.3.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.commons.fsclassloader/1.0.6", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.mime/2.1.10", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.osgi/2.4.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.scheduler/2.6.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.threads/3.2.6", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.engine/2.6.8", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.fsresource/2.1.8", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.hc.api/1.0.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.hc.core/1.2.8", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.hc.webconsole/1.1.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.i18n/2.5.8", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.installer.console/1.0.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.installer.provider.jcr/3.1.26", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.contentloader/2.2.4", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.jcr.resource/3.0.4", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.launchpad.content/2.0.12", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.models.api/1.3.4", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.models.impl/1.4.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.resourceresolver/1.5.30", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.scripting.api/2.2.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.scripting.core/2.0.46", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.scripting.el-api/1.0.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.javascript/3.0.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.scripting.jsp-api/1.0.0", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.jsp.taglib/2.2.6", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.scripting.jsp/2.3.2", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.sightly.compiler.java/1.0.12", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.sightly.compiler/1.0.12", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.sightly.js.provider/1.0.24", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.sightly.models.provider/1.0.6", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.sightly.repl/1.0.4", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.scripting.sightly/1.0.40", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.serviceusermapper/1.3.4", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.servlets.get/2.1.26", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.servlets.post/2.3.22", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": 
"org.apache.sling/org.apache.sling.servlets.resolver/2.4.14", 
-            "startOrder" : 20
+            "start-order" : 20
         },
         {
             "id": "org.apache.sling/org.apache.sling.xss/2.0.0", 
-            "startOrder" : 20
+            "start-order" : 20
         }
     ],
     "configurations": {
diff --git 
a/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
 
b/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
index d92398a..bff0af9 100644
--- 
a/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
+++ 
b/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/AnalyserTest.java
@@ -17,7 +17,10 @@
 package org.apache.sling.feature.analyser;
 
 import org.apache.sling.feature.Application;
+import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.FeatureResource;
+import org.apache.sling.feature.analyser.impl.BundleDescriptorImpl;
 import org.apache.sling.feature.analyser.service.Analyser;
 import org.apache.sling.feature.analyser.service.Scanner;
 import org.apache.sling.feature.process.FeatureResolver;
@@ -27,8 +30,11 @@
 import org.apache.sling.feature.support.json.FeatureJSONReader;
 import org.junit.Test;
 
+import java.io.File;
+import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.util.ArrayList;
 import java.util.List;
 
 import static junit.framework.TestCase.fail;
@@ -78,8 +84,31 @@ public void close() throws Exception {
             }
 
             @Override
-            public List<Feature> orderFeatures(List<Feature> features) {
-                return features;
+            public List<FeatureResource> orderResources(List<Feature> 
features) {
+                try {
+                    // Just return the resources in the same order as they are 
listed in the features
+                    List<FeatureResource> l = new ArrayList<>();
+
+                    for (Feature f : features) {
+                        for (Artifact a : f.getBundles()) {
+                            BundleDescriptor bd = 
getBundleDescriptor(ArtifactManager.getArtifactManager(new 
ArtifactManagerConfig()), a);
+                            l.add(new TestBundleResourceImpl(bd, f));
+                        }
+                    }
+
+                    return l;
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            private BundleDescriptor getBundleDescriptor(ArtifactManager 
artifactManager, Artifact b) throws IOException {
+                final File file = 
artifactManager.getArtifactHandler(b.getId().toMvnUrl()).getFile();
+                if ( file == null ) {
+                    throw new IOException("Unable to find file for " + 
b.getId());
+                }
+
+                return new BundleDescriptorImpl(b, file, -1);
             }
         };
     }
diff --git 
a/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/TestBundleResourceImpl.java
 
b/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/TestBundleResourceImpl.java
new file mode 100644
index 0000000..40d5b09
--- /dev/null
+++ 
b/featuremodel/feature-analyser/src/test/java/org/apache/sling/feature/analyser/TestBundleResourceImpl.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations 
under
+ * the License.
+ */
+package org.apache.sling.feature.analyser;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.BundleResource;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.OSGiCapability;
+import org.apache.sling.feature.OSGiRequirement;
+import org.apache.sling.feature.support.util.PackageInfo;
+import org.osgi.framework.Version;
+import org.osgi.framework.VersionRange;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation of the OSGi Resource interface, used by the test
+ */
+public class TestBundleResourceImpl implements BundleResource {
+    final Artifact artifact;
+    final String bsn;
+    final String version;
+    final Map<String, List<Capability>> capabilities;
+    final Map<String, List<Requirement>> requirements;
+    final Feature feature;
+
+    /**
+     * Create a resource based on a BundleDescriptor.
+     * @param bd The BundleDescriptor to represent.
+     */
+    public TestBundleResourceImpl(BundleDescriptor bd, Feature feat) {
+        artifact = bd.getArtifact();
+        bsn = bd.getBundleSymbolicName();
+        version = bd.getBundleVersion();
+        feature = feat;
+
+        Map<String, List<Capability>> caps = new HashMap<>();
+        for (Capability c : bd.getCapabilities()) {
+            List<Capability> l = caps.get(c.getNamespace());
+            if (l == null) {
+                l = new ArrayList<>();
+                caps.put(c.getNamespace(), l);
+            }
+            l.add(new OSGiCapability(this, c));
+        }
+
+        // Add the package capabilities (export package)
+        List<Capability> pkgCaps = new ArrayList<>();
+        for(PackageInfo exported : bd.getExportedPackages()) {
+            Map<String, Object> attrs = new HashMap<>();
+            attrs.put(PackageNamespace.PACKAGE_NAMESPACE, exported.getName());
+            attrs.put(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, 
exported.getPackageVersion());
+            
attrs.put(PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE, 
bd.getBundleSymbolicName());
+            attrs.put(PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, 
new Version(bd.getBundleVersion()));
+            pkgCaps.add(new OSGiCapability(this, 
PackageNamespace.PACKAGE_NAMESPACE, attrs, Collections.emptyMap()));
+        }
+        caps.put(PackageNamespace.PACKAGE_NAMESPACE, 
Collections.unmodifiableList(pkgCaps));
+
+        // Add the bundle capability
+        Map<String, Object> battrs = new HashMap<>();
+        battrs.put(BundleNamespace.BUNDLE_NAMESPACE, 
bd.getBundleSymbolicName());
+        battrs.put(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, new 
Version(bd.getBundleVersion()));
+        OSGiCapability bundleCap = new OSGiCapability(this, 
BundleNamespace.BUNDLE_NAMESPACE, battrs, Collections.emptyMap());
+        caps.put(BundleNamespace.BUNDLE_NAMESPACE, 
Collections.singletonList(bundleCap));
+        capabilities = Collections.unmodifiableMap(caps);
+
+        Map<String, List<Requirement>> reqs = new HashMap<>();
+        for (Requirement r : bd.getRequirements()) {
+            List<Requirement> l = reqs.get(r.getNamespace());
+            if (l == null) {
+                l = new ArrayList<>();
+                reqs.put(r.getNamespace(), l);
+            }
+            // Add the requirement and associate with this resource
+            l.add(new OSGiRequirement(this, r));
+        }
+
+        // TODO What do we do with the execution environment?
+        
reqs.remove(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE);
+
+        // Add the package requirements (import package)
+        List<Requirement> pkgReqs = new ArrayList<>();
+        for(PackageInfo imported : bd.getImportedPackages()) {
+            Map<String, String> dirs = new HashMap<>();
+            VersionRange range = imported.getPackageVersionRange();
+            String rangeFilter;
+            if (range != null) {
+                rangeFilter = 
range.toFilterString(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+            } else {
+                rangeFilter = "";
+            }
+            dirs.put(PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE,
+                "(&(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + 
imported.getName() + ")" + rangeFilter + ")");
+            if (imported.isOptional())
+                dirs.put(PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE,
+                    PackageNamespace.RESOLUTION_OPTIONAL);
+            pkgReqs.add(new OSGiRequirement(this, 
PackageNamespace.PACKAGE_NAMESPACE, Collections.emptyMap(), dirs));
+        }
+        reqs.put(PackageNamespace.PACKAGE_NAMESPACE, 
Collections.unmodifiableList(pkgReqs));
+        requirements = Collections.unmodifiableMap(reqs);
+    }
+
+    public TestBundleResourceImpl(String sn, String ver, Artifact art, Feature 
feat, Map<String, List<Capability>> caps, Map<String, List<Requirement>> reqs) {
+        artifact = art;
+        bsn = sn;
+        version = ver;
+        feature = feat;
+        capabilities = caps;
+        requirements = reqs;
+    }
+
+    @Override
+    public Artifact getArtifact() {
+        return artifact;
+    }
+
+    @Override
+    public String getSymbolicName() {
+        return bsn;
+    }
+
+    @Override
+    public String getVersion() {
+        return version;
+    }
+
+    @Override
+    public List<Capability> getCapabilities(String namespace) {
+        if (namespace == null) {
+            return 
capabilities.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
+        }
+
+        List<Capability> caps = capabilities.get(namespace);
+        if (caps == null)
+            return Collections.emptyList();
+        return caps;
+    }
+
+    @Override
+    public List<Requirement> getRequirements(String namespace) {
+        if (namespace == null) {
+            return 
requirements.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
+        }
+
+        List<Requirement> reqs = requirements.get(namespace);
+        if (reqs == null)
+            return Collections.emptyList();
+        return reqs;
+    }
+
+    @Override
+    public Feature getFeature() {
+        return feature;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((artifact == null) ? 0 : 
artifact.hashCode());
+        result = prime * result + ((bsn == null) ? 0 : bsn.hashCode());
+        result = prime * result + ((capabilities == null) ? 0 : 
capabilities.hashCode());
+        result = prime * result + ((feature == null) ? 0 : feature.hashCode());
+        result = prime * result + ((requirements == null) ? 0 : 
requirements.hashCode());
+        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;
+        TestBundleResourceImpl other = (TestBundleResourceImpl) obj;
+        if (artifact == null) {
+            if (other.artifact != null)
+                return false;
+        } else if (!artifact.equals(other.artifact))
+            return false;
+        if (bsn == null) {
+            if (other.bsn != null)
+                return false;
+        } else if (!bsn.equals(other.bsn))
+            return false;
+        if (capabilities == null) {
+            if (other.capabilities != null)
+                return false;
+        } else if (!capabilities.equals(other.capabilities))
+            return false;
+        if (feature == null) {
+            if (other.feature != null)
+                return false;
+        } else if (!feature.equals(other.feature))
+            return false;
+        if (requirements == null) {
+            if (other.requirements != null)
+                return false;
+        } else if (!requirements.equals(other.requirements))
+            return false;
+        if (version == null) {
+            if (other.version != null)
+                return false;
+        } else if (!version.equals(other.version))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "BundleResourceImpl [" + bsn + " " + version + "]";
+    }
+}
diff --git 
a/featuremodel/feature-analyser/src/test/resources/feature_complete.json 
b/featuremodel/feature-analyser/src/test/resources/feature_complete.json
index 63b8bd0..6271a9c 100644
--- a/featuremodel/feature-analyser/src/test/resources/feature_complete.json
+++ b/featuremodel/feature-analyser/src/test/resources/feature_complete.json
@@ -4,79 +4,79 @@
     "bundles" : [
         {
           "id" : "org.apache.sling/org.apache.sling.commons.log/5.0.0",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.slf4j/jcl-over-slf4j/1.7.21",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.slf4j/log4j-over-slf4j/1.7.21",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.slf4j/slf4j-api/1.7.21",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.apache.felix/org.apache.felix.configadmin/1.8.14",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.apache.felix/org.apache.felix.eventadmin/1.4.8",
-          "startOrder" : 4
+          "start-order" : 4
         },
         {
           "id" : "org.apache.felix/org.apache.felix.metatype/1.1.2",
-          "startOrder" : 4
+          "start-order" : 4
         },
         {
           "id" : "org.apache.felix/org.apache.felix.scr/2.0.12",
-          "startOrder" : 4
+          "start-order" : 4
         },
         {
           "id" : "org.apache.felix/org.apache.felix.http.jetty/3.4.2",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "org.apache.felix/org.apache.felix.http.servlet-api/1.1.2",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "commons-io/commons-io/2.5",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "commons-fileupload/commons-fileupload/1.3.2",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "org.apache.felix/org.apache.felix.inventory/1.0.4",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.felix/org.apache.felix.webconsole.plugins.ds/2.0.6",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.felix/org.apache.felix.webconsole.plugins.event/1.1.6",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.felix/org.apache.felix.webconsole.plugins.packageadmin/1.0.4",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "org.apache.felix/org.apache.felix.webconsole/4.3.4",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.sling/org.apache.sling.commons.log.webconsole/1.0.0",
-          "startOrder" : 5
+          "start-order" : 5
         }
     ]
 }
diff --git 
a/featuremodel/feature-analyser/src/test/resources/feature_incomplete.json 
b/featuremodel/feature-analyser/src/test/resources/feature_incomplete.json
index 3ab884c..514e878 100644
--- a/featuremodel/feature-analyser/src/test/resources/feature_incomplete.json
+++ b/featuremodel/feature-analyser/src/test/resources/feature_incomplete.json
@@ -4,79 +4,79 @@
     "bundles" : [
         {
           "id" : "org.apache.sling/org.apache.sling.commons.log/5.0.0",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.slf4j/jcl-over-slf4j/1.7.21",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.slf4j/log4j-over-slf4j/1.7.21",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.slf4j/slf4j-api/1.7.21",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.apache.felix/org.apache.felix.configadmin/1.8.14",
-          "startOrder" : 1
+          "start-order" : 1
         },
         {
           "id" : "org.apache.felix/org.apache.felix.eventadmin/1.4.8",
-          "startOrder" : 4
+          "start-order" : 4
         },
         {
           "id" : "org.apache.felix/org.apache.felix.metatype/1.1.2",
-          "startOrder" : 4
+          "start-order" : 4
         },
         {
           "id" : "org.apache.felix/org.apache.felix.scr/2.0.12",
-          "startOrder" : 4
+          "start-order" : 4
         },
         {
           "id" : "org.apache.felix/org.apache.felix.http.servlet-api/1.1.2",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "commons-io/commons-io/2.5",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "commons-fileupload/commons-fileupload/1.3.2",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "org.apache.felix/org.apache.felix.inventory/1.0.4",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.felix/org.apache.felix.webconsole.plugins.ds/2.0.6",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.felix/org.apache.felix.webconsole.plugins.event/1.1.6",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.felix/org.apache.felix.webconsole.plugins.packageadmin/1.0.4",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "org.apache.felix/org.apache.felix.webconsole/4.3.4",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : 
"org.apache.sling/org.apache.sling.commons.log.webconsole/1.0.0",
-          "startOrder" : 5
+          "start-order" : 5
         },
         {
           "id" : "org.apache.sling/org.apache.sling.i18n/2.5.8",
-          "startOrder" : 6
+          "start-order" : 6
         }
     ]
 }
diff --git a/featuremodel/feature-applicationbuilder/pom.xml 
b/featuremodel/feature-applicationbuilder/pom.xml
index 9f0d02f..917e103 100644
--- a/featuremodel/feature-applicationbuilder/pom.xml
+++ b/featuremodel/feature-applicationbuilder/pom.xml
@@ -132,11 +132,36 @@
             <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>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.resolver</artifactId>
+            <version>1.0.1</version>
+            <scope>provided</scope>
+        </dependency>
                 
-      <!-- Testing -->
+        <!-- Testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
-               <groupId>junit</groupId>
-               <artifactId>junit</artifactId>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>5.6.10</version>
+            <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.analyser</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>        
     </dependencies>
 </project>
diff --git 
a/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java
 
b/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java
new file mode 100644
index 0000000..1cc9cfa
--- /dev/null
+++ 
b/featuremodel/feature-applicationbuilder/src/test/java/org/apache/sling/feature/applicationbuilder/impl/ApplicationBuilderTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.applicationbuilder.impl;
+
+import org.apache.sling.feature.Application;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.process.ApplicationBuilder;
+import org.apache.sling.feature.process.BuilderContext;
+import org.apache.sling.feature.process.FeatureProvider;
+import org.apache.sling.feature.process.FeatureResolver;
+import org.apache.sling.feature.resolver.FrameworkResolver;
+import org.apache.sling.feature.support.ArtifactHandler;
+import org.apache.sling.feature.support.ArtifactManager;
+import org.apache.sling.feature.support.ArtifactManagerConfig;
+import org.apache.sling.feature.support.json.ApplicationJSONWriter;
+import org.apache.sling.feature.support.json.FeatureJSONReader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class ApplicationBuilderTest {
+    private Path tempDir;
+
+    @Before
+    public void setup() throws Exception {
+        tempDir = Files.createTempDirectory(getClass().getSimpleName());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Delete the temp dir again
+        Files.walk(tempDir)
+            .sorted(Comparator.reverseOrder())
+            .map(Path::toFile)
+            .forEach(File::delete);
+    }
+
+    private Map<String, String> getFrameworkProps() {
+        return Collections.singletonMap(Constants.FRAMEWORK_STORAGE, 
tempDir.toFile().getAbsolutePath());
+    }
+
+    @Test
+    public void testBundleOrdering() throws Exception {
+        FeatureProvider fp = new FeatureProvider() {
+            @Override
+            public Feature provide(ArtifactId id) {
+                return null;
+            }
+        };
+        BuilderContext bc = new BuilderContext(fp);
+        ArtifactManager am = ArtifactManager.getArtifactManager(new 
ArtifactManagerConfig());
+
+        Feature fa = readFeature("/featureA.json", am);
+        Feature fb = readFeature("/featureB.json", am);
+        Feature[] features = {fa, fb};
+
+        try (FeatureResolver fr = new FrameworkResolver(am, 
getFrameworkProps())) {
+            Application app = ApplicationBuilder.assemble(null, bc, fr, 
features);
+            String genApp = writeApplication(app);
+
+            String expected = "{\"features\":["
+                    + "\"org.apache.sling.test.features:featureB:1.0.0\","
+                    + "\"org.apache.sling.test.features:featureA:1.0.0\"],"
+                + "\"bundles\":["
+                    + 
"{\"id\":\"commons-io:commons-io:2.6\",\"start-order\":\"10\"},"
+                    + 
"{\"id\":\"org.apache.felix:org.apache.felix.http.servlet-api:1.1.2\",\"start-order\":\"15\"},"
+                    + 
"{\"id\":\"commons-fileupload:commons-fileupload:1.3.3\",\"start-order\":\"16\"}]}";
+            assertEquals(expected, genApp);
+        }
+    }
+
+    private static String writeApplication(Application app) throws Exception {
+        Writer writer = new StringWriter();
+        ApplicationJSONWriter.write(writer, app);
+        return writer.toString();
+    }
+
+    private Feature readFeature(final String res,
+            final ArtifactManager artifactManager) throws Exception {
+        URL url = getClass().getResource(res);
+        String file = new File(url.toURI()).getAbsolutePath();
+        final ArtifactHandler featureArtifact = 
artifactManager.getArtifactHandler(file);
+
+        try (final FileReader r = new FileReader(featureArtifact.getFile())) {
+            final Feature f = FeatureJSONReader.read(r, 
featureArtifact.getUrl());
+            return f;
+        }
+    }
+}
diff --git 
a/featuremodel/feature-applicationbuilder/src/test/resources/featureA.json 
b/featuremodel/feature-applicationbuilder/src/test/resources/featureA.json
new file mode 100644
index 0000000..1daed33
--- /dev/null
+++ b/featuremodel/feature-applicationbuilder/src/test/resources/featureA.json
@@ -0,0 +1,5 @@
+{
+    "id": "org.apache.sling.test.features/featureA/1.0.0",
+    "bundles": 
+        ["commons-fileupload/commons-fileupload/1.3.3"]
+}
\ No newline at end of file
diff --git 
a/featuremodel/feature-applicationbuilder/src/test/resources/featureB.json 
b/featuremodel/feature-applicationbuilder/src/test/resources/featureB.json
new file mode 100644
index 0000000..952c810
--- /dev/null
+++ b/featuremodel/feature-applicationbuilder/src/test/resources/featureB.json
@@ -0,0 +1,14 @@
+{
+    "id": "org.apache.sling.test.features/featureB/1.0.0",
+    "bundles": 
+        [
+            {
+                "id": 
"org.apache.felix/org.apache.felix.http.servlet-api/1.1.2",
+                "start-order" : 10
+            },
+            {
+                "id": "commons-io/commons-io/2.6",
+                "start-order" : 5
+            }
+        ]
+}
\ No newline at end of file
diff --git a/featuremodel/feature-resolver/pom.xml 
b/featuremodel/feature-resolver/pom.xml
index 7d379f9..d4bcdf8 100644
--- a/featuremodel/feature-resolver/pom.xml
+++ b/featuremodel/feature-resolver/pom.xml
@@ -72,6 +72,12 @@
             <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>
+        </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.service.resolver</artifactId>
@@ -96,5 +102,17 @@
             <version>5.6.10</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configurator</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.johnzon</artifactId>
+            <version>1.0.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/FrameworkResolver.java
 
b/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/FrameworkResolver.java
index f62c3db..36bcd60 100644
--- 
a/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/FrameworkResolver.java
+++ 
b/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/FrameworkResolver.java
@@ -18,7 +18,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -31,6 +30,7 @@
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.FeatureResource;
 import org.apache.sling.feature.analyser.BundleDescriptor;
 import org.apache.sling.feature.analyser.impl.BundleDescriptorImpl;
 import org.apache.sling.feature.process.FeatureResolver;
@@ -74,7 +74,7 @@ public FrameworkResolver(ArtifactManager am, Map<String, 
String> frameworkProper
             // Create a resource representing the framework
             BundleRevision br = framework.adapt(BundleRevision.class);
             List<Capability> caps = 
br.getCapabilities(PackageNamespace.PACKAGE_NAMESPACE);
-            frameworkResource = new BundleResourceImpl(
+            frameworkResource = new 
BundleResourceImpl(framework.getSymbolicName(), 
framework.getVersion().toString(), null, null,
                     
Collections.singletonMap(PackageNamespace.PACKAGE_NAMESPACE, caps), 
Collections.emptyMap());
 
             int i=0;
@@ -101,7 +101,7 @@ public void close() throws Exception {
     }
 
     @Override
-    public List<Feature> orderFeatures(List<Feature> features) {
+    public List<FeatureResource> orderResources(List<Feature> features) {
         try {
             return internalOrderFeatures(features);
         } catch (Exception e) {
@@ -109,23 +109,25 @@ public void close() throws Exception {
         }
     }
 
-    public List<Feature> internalOrderFeatures(List<Feature> features) throws 
IOException {
-        Map<Resource, Feature> bundleMap = new HashMap<>();
+    public List<FeatureResource> internalOrderFeatures(List<Feature> features) 
throws IOException {
+        Map<FeatureResource, Feature> bundleMap = new HashMap<>();
+        Map<String, FeatureResource> bsnVerMap = new HashMap<>();
         for (Feature f : features) {
             for (Artifact b : f.getBundles()) {
                 BundleDescriptor bd = getBundleDescriptor(artifactManager, b);
-                Resource r = new BundleResourceImpl(bd);
+                FeatureResource r = new BundleResourceImpl(bd, f);
                 bundleMap.put(r, f);
+                bsnVerMap.put(bd.getBundleSymbolicName() + " " + 
bd.getBundleVersion(), r);
             }
         }
 
         Set<Resource> availableBundles = new HashSet<>(bundleMap.keySet());
         // Add these to the available features
         Artifact lpa = new 
Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
-        availableBundles.add(new 
BundleResourceImpl(getBundleDescriptor(artifactManager, lpa)));
+        availableBundles.add(new 
BundleResourceImpl(getBundleDescriptor(artifactManager, lpa), null));
         availableBundles.add(frameworkResource);
 
-        List<Resource> orderedBundles = new LinkedList<>();
+        List<FeatureResource> orderedBundles = new LinkedList<>();
         try {
             for (Resource bundle : bundleMap.keySet()) {
                 if (orderedBundles.contains(bundle)) {
@@ -135,19 +137,20 @@ public void close() throws Exception {
                 Map<Resource, List<Wire>> deps = resolver.resolve(new 
ResolveContextImpl(bundle, availableBundles));
 
                 for (Map.Entry<Resource, List<Wire>> entry : deps.entrySet()) {
-                    Resource curBundle = entry.getKey();
-
-                    if (!bundleMap.containsKey(curBundle)) {
-                        // This is some synthesized bundle. Ignoring.
+                    Resource depBundle = entry.getKey();
+                    FeatureResource curBundle = getFeatureResource(depBundle, 
bsnVerMap);
+                    if (curBundle == null)
                         continue;
-                    }
 
                     if (!orderedBundles.contains(curBundle)) {
                         orderedBundles.add(curBundle);
                     }
 
                     for (Wire w : entry.getValue()) {
-                        Resource provBundle = w.getProvider();
+                        FeatureResource provBundle = 
getFeatureResource(w.getProvider(), bsnVerMap);
+                        if (provBundle == null)
+                            continue;
+
                         int curBundleIdx = orderedBundles.indexOf(curBundle);
                         int newBundleIdx = orderedBundles.indexOf(provBundle);
                         if (newBundleIdx >= 0) {
@@ -178,25 +181,29 @@ public void close() throws Exception {
                 int idx = getBundleIndex(orderedBundles, bsn); // TODO check 
for filter too
                 if (idx < i) {
                     // the fragment is after the host, and should be moved to 
be before the host
-                    Resource frag = orderedBundles.remove(i);
+                    FeatureResource frag = orderedBundles.remove(i);
                     orderedBundles.add(idx, frag);
                 }
             }
         }
 
-        List<Feature> orderedFeatures = new ArrayList<>();
-        for (Resource r : orderedBundles) {
-            Feature f = bundleMap.get(r);
-            if (f != null) {
-                if (!orderedFeatures.contains(f)) {
-                    orderedFeatures.add(f);
-                }
-            }
+        return orderedBundles;
+    }
+
+    private FeatureResource getFeatureResource(Resource res, Map<String, 
FeatureResource> bsnVerMap) {
+        List<Capability> caps = 
res.getCapabilities(BundleNamespace.BUNDLE_NAMESPACE);
+        if (caps.size() == 0) {
+            return null;
         }
-        return orderedFeatures;
+        Capability cap = caps.get(0);
+        Map<String, Object> attrs = cap.getAttributes();
+        Object bsn = attrs.get(BundleNamespace.BUNDLE_NAMESPACE);
+        Object ver = 
attrs.get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+        String bsnVer = "" + bsn + " " + ver;
+        return bsnVerMap.get(bsnVer);
     }
 
-    private static int getBundleIndex(List<Resource> bundles, String 
bundleSymbolicName) {
+    private static int getBundleIndex(List<FeatureResource> bundles, String 
bundleSymbolicName) {
         for (int i=0; i<bundles.size(); i++) {
             Resource b = bundles.get(i);
             if (bundleSymbolicName.equals(getBundleSymbolicName(b))) {
diff --git 
a/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/impl/BundleResourceImpl.java
 
b/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/impl/BundleResourceImpl.java
index 16cc812..b4f30b3 100644
--- 
a/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/impl/BundleResourceImpl.java
+++ 
b/featuremodel/feature-resolver/src/main/java/org/apache/sling/feature/resolver/impl/BundleResourceImpl.java
@@ -24,6 +24,9 @@
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.BundleResource;
+import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.OSGiCapability;
 import org.apache.sling.feature.OSGiRequirement;
 import org.apache.sling.feature.analyser.BundleDescriptor;
@@ -35,22 +38,28 @@
 import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
 
 /**
  * Implementation of the OSGi Resource interface.
  */
-public class BundleResourceImpl implements Resource {
-    final String hint;
+public class BundleResourceImpl implements BundleResource {
+    final Artifact artifact;
+    final String bsn;
+    final String version;
     final Map<String, List<Capability>> capabilities;
     final Map<String, List<Requirement>> requirements;
+    final Feature feature;
 
     /**
      * Create a resource based on a BundleDescriptor.
      * @param bd The BundleDescriptor to represent.
      */
-    public BundleResourceImpl(BundleDescriptor bd) {
-        hint = bd.getBundleSymbolicName() + " " + bd.getBundleVersion();
+    public BundleResourceImpl(BundleDescriptor bd, Feature feat) {
+        artifact = bd.getArtifact();
+        bsn = bd.getBundleSymbolicName();
+        version = bd.getBundleVersion();
+        feature = feat;
+
         Map<String, List<Capability>> caps = new HashMap<>();
         for (Capability c : bd.getCapabilities()) {
             List<Capability> l = caps.get(c.getNamespace());
@@ -117,18 +126,30 @@ public BundleResourceImpl(BundleDescriptor bd) {
         requirements = Collections.unmodifiableMap(reqs);
     }
 
-    /**
-     * Constructor. Create a resource based on capabilties and requirements.
-     * @param hnt
-     * @param caps The capabilities of the resource.
-     * @param reqs The requirements of the resource.
-     */
-    public BundleResourceImpl(Map<String, List<Capability>> caps, Map<String, 
List<Requirement>> reqs) {
-        hint = "" + System.identityHashCode(this);
+    public BundleResourceImpl(String sn, String ver, Artifact art, Feature 
feat, Map<String, List<Capability>> caps, Map<String, List<Requirement>> reqs) {
+        artifact = art;
+        bsn = sn;
+        version = ver;
+        feature = feat;
         capabilities = caps;
         requirements = reqs;
     }
 
+    @Override
+    public Artifact getArtifact() {
+        return artifact;
+    }
+
+    @Override
+    public String getSymbolicName() {
+        return bsn;
+    }
+
+    @Override
+    public String getVersion() {
+        return version;
+    }
+
     @Override
     public List<Capability> getCapabilities(String namespace) {
         if (namespace == null) {
@@ -153,12 +174,21 @@ public BundleResourceImpl(Map<String, List<Capability>> 
caps, Map<String, List<R
         return reqs;
     }
 
+    @Override
+    public Feature getFeature() {
+        return feature;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
+        result = prime * result + ((artifact == null) ? 0 : 
artifact.hashCode());
+        result = prime * result + ((bsn == null) ? 0 : bsn.hashCode());
         result = prime * result + ((capabilities == null) ? 0 : 
capabilities.hashCode());
+        result = prime * result + ((feature == null) ? 0 : feature.hashCode());
         result = prime * result + ((requirements == null) ? 0 : 
requirements.hashCode());
+        result = prime * result + ((version == null) ? 0 : version.hashCode());
         return result;
     }
 
@@ -171,21 +201,41 @@ public boolean equals(Object obj) {
         if (getClass() != obj.getClass())
             return false;
         BundleResourceImpl other = (BundleResourceImpl) obj;
+        if (artifact == null) {
+            if (other.artifact != null)
+                return false;
+        } else if (!artifact.equals(other.artifact))
+            return false;
+        if (bsn == null) {
+            if (other.bsn != null)
+                return false;
+        } else if (!bsn.equals(other.bsn))
+            return false;
         if (capabilities == null) {
             if (other.capabilities != null)
                 return false;
         } else if (!capabilities.equals(other.capabilities))
             return false;
+        if (feature == null) {
+            if (other.feature != null)
+                return false;
+        } else if (!feature.equals(other.feature))
+            return false;
         if (requirements == null) {
             if (other.requirements != null)
                 return false;
         } else if (!requirements.equals(other.requirements))
             return false;
+        if (version == null) {
+            if (other.version != null)
+                return false;
+        } else if (!version.equals(other.version))
+            return false;
         return true;
     }
 
     @Override
     public String toString() {
-        return "BundleResourceImpl [" + hint + "]";
+        return "BundleResourceImpl [" + bsn + " " + version + "]";
     }
 }
diff --git 
a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
 
b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
index 3f28644..f15fa5c 100644
--- 
a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
+++ 
b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/FrameworkResolverTest.java
@@ -16,21 +16,19 @@
  */
 package org.apache.sling.feature.resolver;
 
-import static org.junit.Assert.assertEquals;
-
 import java.io.File;
 import java.io.FileReader;
 import java.net.URL;
-import java.nio.file.FileVisitOption;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.List;
 import java.util.Map;
 
+import org.apache.sling.feature.BundleResource;
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.FeatureResource;
 import org.apache.sling.feature.process.FeatureResolver;
 import org.apache.sling.feature.support.ArtifactHandler;
 import org.apache.sling.feature.support.ArtifactManager;
@@ -41,6 +39,8 @@
 import org.junit.Test;
 import org.osgi.framework.Constants;
 
+import static org.junit.Assert.assertEquals;
+
 public class FrameworkResolverTest {
     private Path tempDir;
 
@@ -52,7 +52,7 @@ public void setup() throws Exception {
     @After
     public void tearDown() throws Exception {
         // Delete the temp dir again
-        Files.walk(tempDir, FileVisitOption.FOLLOW_LINKS)
+        Files.walk(tempDir)
             .sorted(Comparator.reverseOrder())
             .map(Path::toFile)
             .forEach(File::delete);
@@ -67,23 +67,35 @@ public void testResolveEmptyFeatureList() throws Exception {
         ArtifactManager am = ArtifactManager.getArtifactManager(new 
ArtifactManagerConfig());
         try (FeatureResolver fr = new FrameworkResolver(am, 
getFrameworkProps())) {
             assertEquals(Collections.emptyList(),
-                    fr.orderFeatures(Collections.emptyList()));
+                    fr.orderResources(Collections.emptyList()));
         }
     }
 
     @Test
-    public void testOrderFeatures() throws Exception {
+    public void testOrderBundles() throws Exception {
         ArtifactManager am = ArtifactManager.getArtifactManager(new 
ArtifactManagerConfig());
 
         Feature f1 = readFeature("/feature1.json", am);
         Feature f2 = readFeature("/feature2.json", am);
         Feature f3 = readFeature("/feature3.json", am);
 
+        StringBuilder expected = new StringBuilder();
+        expected.append("slf4j.simple 1.7.25\n");
+        expected.append("slf4j.api 1.7.25\n");
+        expected.append("org.apache.sling.commons.logservice 1.0.6\n");
+        expected.append("org.apache.commons.io 2.6.0\n");
+        expected.append("org.apache.felix.http.servlet-api 1.1.2\n");
+
+        StringBuilder result = new StringBuilder();
         try (FeatureResolver fr = new FrameworkResolver(am, 
getFrameworkProps())) {
-            List<Feature> ordered = fr.orderFeatures(Arrays.asList(f1, f2, 
f3));
-            List<Feature> expected = Arrays.asList(f3, f2, f1);
-            assertEquals(expected, ordered);
+            for(FeatureResource ordered : fr.orderResources(Arrays.asList(f1, 
f2, f3))) {
+                if (ordered instanceof BundleResource) {
+                    BundleResource br = (BundleResource) ordered;
+                    result.append(br.getSymbolicName() + " " + br.getVersion() 
+ "\n");
+                }
+            }
         }
+        assertEquals(expected.toString(), result.toString());
     }
 
     private Feature readFeature(final String res,
diff --git 
a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/BundleResourceImplTest.java
 
b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/BundleResourceImplTest.java
index 08deb2c..9891ec3 100644
--- 
a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/BundleResourceImplTest.java
+++ 
b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/BundleResourceImplTest.java
@@ -16,10 +16,6 @@
  */
 package org.apache.sling.feature.resolver.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collections;
@@ -31,6 +27,8 @@
 
 import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.BundleResource;
+import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.OSGiCapability;
 import org.apache.sling.feature.OSGiRequirement;
 import org.apache.sling.feature.analyser.BundleDescriptor;
@@ -38,6 +36,7 @@
 import org.apache.sling.feature.analyser.impl.BundleDescriptorImpl;
 import org.apache.sling.feature.support.util.PackageInfo;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.osgi.framework.Version;
 import org.osgi.framework.namespace.BundleNamespace;
 import org.osgi.framework.namespace.PackageNamespace;
@@ -45,6 +44,11 @@
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
 public class BundleResourceImplTest {
     @Test
     public void testResource() {
@@ -64,7 +68,9 @@ public void testResource() {
         Requirement r1 = new OSGiRequirement("ns.1",
                 Collections.emptyMap(), Collections.singletonMap("mydir", 
"myvalue"));
         List<Requirement> reqList = Collections.singletonList(r1);
-        Resource res = new BundleResourceImpl(caps,
+        Artifact art = Mockito.mock(Artifact.class);
+        Feature feat = Mockito.mock(Feature.class);
+        BundleResource res = new BundleResourceImpl("a.b.c", "1.2.3", art, 
feat, caps,
                 Collections.singletonMap("ns.1", reqList));
 
         assertEquals(0, res.getCapabilities("nonexistent").size());
@@ -77,6 +83,11 @@ public void testResource() {
         assertTrue(mergedCaps.containsAll(capLst1));
         assertTrue(mergedCaps.containsAll(capLst2));
         assertEquals(reqList, res.getRequirements(null));
+
+        assertEquals("a.b.c", res.getSymbolicName());
+        assertEquals("1.2.3", res.getVersion());
+        assertSame(art, res.getArtifact());
+        assertSame(feat, res.getFeature());
     }
 
     @Test
@@ -96,7 +107,7 @@ public void testBundleResource() throws Exception {
         bd.getImportedPackages().add(im1);
         bd.getImportedPackages().add(im2);
 
-        Resource res = new BundleResourceImpl(bd);
+        Resource res = new BundleResourceImpl(bd, null);
         assertNotNull(
                 getCapAttribute(res, BundleNamespace.BUNDLE_NAMESPACE, 
BundleNamespace.BUNDLE_NAMESPACE));
         assertEquals(new Version("1.2.3"),
@@ -155,7 +166,7 @@ public void testBundleResourceGenericCapReq() throws 
Exception {
         Set<Requirement> reqs = new HashSet<>(Arrays.asList(req1, req2));
         BundleDescriptorImpl bd = new BundleDescriptorImpl(artifact, 
Collections.emptySet(), reqs, caps);
 
-        Resource res = new BundleResourceImpl(bd);
+        Resource res = new BundleResourceImpl(bd, null);
 
         assertEquals(caps, new 
HashSet<>(res.getCapabilities("org.example.cap1")));
         assertEquals(Collections.singleton(req1),
diff --git 
a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/ResolveContextImplTest.java
 
b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/ResolveContextImplTest.java
index b63d14b..5e0f6f6 100644
--- 
a/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/ResolveContextImplTest.java
+++ 
b/featuremodel/feature-resolver/src/test/java/org/apache/sling/feature/resolver/impl/ResolveContextImplTest.java
@@ -16,11 +16,6 @@
  */
 package org.apache.sling.feature.resolver.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -40,10 +35,15 @@
 import org.osgi.service.resolver.HostedCapability;
 import org.osgi.service.resolver.ResolveContext;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
 public class ResolveContextImplTest {
     @Test
     public void testMandatory() {
-        Resource mainRes = new BundleResourceImpl(Collections.emptyMap(), 
Collections.emptyMap());
+        Resource mainRes = new BundleResourceImpl("a", "1", null, null, 
Collections.emptyMap(), Collections.emptyMap());
         List<Resource> available = Arrays.asList();
         ResolveContext ctx = new ResolveContextImpl(mainRes, available);
 
@@ -57,7 +57,7 @@ public void testFindProviders() {
         Resource res3 = exportBundle("org.foo", "1.0.0.TESTING");
         Resource res4 = exportBundle("org.foo", "1.9");
 
-        Resource mainRes = new BundleResourceImpl(Collections.emptyMap(), 
Collections.emptyMap());
+        Resource mainRes = new BundleResourceImpl("b", "2", null, null, 
Collections.emptyMap(), Collections.emptyMap());
         List<Resource> available = Arrays.asList(res1, res2, res3, res4);
         ResolveContext ctx = new ResolveContextImpl(mainRes, available);
 
@@ -79,7 +79,7 @@ private Resource exportBundle(String pkg, String version) {
         attrs.put(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, new 
Version(version));
         Capability cap = new OSGiCapability(PackageNamespace.PACKAGE_NAMESPACE,
                 attrs, Collections.emptyMap());
-        return new BundleResourceImpl(
+        return new BundleResourceImpl("c", "3", null, null,
                 Collections.singletonMap(PackageNamespace.PACKAGE_NAMESPACE,
                         Collections.singletonList(cap)),
                 Collections.emptyMap());
@@ -126,4 +126,4 @@ public void testEffectiveRequirement() {
                 Collections.singletonMap("effective", "active"));
         assertFalse(ctx.isEffective(req3));
     }
-}
\ No newline at end of file
+}
diff --git a/featuremodel/feature-resolver/src/test/resources/feature3.json 
b/featuremodel/feature-resolver/src/test/resources/feature3.json
index 33a09a8..014d228 100644
--- a/featuremodel/feature-resolver/src/test/resources/feature3.json
+++ b/featuremodel/feature-resolver/src/test/resources/feature3.json
@@ -1,5 +1,15 @@
 {
     "id": "org.apache.sling.test.features/feature3/1.0.0",
     "bundles": 
-        ["org.slf4j/slf4j-simple/1.7.25"]
+        [
+            "org.slf4j/slf4j-simple/1.7.25",
+            {
+                "id": 
"org.apache.felix/org.apache.felix.http.servlet-api/1.1.2",
+                "start-order" : 10
+            },
+            {
+                "id": "commons-io/commons-io/2.6",
+                "start-order" : 5
+            }
+        ]
 }
\ No newline at end of file
diff --git a/featuremodel/feature-support/src/test/resources/features/test.json 
b/featuremodel/feature-support/src/test/resources/features/test.json
index f4711c4..451b824 100644
--- a/featuremodel/feature-support/src/test/resources/features/test.json
+++ b/featuremodel/feature-support/src/test/resources/features/test.json
@@ -63,19 +63,19 @@
             {
               "id" : "org.apache.sling/oak-server/1.0.0",
               "hash" : "4632463464363646436",
-              "startOrder" : 1
+              "start-order" : 1
             },
             {
               "id" : "org.apache.sling/application-bundle/2.0.0",
-              "startOrder" : 1
+              "start-order" : 1
             },
             {
               "id" : "org.apache.sling/another-bundle/2.1.0",
-              "startOrder" : 1
+              "start-order" : 1
             },
             {
               "id" : "org.apache.sling/foo-xyz/1.2.3",
-              "startOrder" : 2
+              "start-order" : 2
             }
     ],
     "configurations" : {
diff --git 
a/featuremodel/feature/src/main/java/org/apache/sling/feature/BundleResource.java
 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/BundleResource.java
new file mode 100644
index 0000000..9bfd0f2
--- /dev/null
+++ 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/BundleResource.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * A Feature Resource that is an OSGi Bundle.
+ */
+public interface BundleResource extends FeatureResource {
+    /**
+     * Obtain the Symbolic Name for the bundle.
+     * @return The Symbolic Name.
+     */
+    String getSymbolicName();
+
+    /**
+     * Obtain the Version of the bundle.
+     * @return The Version.
+     */
+    String getVersion();
+}
diff --git 
a/featuremodel/feature/src/main/java/org/apache/sling/feature/FeatureResource.java
 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/FeatureResource.java
new file mode 100644
index 0000000..1877718
--- /dev/null
+++ 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/FeatureResource.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+import org.osgi.resource.Resource;
+
+/**
+ * A Resource that is associated with an Maven Artifact and belongs to a 
Feature.
+ */
+public interface FeatureResource extends Resource {
+    /**
+     * Obtain the associated (Maven) Artifact.
+     * @return The artifact for this Resource.
+     */
+    Artifact getArtifact();
+
+    /**
+     * Obtain the feature that contains this resource.
+     * @return The feature that contains the resource.
+     */
+    Feature getFeature();
+}
diff --git 
a/featuremodel/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
index 49c17b8..de9ef5a 100644
--- 
a/featuremodel/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
+++ 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
@@ -20,8 +20,10 @@
 import java.util.List;
 
 import org.apache.sling.feature.Application;
+import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.FeatureResource;
 
 /**
  * Build an application based on features.
@@ -89,12 +91,11 @@ public static Application assemble(
             app = new Application();
         }
 
-        // Created sorted feature list
         // Remove duplicate features by selecting the one with the highest 
version
-        List<Feature> sortedFeatureList = new ArrayList<>();
+        final List<Feature> featureList = new ArrayList<>();
         for(final Feature f : features) {
             Feature found = null;
-            for(final Feature s : sortedFeatureList) {
+            for(final Feature s : featureList) {
                 if ( s.getId().isSame(f.getId()) ) {
                     found = s;
                     break;
@@ -108,21 +109,29 @@ public static Application assemble(
                     add = false;
                 } else {
                     // remove lower version, higher version will be added
-                    app.getFeatureIds().remove(found.getId());
-                    sortedFeatureList.remove(found);
+                    featureList.remove(found);
                 }
             }
             if ( add ) {
-                app.getFeatureIds().add(f.getId());
-                sortedFeatureList.add(f);
+                featureList.add(f);
             }
         }
 
         // order by dependency chain
-        sortedFeatureList = resolver.orderFeatures(sortedFeatureList);
+        final List<FeatureResource> sortedBundleList = 
resolver.orderResources(featureList);
+
+        final List<Feature> sortedFeatures = new ArrayList<>();
+        for (final FeatureResource fr : sortedBundleList) {
+            Feature f = fr.getFeature();
+            if (!sortedFeatures.contains(f)) {
+                sortedFeatures.add(f);
+            }
+        }
 
         // assemble
-        for(final Feature f : sortedFeatureList) {
+        int featureStartOrder = 5; // begin with start order a little higher 
than 0
+        for(final Feature f : sortedFeatures) {
+            app.getFeatureIds().add(f.getId());
             final Feature assembled = FeatureBuilder.assemble(f, 
context.clone(new FeatureProvider() {
 
                 @Override
@@ -136,6 +145,16 @@ public Feature provide(final ArtifactId id) {
                 }
             }));
 
+            int globalStartOrder = featureStartOrder;
+            for (Artifact a : assembled.getBundles()) {
+                int so = a.getStartOrder() + featureStartOrder;
+                if (so > globalStartOrder)
+                    globalStartOrder = so;
+                a.setStartOrder(so);
+            }
+            // Next feature will have a higher start order than the previous
+            featureStartOrder = globalStartOrder + 1;
+
             merge(app, assembled);
         }
 
diff --git 
a/featuremodel/feature/src/main/java/org/apache/sling/feature/process/FeatureResolver.java
 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/process/FeatureResolver.java
index b3eaa35..5fbba7c 100644
--- 
a/featuremodel/feature/src/main/java/org/apache/sling/feature/process/FeatureResolver.java
+++ 
b/featuremodel/feature/src/main/java/org/apache/sling/feature/process/FeatureResolver.java
@@ -19,20 +19,21 @@
 import java.util.List;
 
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.FeatureResource;
 
 /**
  * A resolver that can perform operations on the feature model.
  */
 public interface FeatureResolver extends AutoCloseable {
     /**
-     * Order the features by their dependency chain. Each feature and its
-     * components are resolved and each other feature providing the 
capabilities
-     * needed by the feature is placed before the requiring feature in the
-     * result.
+     * Order the resources in list of features by their dependency chain.
+     * Each feature and its components are resolved. Then all the resources
+     * in the feature are ordered so that each resource is placed before
+     * the requiring feature/resources in the result.
      *
      * @param features
      *            The features to order.
-     * @return The ordered features.
+     * @return The ordered resources from the features.
      */
-    List<Feature> orderFeatures(List<Feature> features);
+    List<FeatureResource> orderResources(List<Feature> features);
 }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


> [Sling Feature Model] Order bundles in the generated app based on feature 
> order and start order
> -----------------------------------------------------------------------------------------------
>
>                 Key: SLING-7521
>                 URL: https://issues.apache.org/jira/browse/SLING-7521
>             Project: Sling
>          Issue Type: Improvement
>          Components: Tooling
>            Reporter: David Bosschaert
>            Priority: Major
>
> When an application is generated from a number of features it needs to 
> aggregate all bundles form these features and put them in the correct global 
> order. Bundles have a start-order associated with them which is local within 
> the feature, but outside of the feature needs to be relative to other 
> features.
> The resulting application needs to have all bundles ordered in such an order 
> that all dependencies by other bundles are started before the bundles that 
> depend on them are started.
> Additionally, the start-order of bundles within the feature from which the 
> bundles originate must be complied with.
> The result needs to be a bundle list that has a total ordering of bundles 
> from all features that are part of the application.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to