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 2015/02/13 18:23:03 UTC
karaf git commit: [KARAF-3529] Make sure the framework resolver uses
the already computed resolution Improve the computation of bundles in need of
a refresh
Repository: karaf
Updated Branches:
refs/heads/master 6d2989580 -> 7ab5cda1c
[KARAF-3529] Make sure the framework resolver uses the already computed resolution
Improve the computation of bundles in need of a refresh
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/7ab5cda1
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/7ab5cda1
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/7ab5cda1
Branch: refs/heads/master
Commit: 7ab5cda1c5a1e721aaa4383eab3b549c566ee87e
Parents: 6d29895
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Feb 13 18:08:38 2015 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Feb 13 18:08:38 2015 +0100
----------------------------------------------------------------------
.../features/internal/service/Deployer.java | 101 ++++++++++++++-----
.../internal/service/FeaturesServiceImpl.java | 78 +++++++++++++-
.../features/internal/service/DeployerTest.java | 23 ++++-
.../features/VerifyFeatureResolutionMojo.java | 4 +-
4 files changed, 172 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/7ab5cda1/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
index 61dd5c7..3b7d18d 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java
@@ -56,10 +56,15 @@ import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.HostNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
import org.osgi.framework.startlevel.BundleStartLevel;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import org.osgi.resource.Wire;
import org.osgi.service.repository.Repository;
@@ -115,7 +120,7 @@ public class Deployer {
void setBundleStartLevel(Bundle bundle, int startLevel);
void refreshPackages(Collection<Bundle> bundles) throws InterruptedException;
- void resolveBundles(Set<Bundle> bundles);
+ void resolveBundles(Set<Bundle> bundles, Map<Resource, List<Wire>> wiring, Map<Resource, Bundle> resToBnd);
void replaceDigraph(Map<String, Map<String,Map<String,Set<String>>>> policies, Map<String, Set<Long>> bundles) throws BundleException, InvalidSyntaxException;
}
@@ -757,7 +762,7 @@ public class Deployer {
toResolve.addAll(toStart);
toResolve.addAll(toRefresh.keySet());
removeFragmentsAndBundlesInState(toResolve, UNINSTALLED);
- callback.resolveBundles(toResolve);
+ callback.resolveBundles(toResolve, resolver.getWiring(), deployment.resToBnd);
// Compute bundles to start
removeFragmentsAndBundlesInState(toStart, UNINSTALLED | ACTIVE | STARTING);
@@ -870,9 +875,18 @@ public class Deployer {
}
// Main loop
int size;
+ Map<Bundle, Resource> bndToRes = new HashMap<>();
+ for (Map.Entry<Resource, Bundle> entry : resources.entrySet()) {
+ bndToRes.put(entry.getValue(), entry.getKey());
+ }
do {
size = toRefresh.size();
- for (Bundle bundle : bundles) {
+ main: for (Bundle bundle : bundles) {
+ Resource resource = bndToRes.get(bundle);
+ // This bundle is not managed
+ if (resource == null) {
+ continue;
+ }
// Continue if we already know about this bundle
if (toRefresh.containsKey(bundle)) {
continue;
@@ -882,6 +896,11 @@ public class Deployer {
if (wiring == null) {
continue;
}
+ // Ignore bundles that won't be wired
+ List<Wire> newWires = resolution.get(resource);
+ if (newWires == null) {
+ continue;
+ }
// Check if this bundle is a host and its fragments changed
Set<Resource> oldFragments = new HashSet<>();
for (BundleWire wire : wiring.getProvidedWires(null)) {
@@ -893,37 +912,67 @@ public class Deployer {
toRefresh.put(bundle, "Attached fragments changed: " + new ArrayList<>(newFragments.get(bundle)));
break;
}
- // Get through the old resolution and flag this bundle
- // if it was wired to a bundle to be refreshed
+ // Compare the old and new resolutions
+ Set<Resource> wiredBundles = new HashSet<>();
for (BundleWire wire : wiring.getRequiredWires(null)) {
- Bundle provider = wire.getProvider().getBundle();
+ BundleRevision rev = wire.getProvider();
+ Bundle provider = rev.getBundle();
if (toRefresh.containsKey(provider)) {
+ // The bundle is wired to a bundle being refreshed,
+ // so we need to refresh it too
toRefresh.put(bundle, "Wired to " + provider.getSymbolicName() + "/" + provider.getVersion() + " which is being refreshed");
- break;
+ continue main;
}
+ Resource res = bndToRes.get(provider);
+ wiredBundles.add(res != null ? res : rev);
}
- // 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) {
- if (!isBundle(wire.getProvider())) {
- continue;
- }
- Bundle b;
- if (wire.getProvider() instanceof BundleRevision) {
- b = ((BundleRevision) wire.getProvider()).getBundle();
+ Map<Resource, Requirement> wiredResources = new HashMap<>();
+ for (Wire wire : newWires) {
+ // Handle only packages, hosts, and required bundles
+ String namespace = wire.getRequirement().getNamespace();
+ if (!namespace.equals(BundleNamespace.BUNDLE_NAMESPACE)
+ && !namespace.equals(PackageNamespace.PACKAGE_NAMESPACE)
+ && !namespace.equals(HostNamespace.HOST_NAMESPACE)) {
+ continue;
+ }
+ // Ignore non-resolution time requirements
+ String effective = wire.getRequirement().getDirectives().get(Namespace.CAPABILITY_EFFECTIVE_DIRECTIVE);
+ if (effective != null && !Namespace.EFFECTIVE_RESOLVE.equals(effective)) {
+ continue;
+ }
+ // Ignore non bundle resources
+ if (!isBundle(wire.getProvider())) {
+ continue;
+ }
+ // Ignore bundles that won't get deployed for some reason
+ if (!resources.containsKey(wire.getProvider())
+ && !(wire.getProvider() instanceof BundleRevision)) {
+ continue;
+ }
+ if (!wiredResources.containsKey(wire.getProvider())) {
+ wiredResources.put(wire.getProvider(), wire.getRequirement());
+ }
+ }
+ if (!wiredBundles.containsAll(wiredResources.keySet())) {
+ Map<Resource, Requirement> newResources = new HashMap<>(wiredResources);
+ newResources.keySet().removeAll(wiredBundles);
+ StringBuilder sb = new StringBuilder();
+ sb.append("Should be wired to: ");
+ boolean first = true;
+ for (Map.Entry<Resource, Requirement> entry : newResources.entrySet()) {
+ if (!first) {
+ sb.append(", ");
} else {
- b = resources.get(wire.getProvider());
- }
- if (b == null) {
- toRefresh.put(bundle, "Wired to a new bundle " + wire.getProvider());
- break;
- } else if (toRefresh.containsKey(b)) {
- toRefresh.put(bundle, "Wired to " + b.getSymbolicName() + "/" + b.getVersion() + " which is being refreshed");
- break;
+ first = false;
}
+ Resource res = entry.getKey();
+ Requirement req = entry.getValue();
+ sb.append(getSymbolicName(res)).append("/").append(getVersion(res));
+ sb.append(" (through ");
+ sb.append(req);
+ sb.append(")");
}
+ toRefresh.put(bundle, sb.toString());
}
}
} while (toRefresh.size() > size);
http://git-wip-us.apache.org/repos/asf/karaf/blob/7ab5cda1/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 608bf78..42776a1 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
@@ -31,6 +31,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -72,10 +73,19 @@ import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Version;
+import org.osgi.framework.hooks.resolver.ResolverHook;
+import org.osgi.framework.hooks.resolver.ResolverHookFactory;
import org.osgi.framework.startlevel.BundleStartLevel;
import org.osgi.framework.startlevel.FrameworkStartLevel;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.FrameworkWiring;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.slf4j.Logger;
@@ -1150,8 +1160,72 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall
}
@Override
- public void resolveBundles(Set<Bundle> bundles) {
- systemBundleContext.getBundle().adapt(FrameworkWiring.class).resolveBundles(bundles);
+ public void resolveBundles(Set<Bundle> bundles, final Map<Resource, List<Wire>> wiring, Map<Resource, Bundle> resToBnd) {
+ // Make sure it's only used for us
+ final Thread thread = Thread.currentThread();
+ // Translate wiring
+ final Map<Bundle, Resource> bndToRes = new HashMap<>();
+ for (Resource res : resToBnd.keySet()) {
+ bndToRes.put(resToBnd.get(res), res);
+ }
+ // Hook
+ final ResolverHook hook = new ResolverHook() {
+ @Override
+ public void filterResolvable(Collection<BundleRevision> candidates) {
+ }
+ @Override
+ public void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates) {
+ }
+ @Override
+ public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) {
+ if (Thread.currentThread() == thread) {
+ Bundle sourceBundle = requirement.getRevision().getBundle();
+ Resource sourceResource = bndToRes.get(sourceBundle);
+ for (Wire wire : wiring.get(sourceResource)) {
+ Requirement req = wire.getRequirement();
+ if (req.getNamespace().equals(requirement.getNamespace())
+ && req.getAttributes().equals(requirement.getAttributes())
+ && req.getDirectives().equals(requirement.getDirectives())) {
+ for (Iterator<BundleCapability> capIter = candidates.iterator(); capIter.hasNext(); ) {
+ BundleCapability cap = capIter.next();
+ BundleRevision br = cap.getRevision();
+ if (br == wire.getCapability().getResource()) {
+ continue;
+ }
+ Resource res = bndToRes.get(br.getBundle());
+ if (res != wire.getCapability().getResource()) {
+ capIter.remove();
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ @Override
+ public void end() {
+ }
+ };
+ ResolverHookFactory factory = new ResolverHookFactory() {
+ @Override
+ public ResolverHook begin(Collection<BundleRevision> triggers) {
+ return hook;
+ }
+ };
+ ServiceRegistration<ResolverHookFactory> registration = systemBundleContext.registerService(ResolverHookFactory.class, factory, null);
+ try {
+ // Given we already have computed the wiring,
+ // there's no need to resolve the bundles all at the same time.
+ // It's much more efficient to resolve them by small chunks.
+ // We could be even smarter and order the bundles according to the
+ // order given by RequirementSort to minimize the size of needed chunks.
+ FrameworkWiring frameworkWiring = systemBundleContext.getBundle().adapt(FrameworkWiring.class);
+ for (Bundle bundle : bundles) {
+ frameworkWiring.resolveBundles(Collections.singleton(bundle));
+ }
+ } finally {
+ registration.unregister();
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/karaf/blob/7ab5cda1/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
index 3a43bda..067f84f 100644
--- a/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/DeployerTest.java
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Hashtable;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Manifest;
@@ -39,6 +40,8 @@ import org.easymock.IArgumentMatcher;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
import static org.apache.karaf.features.FeaturesService.*;
import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
@@ -72,7 +75,9 @@ public class DeployerTest {
EasyMock.expectLastCall();
callback.installFeatureConfigs(f100);
EasyMock.expectLastCall();
- callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject());
+ callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject(),
+ EasyMock.<Map<Resource, List<Wire>>>anyObject(),
+ EasyMock.<Map<Resource, Bundle>>anyObject());
EasyMock.expectLastCall();
callback.callListeners(EasyMock.<FeatureEvent>anyObject());
EasyMock.expectLastCall();
@@ -161,7 +166,9 @@ public class DeployerTest {
EasyMock.expectLastCall();
callback.installFeatureConfigs(f101);
EasyMock.expectLastCall();
- callback.resolveBundles(EasyMock.eq(Collections.<Bundle>singleton(bundleA)));
+ callback.resolveBundles(EasyMock.eq(Collections.<Bundle>singleton(bundleA)),
+ EasyMock.<Map<Resource, List<Wire>>>anyObject(),
+ EasyMock.<Map<Resource, Bundle>>anyObject());
EasyMock.expectLastCall();
callback.refreshPackages(EasyMock.eq(Collections.<Bundle>singleton(bundleA)));
EasyMock.expectLastCall();
@@ -227,7 +234,9 @@ public class DeployerTest {
EasyMock.expectLastCall();
callback.installFeatureConfigs(f1);
EasyMock.expectLastCall();
- callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject());
+ callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject(),
+ EasyMock.<Map<Resource, List<Wire>>>anyObject(),
+ EasyMock.<Map<Resource, Bundle>>anyObject());
EasyMock.expectLastCall();
callback.callListeners(EasyMock.<FeatureEvent>anyObject());
EasyMock.expectLastCall();
@@ -289,7 +298,9 @@ public class DeployerTest {
EasyMock.expectLastCall();
callback.installFeatureConfigs(f1);
EasyMock.expectLastCall();
- callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject());
+ callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject(),
+ EasyMock.<Map<Resource, List<Wire>>>anyObject(),
+ EasyMock.<Map<Resource, Bundle>>anyObject());
EasyMock.expectLastCall();
callback.callListeners(EasyMock.<FeatureEvent>anyObject());
EasyMock.expectLastCall();
@@ -339,7 +350,9 @@ public class DeployerTest {
EasyMock.expectLastCall();
callback.installFeatureConfigs(f2);
EasyMock.expectLastCall();
- callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject());
+ callback.resolveBundles(EasyMock.<Set<Bundle>>anyObject(),
+ EasyMock.<Map<Resource, List<Wire>>>anyObject(),
+ EasyMock.<Map<Resource, Bundle>>anyObject());
EasyMock.expectLastCall();
callback.callListeners(EasyMock.<FeatureEvent>anyObject());
EasyMock.expectLastCall();
http://git-wip-us.apache.org/repos/asf/karaf/blob/7ab5cda1/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
index a68c6b0..d196c44 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java
@@ -108,6 +108,8 @@ import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
import org.osgi.service.resolver.ResolutionException;
import shaded.org.ops4j.util.property.PropertiesPropertyResolver;
@@ -742,7 +744,7 @@ public class VerifyFeatureResolutionMojo extends MojoSupport {
}
@Override
- public void resolveBundles(Set<Bundle> bundles) {
+ public void resolveBundles(Set<Bundle> bundles, Map<Resource, List<Wire>> wiring, Map<Resource, Bundle> resToBnd) {
}
@Override