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);
}