[KARAF-2888] Better computation of bundles to refresh and print them in simulation
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/53996d9c Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/53996d9c Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/53996d9c Branch: refs/heads/master Commit: 53996d9c13aa766b590cfa34a77b738df2c50afa Parents: 6a19214 Author: Guillaume Nodet <gno...@gmail.com> Authored: Thu Apr 10 23:39:15 2014 +0200 Committer: Guillaume Nodet <gno...@gmail.com> Committed: Fri Apr 11 19:20:02 2014 +0200 ---------------------------------------------------------------------- .../internal/service/FeaturesServiceImpl.java | 172 ++++++++----------- 1 file changed, 71 insertions(+), 101 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/53996d9c/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java ---------------------------------------------------------------------- diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java index e6dbc32..0bd1e67 100644 --- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java +++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java @@ -69,6 +69,8 @@ import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; +import org.osgi.framework.wiring.BundleWire; +import org.osgi.framework.wiring.BundleWiring; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.resource.Resource; import org.osgi.resource.Wire; @@ -793,7 +795,7 @@ public class FeaturesServiceImpl implements FeaturesService { Collections.<String>emptySet(), overrides, Collections.<String>emptySet()); - Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles, false); + Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles, true); Collection<Resource> allResources = resolution.keySet(); Map<String, StreamProvider> providers = builder.getProviders(); @@ -858,14 +860,76 @@ public class FeaturesServiceImpl implements FeaturesService { // logDeployment(deployment, verbose); + // + // Compute the set of bundles to refresh + // + Set<Bundle> toRefresh = new HashSet<Bundle>(); + toRefresh.addAll(deployment.toDelete); + toRefresh.addAll(deployment.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 = null; + 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); + } + if (noRefreshUnmanaged) { + Set<Bundle> newSet = new HashSet<Bundle>(); + for (Bundle bundle : toRefresh) { + if (managed.contains(bundle.getBundleId())) { + newSet.add(bundle); + } + } + toRefresh = newSet; + } + + if (simulate) { - // TODO: it would be nice to print bundles that will be refreshed - // TODO: it could be done by checking the differences between - // TODO: the resolution result and the actual wiring state + if (!toRefresh.isEmpty()) { + print(" Bundles to refresh:", verbose); + for (Bundle bundle : toRefresh) { + print(" " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose); + } + } return; } - Set<Bundle> toRefresh = new HashSet<Bundle>(); Set<Bundle> toStart = new HashSet<Bundle>(); // @@ -908,7 +972,6 @@ public class FeaturesServiceImpl implements FeaturesService { print(" " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose); bundle.uninstall(); managed.remove(bundle.getBundleId()); - toRefresh.add(bundle); } } if (!deployment.toUpdate.isEmpty()) { @@ -920,7 +983,6 @@ public class FeaturesServiceImpl implements FeaturesService { print(" " + uri, verbose); InputStream is = getBundleInputStream(resource, providers); bundle.update(is); - toRefresh.add(bundle); toStart.add(bundle); BundleInfo bi = bundleInfos.get(uri); if (bi != null && bi.getStartLevel() > 0) { @@ -940,7 +1002,6 @@ public class FeaturesServiceImpl implements FeaturesService { if (!noStart || resourceLinkedToOldFeatures.contains(resource)) { toStart.add(bundle); } - toRefresh.add(bundle); deployment.resToBnd.put(resource, bundle); // save a checksum of installed snapshot bundle if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots) @@ -982,23 +1043,9 @@ public class FeaturesServiceImpl implements FeaturesService { } } - if (!noRefreshManaged) { - findBundlesWithOptionalPackagesToRefresh(toRefresh); - findBundlesWithFragmentsToRefresh(toRefresh); - } - - if (noRefreshUnmanaged) { - Set<Bundle> newSet = new HashSet<Bundle>(); - for (Bundle bundle : toRefresh) { - if (managed.contains(bundle.getBundleId())) { - newSet.add(bundle); - } - } - toRefresh = newSet; - } - // TODO: remove this hack, but it avoids loading the class after the bundle is refreshed - RequirementSort sort = new RequirementSort(); + new CopyOnWriteArrayIdentityList().iterator(); + new RequirementSort(); if (!noRefresh) { toStop = new HashSet<Bundle>(); @@ -1347,83 +1394,6 @@ public class FeaturesServiceImpl implements FeaturesService { return provider.open(); } - protected void findBundlesWithOptionalPackagesToRefresh(Set<Bundle> toRefresh) { - // First pass: include all bundles contained in these features - if (toRefresh.isEmpty()) { - return; - } - Set<Bundle> bundles = new HashSet<Bundle>(Arrays.asList(systemBundleContext.getBundles())); - bundles.removeAll(toRefresh); - if (bundles.isEmpty()) { - return; - } - // Second pass: for each bundle, check if there is any unresolved optional package that could be resolved - for (Bundle bundle : bundles) { - BundleRevision rev = bundle.adapt(BundleRevision.class); - boolean matches = false; - if (rev != null) { - for (BundleRequirement req : rev.getDeclaredRequirements(null)) { - if (PackageNamespace.PACKAGE_NAMESPACE.equals(req.getNamespace()) - && PackageNamespace.RESOLUTION_OPTIONAL.equals(req.getDirectives().get(PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE))) { - // This requirement is an optional import package - for (Bundle provider : toRefresh) { - BundleRevision providerRev = provider.adapt(BundleRevision.class); - if (providerRev != null) { - for (BundleCapability cap : providerRev.getDeclaredCapabilities(null)) { - if (req.matches(cap)) { - matches = true; - break; - } - } - } - if (matches) { - break; - } - } - } - if (matches) { - break; - } - } - } - if (matches) { - toRefresh.add(bundle); - } - } - } - - protected void findBundlesWithFragmentsToRefresh(Set<Bundle> toRefresh) { - if (toRefresh.isEmpty()) { - return; - } - Set<Bundle> bundles = new HashSet<Bundle>(Arrays.asList(systemBundleContext.getBundles())); - bundles.removeAll(toRefresh); - if (bundles.isEmpty()) { - return; - } - for (Bundle bundle : new ArrayList<Bundle>(toRefresh)) { - BundleRevision rev = bundle.adapt(BundleRevision.class); - if (rev != null) { - for (BundleRequirement req : rev.getDeclaredRequirements(null)) { - if (BundleRevision.HOST_NAMESPACE.equals(req.getNamespace())) { - for (Bundle hostBundle : bundles) { - if (!toRefresh.contains(hostBundle)) { - BundleRevision hostRev = hostBundle.adapt(BundleRevision.class); - if (hostRev != null) { - for (BundleCapability cap : hostRev.getDeclaredCapabilities(null)) { - if (req.matches(cap)) { - toRefresh.add(hostBundle); - } - } - } - } - } - } - } - } - } - } - protected void refreshPackages(Collection<Bundle> bundles) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); FrameworkWiring fw = systemBundleContext.getBundle().adapt(FrameworkWiring.class);