You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/24 16:59:31 UTC

git commit: [KARAF-2923] Fix BundleInfo computation for regions

Repository: karaf
Updated Branches:
  refs/heads/master 23bbe1882 -> d8e6ae44f


[KARAF-2923] Fix BundleInfo computation for regions


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/d8e6ae44
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/d8e6ae44
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/d8e6ae44

Branch: refs/heads/master
Commit: d8e6ae44fd8c9fa1678416dcd8b2ccaf156a9a44
Parents: 23bbe18
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 24 16:46:56 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Thu Apr 24 16:47:22 2014 +0200

----------------------------------------------------------------------
 .../features/internal/region/Subsystem.java     |  51 ++-
 .../internal/region/SubsystemResolver.java      |  27 +-
 .../internal/service/FeaturesServiceImpl.java   | 389 +++++++++----------
 .../karaf/features/internal/service/State.java  |  22 +-
 .../features/internal/service/StateStorage.java |   6 +-
 .../karaf/features/internal/util/MapUtils.java  | 139 ++++++-
 .../features/internal/region/SubsystemTest.java |  17 +-
 .../internal/service/StateStorageTest.java      |   4 +-
 8 files changed, 413 insertions(+), 242 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
index c49d4af..651c388 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
@@ -52,6 +52,7 @@ import org.osgi.resource.Resource;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_SUBSYSTEM;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.addIdentityRequirement;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.getUri;
 import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
 import static org.eclipse.equinox.region.RegionFilter.VISIBLE_ALL_NAMESPACE;
 import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
@@ -203,6 +204,14 @@ public class Subsystem extends ResourceImpl {
         ResourceUtils.addIdentityRequirement(this, name, TYPE_FEATURE, range);
     }
 
+    public Map<String, BundleInfo> getBundleInfos() {
+        Map<String, BundleInfo> infos = new HashMap<String, BundleInfo>();
+        for (DependencyInfo di : dependencies.values()) {
+            infos.put(di.getLocation(), di);
+        }
+        return infos;
+    }
+
     @SuppressWarnings("InfiniteLoopStatement")
     public void preResolve(Collection<Feature> features,
                            DownloadManager manager,
@@ -283,9 +292,9 @@ public class Subsystem extends ResourceImpl {
                 final boolean mandatory = entry.getValue();
                 ResourceImpl res = bundles.get(loc);
                 if (bi.isDependency()) {
-                    addDependency(res, false);
+                    addDependency(res, false, bi.isStart(), bi.getStartLevel());
                 } else {
-                    doAddDependency(res, mandatory);
+                    doAddDependency(res, mandatory, bi.isStart(), bi.getStartLevel());
                 }
             }
             for (Dependency dep : feature.getDependencies()) {
@@ -312,15 +321,15 @@ public class Subsystem extends ResourceImpl {
        }
     }
 
-    void addDependency(ResourceImpl resource, boolean mandatory) {
+    void addDependency(ResourceImpl resource, boolean mandatory, boolean start, int startLevel) {
         if (isAcceptDependencies()) {
-            doAddDependency(resource, mandatory);
+            doAddDependency(resource, mandatory, start, startLevel);
         } else {
-            parent.addDependency(resource, mandatory);
+            parent.addDependency(resource, mandatory, start, startLevel);
         }
     }
 
-    private void doAddDependency(ResourceImpl resource, boolean mandatory) {
+    private void doAddDependency(ResourceImpl resource, boolean mandatory, boolean start, int startLevel) {
         String id = Util.getSymbolicName(resource) + "|" + Util.getVersion(resource);
         DependencyInfo info = dependencies.get(id);
         if (info == null) {
@@ -329,11 +338,39 @@ public class Subsystem extends ResourceImpl {
         }
         info.resource = resource;
         info.mandatory |= mandatory;
+        info.start |= start;
+        if (info.startLevel > 0 && startLevel > 0) {
+            info.startLevel = Math.min(info.startLevel, startLevel);
+        } else {
+            info.startLevel = Math.max(info.startLevel, startLevel);
+        }
     }
 
-    class DependencyInfo {
+    class DependencyInfo implements BundleInfo {
         ResourceImpl resource;
         boolean mandatory;
+        boolean start;
+        int startLevel;
+
+        @Override
+        public boolean isStart() {
+            return start;
+        }
+
+        @Override
+        public int getStartLevel() {
+            return startLevel;
+        }
+
+        @Override
+        public String getLocation() {
+            return getUri(resource);
+        }
+
+        @Override
+        public boolean isDependency() {
+            return !mandatory;
+        }
     }
 
     Map<String, Set<String>> createPolicy(List<? extends ScopeFilter> filters) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
index 8f42dda..86d8e1b 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
@@ -27,6 +27,7 @@ import java.util.Set;
 
 import org.apache.felix.resolver.ResolverImpl;
 import org.apache.felix.resolver.Util;
+import org.apache.karaf.features.BundleInfo;
 import org.apache.karaf.features.Feature;
 import org.apache.karaf.features.Repository;
 import org.apache.karaf.features.internal.download.DownloadManager;
@@ -77,7 +78,7 @@ public class SubsystemResolver {
     }
 
     public Map<Resource, List<Wire>> resolve(
-            List<Repository> repositories,
+            Collection<Feature> allFeatures,
             Map<String, Set<String>> features,
             Map<String, Set<BundleRevision>> system,
             Set<String> overrides,
@@ -113,10 +114,6 @@ public class SubsystemResolver {
             return Collections.emptyMap();
         }
         // Pre-resolve
-        List<Feature> allFeatures = new ArrayList<Feature>();
-        for (Repository repo : repositories) {
-            allFeatures.addAll(Arrays.asList(repo.getFeatures()));
-        }
         root.preResolve(allFeatures, manager, overrides, featureResolutionRange);
 
         // Add system resources
@@ -154,6 +151,26 @@ public class SubsystemResolver {
         return wiring;
     }
 
+    public Map<String, Map<String, BundleInfo>> getBundleInfos() {
+        Map<String, Map<String, BundleInfo>> infos = new HashMap<String, Map<String, BundleInfo>>();
+        Map<String, String> flats = getFlatSubsystemsMap();
+        addBundleInfos(infos, root, flats);
+        return infos;
+    }
+
+    private void addBundleInfos(Map<String, Map<String, BundleInfo>> infos, Subsystem subsystem, Map<String, String> flats) {
+        String region = flats.get(subsystem.getName());
+        Map<String, BundleInfo> bis = infos.get(region);
+        if (bis == null) {
+            bis = new HashMap<String, BundleInfo>();
+            infos.put(region, bis);
+        }
+        bis.putAll(subsystem.getBundleInfos());
+        for (Subsystem child : subsystem.getChildren()) {
+            addBundleInfos(infos, child, flats);
+        }
+    }
+
     public Map<String, StreamProvider> getProviders() {
         return manager.getProviders();
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 7e42df9..cbfb15a 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -20,13 +20,13 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -54,6 +54,7 @@ import org.apache.karaf.features.internal.region.ResourceComparator;
 import org.apache.karaf.features.internal.region.SubsystemResolver;
 import org.apache.karaf.features.internal.util.ChecksumUtils;
 import org.apache.karaf.features.internal.util.Macro;
+import org.apache.karaf.features.internal.util.MapUtils;
 import org.apache.karaf.features.internal.util.MultiException;
 import org.apache.karaf.util.collections.CopyOnWriteArrayIdentityList;
 import org.eclipse.equinox.region.Region;
@@ -82,7 +83,11 @@ import static org.apache.felix.resolver.Util.getVersion;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.getFeatureId;
 import static org.apache.karaf.features.internal.resolver.ResourceUtils.getUri;
 import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
-import static org.apache.karaf.features.internal.util.MapUtils.copyMapSet;
+import static org.apache.karaf.features.internal.util.MapUtils.apply;
+import static org.apache.karaf.features.internal.util.MapUtils.copy;
+import static org.apache.karaf.features.internal.util.MapUtils.diff;
+import static org.apache.karaf.features.internal.util.MapUtils.flatten;
+import static org.apache.karaf.features.internal.util.MapUtils.map;
 import static org.apache.karaf.features.internal.util.MapUtils.removeFromMapSet;
 import static org.osgi.framework.Bundle.ACTIVE;
 import static org.osgi.framework.Bundle.RESOLVED;
@@ -582,7 +587,7 @@ public class FeaturesServiceImpl implements FeaturesService {
     public boolean isRequired(Feature f) {
         String id = f.getName() + "/" + new VersionRange(f.getVersion(), true);
         synchronized (lock) {
-            Set<String> features = state.features.get(ROOT_REGION);
+            Set<String> features = state.requestedFeatures.get(ROOT_REGION);
             return features != null && features.contains(id);
         }
     }
@@ -659,7 +664,7 @@ public class FeaturesServiceImpl implements FeaturesService {
     @Override
     public void installFeatures(Set<String> features, String region, EnumSet<Option> options) throws Exception {
         State state = copyState();
-        Map<String, Set<String>> required = copyMapSet(state.features);
+        Map<String, Set<String>> required = copy(state.requestedFeatures);
         if (region == null || region.isEmpty()) {
             region = ROOT_REGION;
         }
@@ -700,7 +705,7 @@ public class FeaturesServiceImpl implements FeaturesService {
 
     public void uninstallFeatures(Set<String> features, String region, EnumSet<Option> options) throws Exception {
         State state = copyState();
-        Map<String, Set<String>> required = copyMapSet(state.features);
+        Map<String, Set<String>> required = copy(state.requestedFeatures);
         if (region == null || region.isEmpty()) {
             region = ROOT_REGION;
         }
@@ -811,9 +816,57 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
     }
 
-    public void doInstallFeatures(Map<String, Set<String>> features,  // all request features
-                                  State                    state,     // current state
-                                  EnumSet<Option>          options    // installation options
+    static class DeploymentState {
+        Map<Long, Bundle> bundles;
+        Map<String, Feature> features;
+        Map<String, Set<Long>> bundlesPerRegion;
+        Map<String, Map<String, Map<String, Set<String>>>> filtersPerRegion;
+    }
+    
+    protected DeploymentState getDeploymentState() throws Exception {
+        DeploymentState state = new DeploymentState();
+        // Bundles
+        state.bundles = new HashMap<Long, Bundle>();
+        for (Bundle bundle : systemBundleContext.getBundles()) {
+            state.bundles.put(bundle.getBundleId(), bundle);
+        }
+        // Features
+        state.features = new HashMap<String, Feature>();
+        for (Map<String, Feature> m : getFeatures().values()) {
+            for (Feature feature : m.values()) {
+                String id = feature.getName() + "/" + VersionTable.getVersion(feature.getVersion());
+                state.features.put(id, feature);
+            }
+        }
+        // Region -> bundles mapping
+        // Region -> policy mapping
+        state.bundlesPerRegion = new HashMap<String, Set<Long>>();
+        state.filtersPerRegion = new HashMap<String, Map<String, Map<String, Set<String>>>>();
+        RegionDigraph clone = digraph.copy();
+        for (Region region : clone.getRegions()) {
+            // Get bundles
+            state.bundlesPerRegion.put(region.getName(), new HashSet<Long>(region.getBundleIds()));
+            // Get policies
+            Map<String, Map<String, Set<String>>> edges = new HashMap<String, Map<String, Set<String>>>();
+            for (RegionDigraph.FilteredRegion fr : clone.getEdges(region)) {
+                Map<String, Set<String>> policy = new HashMap<String, Set<String>>();
+                Map<String, Collection<String>> current = fr.getFilter().getSharingPolicy();
+                for (String ns : current.keySet()) {
+                    for (String f : current.get(ns)) {
+                        addToMapSet(policy, ns, f);
+                    }
+                }
+                edges.put(fr.getRegion().getName(), policy);
+            }
+            state.filtersPerRegion.put(region.getName(), edges);
+        }
+        // Return
+        return state;
+    }
+
+    public void doInstallFeatures(Map<String, Set<String>> requestedFeatures,  // all request features
+                                  State                    state,              // current state
+                                  EnumSet<Option>          options             // installation options
                     ) throws Exception {
 
         boolean noRefreshUnmanaged = options.contains(Option.NoAutoRefreshUnmanagedBundles);
@@ -823,94 +876,47 @@ public class FeaturesServiceImpl implements FeaturesService {
         boolean verbose = options.contains(Option.Verbose);
         boolean simulate = options.contains(Option.Simulate);
 
-        Map<String, Set<String>> installed = state.installedFeatures;
-        Map<String, Set<Long>> managed = copyMapSet(state.managedBundles);
+        DeploymentState dstate = getDeploymentState();
+        
+        Map<String, Set<Long>> managedBundles = copy(state.managedBundles);
 
-        Bundle[] bundles = systemBundleContext.getBundles();
-
-        // Get a map of unmanaged bundles to use as capabilities during resolution
-        Map<String, Set<BundleRevision>> unmanagedBundles = new HashMap<String, Set<BundleRevision>>();
-        Map<String, Map<String, Map<String, Set<String>>>> policies = new HashMap<String, Map<String, Map<String, Set<String>>>>();
-        {
-            RegionDigraph clone = digraph.copy();
-            for (Region region : clone.getRegions()) {
-                // Get bundles
-                Set<Long> ids = new HashSet<Long>(region.getBundleIds());
-                if (managed.containsKey(region.getName())) {
-                    ids.removeAll(managed.get(region.getName()));
-                }
-                if (!ids.isEmpty()) {
-                    Set<BundleRevision> revs = new HashSet<BundleRevision>();
-                    for (Bundle bundle : bundles) {
-                        if (ids.contains(bundle.getBundleId())) {
-                            revs.add(bundle.adapt(BundleRevision.class));
-                        }
-                    }
-                    unmanagedBundles.put(region.getName(), revs);
-                }
-                // Get policies
-                Map<String, Map<String, Set<String>>> edges = new HashMap<String, Map<String, Set<String>>>();
-                for (RegionDigraph.FilteredRegion fr : clone.getEdges(region)) {
-                    Map<String, Set<String>> policy = new HashMap<String, Set<String>>();
-                    Map<String, Collection<String>> current = fr.getFilter().getSharingPolicy();
-                    for (String ns : current.keySet()) {
-                        for (String f : current.get(ns)) {
-                            addToMapSet(policy, ns, f);
-                        }
-                    }
-                    edges.put(fr.getRegion().getName(), policy);
-                }
-                policies.put(region.getName(), edges);
-            }
-        }
+        Map<String, Set<Bundle>> unmanagedBundles = apply(diff(dstate.bundlesPerRegion, state.managedBundles),
+                                                          map(dstate.bundles));
 
         // Resolve
         // TODO: requirements
         // TODO: bundles
-        Repository[] repositories = listRepositories();
-
-        if (!installed.containsKey(ROOT_REGION)) {
-            installed.put(ROOT_REGION, new HashSet<String>());
-        }
 
         SubsystemResolver resolver = new SubsystemResolver();
-        Map<Resource, List<Wire>> resolution = resolver.resolve(
-                Arrays.asList(repositories),
-                features,
-                unmanagedBundles,
+        resolver.resolve(
+                dstate.features.values(),
+                requestedFeatures,
+                apply(unmanagedBundles, adapt(BundleRevision.class)),
                 Overrides.loadOverrides(this.overrides),
                 featureResolutionRange,
                 globalRepository);
-        Collection<Resource> allResources = resolution.keySet();
-        Map<String, StreamProvider> providers = resolver.getProviders();
-
-        Map<String, Set<String>> installedFeatures = getInstalledFeatures(resolver);
 
-        List<String> installedFeatureIds = getFeatureIds(allResources);
-        List<String> newFeatures = new ArrayList<String>(installedFeatureIds);
-        newFeatures.removeAll(installed.get(ROOT_REGION));
-        List<String> delFeatures = new ArrayList<String>(installed.get(ROOT_REGION));
-        delFeatures.removeAll(installedFeatureIds);
+        Map<String, StreamProvider> providers = resolver.getProviders();
+        Map<String, Set<Resource>> featuresPerRegion = resolver.getFeaturesPerRegions();
+        Map<String, Set<String>> installedFeatures = apply(featuresPerRegion, featureId());
+        Map<String, Set<String>> newFeatures = diff(installedFeatures, state.installedFeatures);
+        Map<String, Set<String>> delFeatures = diff(state.installedFeatures, installedFeatures);
 
         // Compute information for each bundle
-        Map<String, BundleInfo> bundleInfos = new HashMap<String, BundleInfo>();
-        for (Feature feature : getFeatures(repositories, getFeatureIds(allResources))) {
-            for (BundleInfo bi : feature.getBundles()) {
-                BundleInfo oldBi = bundleInfos.get(bi.getLocation());
-                if (oldBi != null) {
-                    bi = mergeBundleInfo(bi, oldBi);
-                }
-                bundleInfos.put(bi.getLocation(), bi);
-            }
-        }
+        Map<String, Map<String, BundleInfo>> bundleInfos = resolver.getBundleInfos();
 
         // Get all resources that will be used to satisfy the old features set
+        // If noStart is true, we don't want to start the newly installed features
+        // but we still want old features to be started.
         Set<Resource> resourceLinkedToOldFeatures = new HashSet<Resource>();
         if (noStart) {
-            for (Resource resource : resolver.getFeatures().keySet()) {
-                String id = getFeatureId(resource);
-                if (installed.get(ROOT_REGION).contains(id)) {
-                    addTransitive(resource, resourceLinkedToOldFeatures, resolution);
+            for (Map.Entry<String, Set<Resource>> entry : featuresPerRegion.entrySet()) {
+                for (Resource resource : entry.getValue()) {
+                    String id = getFeatureId(resource);
+                    if (state.installedFeatures.containsKey(entry.getKey())
+                            && state.installedFeatures.get(entry.getKey()).contains(id)) {
+                        addTransitive(resource, resourceLinkedToOldFeatures, resolver.getWiring());
+                    }
                 }
             }
         }
@@ -918,7 +924,7 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
         // Compute deployment
         //
-        Deployment deployment = computeDeployment(resolver, state);
+        Deployment deployment = computeDeployment(dstate, resolver, state);
 
         if (deployment.regions.isEmpty()) {
             print("No deployment change.", verbose);
@@ -937,63 +943,13 @@ public class FeaturesServiceImpl implements FeaturesService {
             toRefresh.addAll(regionDeployment.toDelete);
             toRefresh.addAll(regionDeployment.toUpdate.keySet());
         }
-
         if (!noRefreshManaged) {
-            int size;
-            do {
-                size = toRefresh.size();
-                for (Bundle bundle : bundles) {
-                    // Continue if we already know about this bundle
-                    if (toRefresh.contains(bundle)) {
-                        continue;
-                    }
-                    // Ignore non resolved bundle
-                    BundleWiring wiring = bundle.adapt(BundleWiring.class);
-                    if (wiring == null) {
-                        continue;
-                    }
-                    // Get through the old resolution and flag this bundle
-                    // if it was wired to a bundle to be refreshed
-                    for (BundleWire wire : wiring.getRequiredWires(null)) {
-                        if (toRefresh.contains(wire.getProvider().getBundle())) {
-                            toRefresh.add(bundle);
-                            break;
-                        }
-                    }
-                    // Get through the new resolution and flag this bundle
-                    // if it's wired to any new bundle
-                    List<Wire> newWires = resolution.get(wiring.getRevision());
-                    if (newWires != null) {
-                        for (Wire wire : newWires) {
-                            Bundle b;
-                            if (wire.getProvider() instanceof BundleRevision) {
-                                b = ((BundleRevision) wire.getProvider()).getBundle();
-                            } else {
-                                b = deployment.resToBnd.get(wire.getProvider());
-                            }
-                            if (b == null || toRefresh.contains(b)) {
-                                toRefresh.add(bundle);
-                                break;
-                            }
-                        }
-                    }
-                }
-            } while (toRefresh.size() > size);
+            computeBundlesToRefresh(toRefresh, dstate.bundles.values(), deployment.resToBnd, resolver.getWiring());
         }
         if (noRefreshUnmanaged) {
-            Set<Bundle> newSet = new HashSet<Bundle>();
-            for (Bundle bundle : toRefresh) {
-                for (Set<Long> m : managed.values()) {
-                    if (m.contains(bundle.getBundleId())) {
-                        newSet.add(bundle);
-                        break;
-                    }
-                }
-            }
-            toRefresh = newSet;
+            toRefresh.removeAll(flatten(unmanagedBundles));
         }
 
-
         if (simulate) {
             if (!toRefresh.isEmpty()) {
                 print("  Bundles to refresh:", verbose);
@@ -1009,6 +965,17 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
         // Execute deployment
         //
+        // #1: stop bundles that needs to be updated or uninstalled in order
+        // #2: uninstall needed bundles
+        // #3: update regions
+        // #4: update bundles
+        // #5: install bundles
+        // #6: save state
+        // #7: install configuration
+        // #8: refresh bundles
+        // #9: start bundles in order
+        // #10: send events
+        //
 
         // TODO: handle update on the features service itself
         RegionDeployment rootRegionDeployment = deployment.regions.get(ROOT_REGION);
@@ -1064,7 +1031,7 @@ public class FeaturesServiceImpl implements FeaturesService {
                 for (Bundle bundle : regionDeployment.toDelete) {
                     print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
                     bundle.uninstall();
-                    removeFromMapSet(managed, name, bundle.getBundleId());
+                    removeFromMapSet(managedBundles, name, bundle.getBundleId());
                 }
             }
         }
@@ -1075,11 +1042,12 @@ public class FeaturesServiceImpl implements FeaturesService {
         {
             RegionDigraph clone = digraph.copy();
             RegionDigraph computedDigraph = resolver.getFlatDigraph();
+            Map<String, Map<String, Map<String, Set<String>>>> policies = copy(dstate.filtersPerRegion);
             // Iterate through previously managed regions and
             // delete those that do not contain any bundles anymore
             for (String name : state.managedBundles.keySet()) {
-                if (!managed.containsKey(name) && !unmanagedBundles.containsKey(name)) {
-                    policies.remove(name);
+                if (!managedBundles.containsKey(name) && !unmanagedBundles.containsKey(name)) {
+                    dstate.filtersPerRegion.remove(name);
                 }
             }
             // Fix broken filters
@@ -1128,12 +1096,12 @@ public class FeaturesServiceImpl implements FeaturesService {
                 }
                 // Dispatch bundles
                 if (unmanagedBundles.containsKey(r1Name)) {
-                    for (BundleRevision rev : unmanagedBundles.get(r1Name)) {
-                        r1.addBundle(rev.getBundle());
+                    for (Bundle bundle : unmanagedBundles.get(r1Name)) {
+                        r1.addBundle(bundle);
                     }
                 }
-                if (managed.containsKey(r1Name)) {
-                    for (long id : managed.get(r1Name)) {
+                if (managedBundles.containsKey(r1Name)) {
+                    for (long id : managedBundles.get(r1Name)) {
                         r1.addBundle(id);
                     }
                 }
@@ -1153,8 +1121,8 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
         if (hasToUpdate) {
             print("Updating bundles:", verbose);
-            for (RegionDeployment regionDeployment : deployment.regions.values()) {
-                for (Map.Entry<Bundle, Resource> entry : regionDeployment.toUpdate.entrySet()) {
+            for (Map.Entry<String, RegionDeployment> rde : deployment.regions.entrySet()) {
+                for (Map.Entry<Bundle, Resource> entry : rde.getValue().toUpdate.entrySet()) {
                     Bundle bundle = entry.getKey();
                     Resource resource = entry.getValue();
                     String uri = getUri(resource);
@@ -1162,7 +1130,7 @@ public class FeaturesServiceImpl implements FeaturesService {
                     InputStream is = getBundleInputStream(resource, providers);
                     bundle.update(is);
                     toStart.add(bundle);
-                    BundleInfo bi = bundleInfos.get(uri);
+                    BundleInfo bi = bundleInfos.get(rde.getKey()).get(uri);
                     if (bi != null && bi.getStartLevel() > 0) {
                         bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
                     }
@@ -1194,14 +1162,14 @@ public class FeaturesServiceImpl implements FeaturesService {
                     } else {
                         bundle = region.installBundle(uri, is);
                     }
-                    addToMapSet(managed, name, bundle.getBundleId());
+                    addToMapSet(managedBundles, name, bundle.getBundleId());
                     deployment.resToBnd.put(resource, bundle);
                     // save a checksum of installed snapshot bundle
                     if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots)
-                            && isUpdateable(resource) && !deployment.newCheckums.containsKey(bundle.getBundleId())) {
-                        deployment.newCheckums.put(bundle.getBundleId(), ChecksumUtils.checksum(getBundleInputStream(resource, providers)));
+                            && isUpdateable(resource) && !deployment.bundleChecksums.containsKey(bundle.getBundleId())) {
+                        deployment.bundleChecksums.put(bundle.getBundleId(), ChecksumUtils.checksum(getBundleInputStream(resource, providers)));
                     }
-                    BundleInfo bi = bundleInfos.get(uri);
+                    BundleInfo bi = bundleInfos.get(entry.getKey()).get(uri);
                     if (bi != null && bi.getStartLevel() > 0) {
                         bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
                     }
@@ -1220,13 +1188,14 @@ public class FeaturesServiceImpl implements FeaturesService {
         // Update and save state
         //
         synchronized (lock) {
-            this.state.bundleChecksums.putAll(deployment.newCheckums);
-            this.state.features.clear();
-            this.state.features.putAll(features);
+            this.state.bundleChecksums.clear();
+            this.state.bundleChecksums.putAll(deployment.bundleChecksums);
+            this.state.requestedFeatures.clear();
+            this.state.requestedFeatures.putAll(requestedFeatures);
             this.state.installedFeatures.clear();
             this.state.installedFeatures.putAll(installedFeatures);
             this.state.managedBundles.clear();
-            this.state.managedBundles.putAll(managed);
+            this.state.managedBundles.putAll(managedBundles);
             saveState();
         }
 
@@ -1234,12 +1203,9 @@ public class FeaturesServiceImpl implements FeaturesService {
         // Install configurations
         //
         if (configInstaller != null && !newFeatures.isEmpty()) {
-            for (Repository repository : repositories) {
-                for (Feature feature : repository.getFeatures()) {
-                    if (newFeatures.contains(feature.getId())) {
-                        configInstaller.installFeatureConfigs(feature);
-                    }
-                }
+            Set<Feature> set = apply(flatten(newFeatures), map(dstate.features));
+            for (Feature feature : set) {
+                configInstaller.installFeatureConfigs(feature);
             }
         }
 
@@ -1299,16 +1265,60 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
 
         // Call listeners
-        for (Feature feature : getFeatures(repositories, delFeatures)) {
+        // TODO: add region information and avoid flattening
+        for (Feature feature : apply(flatten(delFeatures), map(dstate.features))) {
             callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureUninstalled, false));
         }
-        for (Feature feature : getFeatures(repositories, newFeatures)) {
+        for (Feature feature : apply(flatten(newFeatures), map(dstate.features))) {
             callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false));
         }
 
         print("Done.", verbose);
     }
 
+    private void computeBundlesToRefresh(Set<Bundle> toRefresh, Collection<Bundle> bundles, Map<Resource, Bundle> resources, Map<Resource, List<Wire>> resolution) {
+        int size;
+        do {
+            size = toRefresh.size();
+            for (Bundle bundle : bundles) {
+                // Continue if we already know about this bundle
+                if (toRefresh.contains(bundle)) {
+                    continue;
+                }
+                // Ignore non resolved bundle
+                BundleWiring wiring = bundle.adapt(BundleWiring.class);
+                if (wiring == null) {
+                    continue;
+                }
+                // Get through the old resolution and flag this bundle
+                // if it was wired to a bundle to be refreshed
+                for (BundleWire wire : wiring.getRequiredWires(null)) {
+                    if (toRefresh.contains(wire.getProvider().getBundle())) {
+                        toRefresh.add(bundle);
+                        break;
+                    }
+                }
+                // Get through the new resolution and flag this bundle
+                // if it's wired to any new bundle
+                List<Wire> newWires = resolution.get(wiring.getRevision());
+                if (newWires != null) {
+                    for (Wire wire : newWires) {
+                        Bundle b;
+                        if (wire.getProvider() instanceof BundleRevision) {
+                            b = ((BundleRevision) wire.getProvider()).getBundle();
+                        } else {
+                            b = resources.get(wire.getProvider());
+                        }
+                        if (b == null || toRefresh.contains(b)) {
+                            toRefresh.add(bundle);
+                            break;
+                        }
+                    }
+                }
+            }
+        } while (toRefresh.size() > size);
+    }
+
     private void addTransitive(Resource resource, Set<Resource> resources, Map<Resource, List<Wire>> resolution) {
         if (resources.add(resource)) {
             for (Wire wire : resolution.get(resource)) {
@@ -1317,15 +1327,6 @@ public class FeaturesServiceImpl implements FeaturesService {
         }
     }
 
-    protected BundleInfo mergeBundleInfo(BundleInfo bi1, BundleInfo bi2) {
-        org.apache.karaf.features.internal.model.Bundle bi = new org.apache.karaf.features.internal.model.Bundle();
-        bi.setLocation(bi1.getLocation());
-        bi.setDependency(bi1.isDependency() && bi2.isDependency());
-        bi.setStart(bi1.isStart() || bi2.isStart());
-        bi.setStartLevel(Math.min(bi1.getStartLevel(), bi2.getStartLevel()));
-        return bi;
-    }
-
     private void print(String message, boolean verbose) {
         LOGGER.info(message);
         if (verbose) {
@@ -1334,10 +1335,11 @@ public class FeaturesServiceImpl implements FeaturesService {
     }
 
     private void removeFragmentsAndBundlesInState(Collection<Bundle> bundles, int state) {
-        for (Bundle bundle : new ArrayList<Bundle>(bundles)) {
+        for (Iterator<Bundle> iterator = bundles.iterator(); iterator.hasNext();) {
+            Bundle bundle = iterator.next();
             if ((bundle.getState() & state) != 0
-                     || bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) {
-                bundles.remove(bundle);
+                    || bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) {
+                iterator.remove();
             }
         }
     }
@@ -1369,6 +1371,7 @@ public class FeaturesServiceImpl implements FeaturesService {
     }
 
     protected Deployment computeDeployment(
+                                DeploymentState dstate,
                                 SubsystemResolver resolver,
                                 State state) throws IOException {
 
@@ -1400,7 +1403,7 @@ public class FeaturesServiceImpl implements FeaturesService {
             // as either to ignore or delete
             for (long bundleId : managed) {
                 // Look for the installed bundle
-                Bundle bundle = systemBundleContext.getBundle(bundleId);
+                Bundle bundle = dstate.bundles.get(bundleId);
                 // Bundle has been manually uninstalled ?
                 if (bundle != null) {
                     // Look for a matching resource
@@ -1432,8 +1435,8 @@ public class FeaturesServiceImpl implements FeaturesService {
                                     if (newCrc != oldCrc) {
                                         LOGGER.debug("New snapshot available for " + bundle.getLocation());
                                         deployment.toUpdate.put(bundle, resource);
-                                        result.newCheckums.put(bundle.getBundleId(), newCrc);
                                     }
+                                    result.bundleChecksums.put(bundle.getBundleId(), newCrc);
                                 } finally {
                                     if (is != null) {
                                         is.close();
@@ -1483,40 +1486,24 @@ public class FeaturesServiceImpl implements FeaturesService {
         return result;
     }
 
-    protected List<Feature> getFeatures(Repository[] repositories, List<String> featureIds) throws Exception {
-        List<Feature> installedFeatures = new ArrayList<Feature>();
-        for (Repository repository : repositories) {
-            for (Feature feature : repository.getFeatures()) {
-                String id = feature.getName() + "/" + VersionTable.getVersion(feature.getVersion());
-                if (featureIds.contains(id)) {
-                    installedFeatures.add(feature);
-                }
+    protected <T> MapUtils.Function<Bundle, T> adapt(final Class<T> clazz) {
+        return new MapUtils.Function<Bundle, T>() {
+            @Override
+            public T apply(Bundle bundle) {
+                return bundle.adapt(clazz);
             }
-        }
-        return installedFeatures;
+        };
     }
 
-    protected Map<String, Set<String>> getInstalledFeatures(SubsystemResolver resolver) {
-        Map<String, Set<String>> installed = new HashMap<String, Set<String>>();
-        Map<String, Set<Resource>> mapping = resolver.getFeaturesPerRegions();
-        for (Map.Entry<String, Set<Resource>> entry : mapping.entrySet()) {
-            for (Resource resource : entry.getValue()) {
-                addToMapSet(installed, entry.getKey(), getFeatureId(resource));
+    protected MapUtils.Function<Resource, String> featureId() {
+        return new MapUtils.Function<Resource, String>() {
+            @Override
+            public String apply(Resource resource) {
+                return getFeatureId(resource);
             }
-        }
-        return installed;
+        };
     }
 
-    protected List<String> getFeatureIds(Collection<Resource> allResources) {
-        List<String> installedFeatureIds = new ArrayList<String>();
-        for (Resource resource : allResources) {
-            String id = getFeatureId(resource);
-            if (id != null) {
-                installedFeatureIds.add(id);
-            }
-        }
-        return installedFeatureIds;
-    }
 
     protected boolean isUpdateable(Resource resource) {
         String uri = getUri(resource);
@@ -1649,7 +1636,7 @@ public class FeaturesServiceImpl implements FeaturesService {
 
 
     static class Deployment {
-        Map<Long, Long> newCheckums = new HashMap<Long, Long>();
+        Map<Long, Long> bundleChecksums = new HashMap<Long, Long>();
         Map<Resource, Bundle> resToBnd = new HashMap<Resource, Bundle>();
         Map<String, RegionDeployment> regions = new HashMap<String, RegionDeployment>();
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
index df4d901..387e040 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
@@ -22,13 +22,13 @@ import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static org.apache.karaf.features.internal.util.MapUtils.copyMapSet;
+import org.apache.karaf.features.internal.util.MapUtils;
 
 public class State {
 
     public final AtomicBoolean bootDone = new AtomicBoolean();
     public final Set<String> repositories = new TreeSet<String>();
-    public final Map<String, Set<String>> features = new HashMap<String, Set<String>>();
+    public final Map<String, Set<String>> requestedFeatures = new HashMap<String, Set<String>>();
     public final Map<String, Set<String>> installedFeatures = new HashMap<String, Set<String>>();
     public final Map<String, Set<Long>> managedBundles = new HashMap<String, Set<Long>>();
     public final Map<Long, Long> bundleChecksums = new HashMap<Long, Long>();
@@ -36,20 +36,12 @@ public class State {
     public State copy() {
         State state = new State();
         state.bootDone.set(bootDone.get());
-        copySet(repositories, state.repositories);
-        copyMapSet(features, state.features);
-        copyMapSet(installedFeatures, state.installedFeatures);
-        copyMapSet(managedBundles, state.managedBundles);
-        copyMap(bundleChecksums, state.bundleChecksums);
+        MapUtils.copy(repositories, state.repositories);
+        MapUtils.copy(requestedFeatures, state.requestedFeatures);
+        MapUtils.copy(installedFeatures, state.installedFeatures);
+        MapUtils.copy(managedBundles, state.managedBundles);
+        MapUtils.copy(bundleChecksums, state.bundleChecksums);
         return state;
     }
 
-    static <T> void copySet(Set<T> from, Set<T> to) {
-        to.addAll(from);
-    }
-
-    static <S, T> void copyMap(Map<S, T> from, Map<S, T> to) {
-        to.putAll(from);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
index 3b3424f..1b0a728 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
@@ -33,7 +33,7 @@ public abstract class StateStorage {
 
     public void load(State state) throws IOException {
         state.repositories.clear();
-        state.features.clear();
+        state.requestedFeatures.clear();
         state.installedFeatures.clear();
         state.managedBundles.clear();
         InputStream is = getInputStream();
@@ -42,7 +42,7 @@ public abstract class StateStorage {
                 Map json = (Map) JsonReader.read(is);
                 state.bootDone.set((Boolean) json.get("bootDone"));
                 state.repositories.addAll(toStringSet((Collection) json.get("repositories")));
-                state.features.putAll(toStringStringSetMap((Map) json.get("features")));
+                state.requestedFeatures.putAll(toStringStringSetMap((Map) json.get("features")));
                 state.installedFeatures.putAll(toStringStringSetMap((Map) json.get("installed")));
                 state.managedBundles.putAll(toStringLongSetMap((Map) json.get("managed")));
                 state.bundleChecksums.putAll(toLongLongMap((Map) json.get("checksums")));
@@ -59,7 +59,7 @@ public abstract class StateStorage {
                 Map<String, Object> json = new HashMap<String, Object>();
                 json.put("bootDone", state.bootDone.get());
                 json.put("repositories", state.repositories);
-                json.put("features", state.features);
+                json.put("features", state.requestedFeatures);
                 json.put("installed", state.installedFeatures);
                 json.put("managed", state.managedBundles);
                 json.put("checksums", toStringLongMap(state.bundleChecksums));

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
index 455ceda..0a21e29 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/MapUtils.java
@@ -16,21 +16,158 @@
  */
 package org.apache.karaf.features.internal.util;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 public class MapUtils {
 
+    public interface Function<T, U> {
+        U apply(T t);
+    }
+
     public static <S, T> Map<S, Set<T>> invert(Map<T, S> map) {
-        Map<S, Set<T>> inverted = new HashMap<S, Set<T>>();
+        Map<S, Set<T>> inverted = new HashMap<S, Set<T>>(map.size());
         for (Map.Entry<T, S> entry : map.entrySet()) {
             addToMapSet(inverted, entry.getValue(), entry.getKey());
         }
         return inverted;
     }
 
+    public static <S, T, U> Map<S, Set<U>> apply(Map<S, Set<T>> mapset, Function<T, U> function) {
+        Map<S, Set<U>> result = new HashMap<S, Set<U>>(mapset.size());
+        for (Map.Entry<S, Set<T>> entry : mapset.entrySet()) {
+            result.put(entry.getKey(), apply(entry.getValue(), function));
+        }
+        return result;
+    }
+
+    public static <U, T> Set<U> apply(Set<T> set, Function<T, U> function) {
+        Set<U> result = new HashSet<U>(set.size());
+        for (T t : set) {
+            result.add(function.apply(t));
+        }
+        return result;
+    }
+
+    public static <S, T, U> Map<T, U> build(Collection<S> col, Function<S, T> key, Function<S, U> value) {
+        Map<T, U> result = new HashMap<T, U>(col.size());
+        for (S s : col) {
+            result.put(key.apply(s), value.apply(s));
+        }
+        return result;
+    }
+
+    public static <S, T, U> Function<S, U> compose(final Function<S, T> f1, final Function<T, U> f2) {
+        return new Function<S, U>() {
+            @Override
+            public U apply(S s) {
+                return f2.apply(f1.apply(s));
+            }
+        };
+    }
+
+    public static <T, U> MapUtils.Function<T, U> map(final Map<T, U> map) {
+        return new MapUtils.Function<T, U>() {
+            @Override
+            public U apply(T t) {
+                return map.get(t);
+            }
+        };
+    }
+
+    public static <S, T> Set<T> flatten(Map<S, Set<T>> mapset) {
+        Set<T> set = new HashSet<T>();
+        for (Set<T> s : mapset.values()) {
+            set.addAll(s);
+        }
+        return set;
+    }
+
+    public static <S, T> Map<S, Set<T>> diff(Map<S, Set<T>> from, Map<S, Set<T>> to) {
+        Map<S, Set<T>> diff = copyMapSet(from);
+        remove(diff, to);
+        return diff;
+    }
+
+    public static <S, T> void add(Map<S, Set<T>> from, Map<S, Set<T>> toAdd) {
+        for (Map.Entry<S, Set<T>> entry : toAdd.entrySet()) {
+            Set<T> s = from.get(entry.getKey());
+            if (s == null) {
+                s = new HashSet<T>();
+                from.put(entry.getKey(), s);
+            }
+            s.addAll(entry.getValue());
+        }
+    }
+
+    public static <S, T> void retain(Map<S, Set<T>> from, Map<S, Set<T>> toRetain) {
+        for (Iterator<Map.Entry<S, Set<T>>> iterator = from.entrySet().iterator(); iterator.hasNext();) {
+            Map.Entry<S, Set<T>> entry = iterator.next();
+            Set<T> s = toRetain.get(entry.getKey());
+            if (s != null) {
+                entry.getValue().retainAll(s);
+            } else {
+                iterator.remove();
+            }
+        }
+    }
+
+    public static <S, T> void remove(Map<S, Set<T>> from, Map<S, Set<T>> toRemove) {
+        for (Map.Entry<S, Set<T>> entry : toRemove.entrySet()) {
+            Set<T> s = from.get(entry.getKey());
+            if (s != null) {
+                s.removeAll(entry.getValue());
+                if (s.isEmpty()) {
+                    from.remove(entry.getKey());
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <S> S copy(S obj) {
+        if (obj instanceof List) {
+            List r = new ArrayList();
+            for (Object o : (List) obj) {
+                r.add(copy(o));
+            }
+            return (S) r;
+        } else if (obj instanceof Set) {
+            Set r = new HashSet();
+            for (Object o : (Set) obj) {
+                r.add(copy(o));
+            }
+            return (S) r;
+        } else if (obj instanceof Map) {
+            Map r = new HashMap();
+            for (Map.Entry<?,?> e : ((Map<?,?>) obj).entrySet()) {
+                r.put(copy(e.getKey()), copy(e.getValue()));
+            }
+            return (S) r;
+        }
+        return obj;
+    }
+
+    public static <S> void copy(S s1, S s2) {
+        if (s1 instanceof Collection) {
+            for (Object o : (Collection) s1) {
+                ((Collection) s2).add(copy(o));
+            }
+        } else if (s1 instanceof Map) {
+            for (Map.Entry<?,?> e : ((Map<?,?>) s1).entrySet()) {
+                ((Map) s2).put(copy(e.getKey()), copy(e.getValue()));
+            }
+        } else {
+            throw new IllegalArgumentException("Source is not a Collection or a Map");
+        }
+    }
+
     public static <S, T> Map<S, Set<T>> copyMapSet(Map<S, Set<T>> from) {
         Map<S, Set<T>> to = new HashMap<S, Set<T>>();
         copyMapSet(from, to);

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
index a027290..5e8edd5 100644
--- a/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/region/SubsystemTest.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -62,7 +63,7 @@ public class SubsystemTest {
         addToMapSet(expected, "root/apps1", "b/1.0.0");
 
         SubsystemResolver resolver = new SubsystemResolver(new TestDownloadManager("data1"));
-        resolver.resolve(Collections.<Repository>singletonList(repo),
+        resolver.resolve(Arrays.asList(repo.getFeatures()),
                          features,
                          Collections.<String, Set<BundleRevision>>emptyMap(),
                          Collections.<String>emptySet(),
@@ -93,7 +94,7 @@ public class SubsystemTest {
         addToMapSet(expected, "root/apps2#f1", "a/1.0.0");
 
         SubsystemResolver resolver = new SubsystemResolver(new TestDownloadManager("data2"));
-        resolver.resolve(Collections.<Repository>singletonList(repo),
+        resolver.resolve(Arrays.asList(repo.getFeatures()),
                          features,
                          Collections.<String, Set<BundleRevision>>emptyMap(),
                          Collections.<String>emptySet(),
@@ -114,12 +115,12 @@ public class SubsystemTest {
         addToMapSet(expected, "root/apps1", "a/1.0.1");
 
         SubsystemResolver resolver = new SubsystemResolver(new TestDownloadManager("data3"));
-        resolver.resolve(Collections.<Repository>singletonList(repo),
-                features,
-                Collections.<String, Set<BundleRevision>>emptyMap(),
-                Collections.singleton("b"),
-                FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE,
-                null);
+        resolver.resolve(Arrays.asList(repo.getFeatures()),
+                         features,
+                         Collections.<String, Set<BundleRevision>>emptyMap(),
+                         Collections.singleton("b"),
+                         FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE,
+                         null);
 
         verify(resolver, expected);
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/d8e6ae44/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
index 5bee904..857936c 100644
--- a/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/StateStorageTest.java
@@ -37,7 +37,7 @@ public class StateStorageTest {
         State oldState = new State();
         oldState.bootDone.set(true);
         oldState.bundleChecksums.put(4l, 32794l);
-        oldState.features.put("bar", Collections.singleton("f1"));
+        oldState.requestedFeatures.put("bar", Collections.singleton("f1"));
         oldState.managedBundles.put("reg", Collections.singleton(32l));
         oldState.managedBundles.put("reg2", new HashSet<Long>(Arrays.asList(24l, 43l)));
         oldState.repositories.add("repo");
@@ -53,7 +53,7 @@ public class StateStorageTest {
 
         assertEquals(oldState.bootDone.get(), newState.bootDone.get());
         assertEquals(oldState.bundleChecksums, newState.bundleChecksums);
-        assertEquals(oldState.features, newState.features);
+        assertEquals(oldState.requestedFeatures, newState.requestedFeatures);
         assertEquals(oldState.managedBundles, newState.managedBundles);
         assertEquals(oldState.repositories, newState.repositories);
     }