diff options
Diffstat (limited to 'bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java')
-rwxr-xr-x | bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java | 126 |
1 files changed, 90 insertions, 36 deletions
diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java index 7735df71f..09f9ec56a 100755 --- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java +++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java @@ -53,7 +53,7 @@ public class ResolverImpl implements Resolver // Note this class is not thread safe. // Only use in the context of a single thread. - static class ResolveSession + static class ResolveSession implements Runnable { // Holds the resolve context for this session private final ResolveContext m_resolveContext; @@ -62,9 +62,11 @@ public class ResolverImpl implements Resolver private final Resource m_dynamicHost; private final Requirement m_dynamicReq; private final List<Capability> m_dynamicCandidates; - // keeps track of valid on demand fragments that we have seen. + // keeps track of valid related resources that we have seen. // a null value or TRUE indicate it is valid - Map<Resource, Boolean> m_validOnDemandResources = new HashMap<Resource, Boolean>(0); + private Map<Resource, Boolean> m_validRelatedResources = new HashMap<Resource, Boolean>(0); + // keeps track of related resources for each resource + private Map<Resource, Collection<Resource>> m_relatedResources = new HashMap<Resource, Collection<Resource>>(0); // Holds candidate permutations based on permutating "uses" chains. // These permutations are given higher priority. private final List<Candidates> m_usesPermutations = new LinkedList<Candidates>(); @@ -88,8 +90,19 @@ public class ResolverImpl implements Resolver private final Set<Requirement> m_sub_mutated = new HashSet<Requirement>(); private final ConcurrentMap<String, List<String>> m_usesCache = new ConcurrentHashMap<String, List<String>>(); private ResolutionError m_currentError; + volatile private CancellationException m_isCancelled = null; - ResolveSession(ResolveContext resolveContext, Executor executor, Resource dynamicHost, Requirement dynamicReq, List<Capability> dynamicCandidates) + static ResolveSession createSession(ResolveContext resolveContext, Executor executor, Resource dynamicHost, Requirement dynamicReq, List<Capability> dynamicCandidates) + { + ResolveSession session = new ResolveSession(resolveContext, executor, dynamicHost, dynamicReq, dynamicCandidates); + // call onCancel first + session.getContext().onCancel(session); + // now gather the mandatory and optional resources + session.initMandatoryAndOptionalResources(); + return session; + } + + private ResolveSession(ResolveContext resolveContext, Executor executor, Resource dynamicHost, Requirement dynamicReq, List<Capability> dynamicCandidates) { m_resolveContext = resolveContext; m_executor = executor; @@ -100,12 +113,18 @@ public class ResolverImpl implements Resolver m_mandatoryResources = Collections.singletonList(dynamicHost); m_optionalResources = Collections.emptyList(); } else { - // Make copies of arguments in case we want to modify them. - m_mandatoryResources = new ArrayList<Resource>(resolveContext.getMandatoryResources()); - m_optionalResources = new ArrayList<Resource>(resolveContext.getOptionalResources()); + // Do not call resolve context yet, onCancel must be called first + m_mandatoryResources = new ArrayList<Resource>(); + m_optionalResources = new ArrayList<Resource>(); } } + private void initMandatoryAndOptionalResources() { + if (!isDynamic()) { + m_mandatoryResources.addAll(getContext().getMandatoryResources()); + m_optionalResources.addAll(getContext().getOptionalResources()); + } + } Candidates getMultipleCardCandidates() { return m_multipleCardCandidates; @@ -281,28 +300,52 @@ public class ResolverImpl implements Resolver return m_dynamicCandidates; } - public boolean isValidOnDemandResource(Resource fragment) { - Boolean valid = m_validOnDemandResources.get(fragment); + public boolean isValidRelatedResource(Resource resource) { + Boolean valid = m_validRelatedResources.get(resource); if (valid == null) { - // Mark this resource as a valid on demand resource - m_validOnDemandResources.put(fragment, Boolean.TRUE); + // Mark this resource as a valid related resource + m_validRelatedResources.put(resource, Boolean.TRUE); valid = Boolean.TRUE; } return valid; } - public boolean invalidateOnDemandResource(Resource faultyResource) { - Boolean valid = m_validOnDemandResources.get(faultyResource); + public boolean invalidateRelatedResource(Resource faultyResource) { + Boolean valid = m_validRelatedResources.get(faultyResource); if (valid != null && valid) { - // This was an ondemand resource. + // This was related resource. // Invalidate it and try again. - m_validOnDemandResources.put(faultyResource, Boolean.FALSE); + m_validRelatedResources.put(faultyResource, Boolean.FALSE); return true; } return false; } + + public Collection<Resource> getRelatedResources(Resource resource) { + Collection<Resource> related = m_relatedResources.get(resource); + return related == null ? Collections.<Resource> emptyList() : related; + } + + public void setRelatedResources(Resource resource, Collection<Resource> related) { + m_relatedResources.put(resource, related); + } + + @Override + public void run() { + m_isCancelled = new CancellationException(); + } + + boolean isCancelled() { + return m_isCancelled != null; + } + + void checkForCancel() throws ResolutionException { + if (isCancelled()) { + throw new ResolutionException("Resolver operation has been cancelled.", m_isCancelled, null); + } + } } public ResolverImpl(Logger logger) @@ -373,13 +416,12 @@ public class ResolverImpl implements Resolver public Map<Resource, List<Wire>> resolve(ResolveContext rc, Executor executor) throws ResolutionException { - ResolveSession session = new ResolveSession(rc, executor, null, null, null); + ResolveSession session = ResolveSession.createSession(rc, executor, null, null, null); return doResolve(session); } private Map<Resource, List<Wire>> doResolve(ResolveSession session) throws ResolutionException { Map<Resource, List<Wire>> wireMap = new HashMap<Resource, List<Wire>>(); - boolean retry; do { @@ -393,6 +435,7 @@ public class ResolverImpl implements Resolver Map<Resource, ResolutionError> faultyResources = new HashMap<Resource, ResolutionError>(); Candidates allCandidates = findValidCandidates(session, faultyResources); + session.checkForCancel(); // If there is a resolve exception, then determine if an // optionally resolved resource is to blame (typically a fragment). @@ -404,7 +447,7 @@ public class ResolverImpl implements Resolver retry = (session.getOptionalResources().removeAll(resourceKeys)); for (Resource faultyResource : resourceKeys) { - if (session.invalidateOnDemandResource(faultyResource)) + if (session.invalidateRelatedResource(faultyResource)) { retry = true; } @@ -432,8 +475,7 @@ public class ResolverImpl implements Resolver } if (session.isDynamic() ) { - wireMap = populateDynamicWireMap(session.getContext(), - session.getDynamicHost(), session.getDynamicRequirement(), + wireMap = populateDynamicWireMap(session, wireMap, allCandidates); } else @@ -444,7 +486,7 @@ public class ResolverImpl implements Resolver { wireMap = populateWireMap( - session.getContext(), allCandidates.getWrappedHost(resource), + session, allCandidates.getWrappedHost(resource), wireMap, allCandidates); } } @@ -551,7 +593,7 @@ public class ResolverImpl implements Resolver } } } - while (session.getCurrentError() != null); + while (!session.isCancelled() && session.getCurrentError() != null); return allCandidates; } @@ -579,6 +621,9 @@ public class ResolverImpl implements Resolver rethrow = checkPackageSpaceConsistency( session, entry.getValue(), allCandidates, session.isDynamic(), resourcePkgMap, resultCache); + if (session.isCancelled()) { + return null; + } if (rethrow != null) { Resource faultyResource = entry.getKey(); @@ -622,7 +667,7 @@ public class ResolverImpl implements Resolver "Matching candidate does not provide a package name."); } } - ResolveSession session = new ResolveSession(context, new DumbExecutor(), host, dynamicRequirement, matches); + ResolveSession session = ResolveSession.createSession(context, new DumbExecutor(), host, dynamicRequirement, matches); return doResolve(session); } @@ -1456,6 +1501,9 @@ public class ResolverImpl implements Resolver rethrow = checkPackageSpaceConsistency( session, cap.getResource(), allCandidates, false, resourcePkgMap, resultCache); + if (session.isCancelled()) { + return null; + } if (rethrow != null) { // If the lower level check didn't create any permutations, @@ -1855,11 +1903,11 @@ public class ResolverImpl implements Resolver } private static Map<Resource, List<Wire>> populateWireMap( - ResolveContext rc, Resource resource, + ResolveSession session, Resource resource, Map<Resource, List<Wire>> wireMap, Candidates allCandidates) { Resource unwrappedResource = getDeclaredResource(resource); - if (!rc.getWirings().containsKey(unwrappedResource) + if (!session.getContext().getWirings().containsKey(unwrappedResource) && !wireMap.containsKey(unwrappedResource)) { wireMap.put(unwrappedResource, Collections.<Wire>emptyList()); @@ -1882,7 +1930,7 @@ public class ResolverImpl implements Resolver || !resource.equals(cand.getResource())) { // Populate wires for the candidate - populateWireMap(rc, cand.getResource(), + populateWireMap(session, cand.getResource(), wireMap, allCandidates); Resource provider; @@ -1962,7 +2010,7 @@ public class ResolverImpl implements Resolver // Otherwise, if the fragment isn't already resolved and // this is the first time we are seeing it, then create // a wire for the non-payload requirement. - else if (!rc.getWirings().containsKey(fragment) + else if (!session.getContext().getWirings().containsKey(fragment) && !wireMap.containsKey(fragment)) { Wire wire = createWire(req, allCandidates); @@ -1978,6 +2026,12 @@ public class ResolverImpl implements Resolver wireMap.put(fragment, fragmentWires); } } + // now make sure any related resources are populated + for (Resource related : session.getRelatedResources(unwrappedResource)) { + if (allCandidates.isPopulated(related)) { + populateWireMap(session, related, wireMap, allCandidates); + } + } } return wireMap; @@ -2012,31 +2066,31 @@ public class ResolverImpl implements Resolver } private static Map<Resource, List<Wire>> populateDynamicWireMap( - ResolveContext rc, Resource resource, Requirement dynReq, - Map<Resource, List<Wire>> wireMap, Candidates allCandidates) + ResolveSession session, Map<Resource, + List<Wire>> wireMap, Candidates allCandidates) { - wireMap.put(resource, Collections.<Wire>emptyList()); + wireMap.put(session.getDynamicHost(), Collections.<Wire>emptyList()); List<Wire> packageWires = new ArrayList<Wire>(); // Get the candidates for the current dynamic requirement. // Record the dynamic candidate. - Capability dynCand = allCandidates.getFirstCandidate(dynReq); + Capability dynCand = allCandidates.getFirstCandidate(session.getDynamicRequirement()); - if (!rc.getWirings().containsKey(dynCand.getResource())) + if (!session.getContext().getWirings().containsKey(dynCand.getResource())) { - populateWireMap(rc, dynCand.getResource(), + populateWireMap(session, dynCand.getResource(), wireMap, allCandidates); } packageWires.add( new WireImpl( - resource, - dynReq, + session.getDynamicHost(), + session.getDynamicRequirement(), getDeclaredResource(dynCand.getResource()), getDeclaredCapability(dynCand))); - wireMap.put(resource, packageWires); + wireMap.put(session.getDynamicHost(), packageWires); return wireMap; } |