diff options
10 files changed, 169 insertions, 98 deletions
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF index 8104043a9..872adf90a 100644 --- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF @@ -71,7 +71,7 @@ Export-Package: org.eclipse.core.runtime.adaptor;x-friends:="org.eclipse.core.ru org.osgi.service.log.admin;version="1.0", org.osgi.service.packageadmin;version="1.2";uses:="org.osgi.framework", org.osgi.service.permissionadmin;version="1.2", - org.osgi.service.resolver;version="1.0.1";uses:="org.osgi.resource", + org.osgi.service.resolver;version="1.1";uses:="org.osgi.resource", org.osgi.service.startlevel;version="1.1";uses:="org.osgi.framework", org.osgi.service.url;version="1.0", org.osgi.util.tracker;version="1.5.1";uses:="org.osgi.framework" diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java index 90321aa1e..d58c142e6 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java @@ -600,7 +600,9 @@ final class ModuleResolver { @Override public List<Capability> findProviders(Requirement requirement) { - return findProviders0(requirement, requirement); + Requirement origReq = requirement; + Requirement lookupReq = dynamicReq == null || dynamicReq.getOriginal() != requirement ? requirement : dynamicReq; + return findProviders0(origReq, lookupReq); } private List<Capability> findProviders0(Requirement origReq, Requirement lookupReq) { @@ -846,7 +848,7 @@ final class ModuleResolver { } @Override - public Collection<Resource> getOndemandResources(Resource host) { + public Collection<Resource> findRelatedResources(Resource host) { List<ModuleCapability> hostCaps = ((ModuleRevision) host).getModuleCapabilities(HostNamespace.HOST_NAMESPACE); if (hostCaps.isEmpty()) { return Collections.emptyList(); @@ -1354,8 +1356,7 @@ final class ModuleResolver { } private Map<Resource, List<Wire>> resolveDynamic() throws ResolutionException { - List<Capability> dynamicMatches = findProviders0(dynamicReq.getOriginal(), dynamicReq); - return new ResolverImpl(new Logger(0), null).resolve(this, dynamicReq.getRevision(), dynamicReq.getOriginal(), dynamicMatches); + return new ResolverImpl(new Logger(0), null).resolveDynamic(this, dynamicReq.getRevision().getWiring(), dynamicReq.getOriginal()); } private void filterResolvable() { diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java index b87c6ac73..af597d487 100755 --- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java +++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java @@ -184,9 +184,9 @@ class Candidates addCandidates(result.candidates); result.candidates = null; result.remaining = null; - if ((rc instanceof FelixResolveContext) && !Util.isFragment(resource)) + if (!Util.isFragment(resource)) { - Collection<Resource> ondemandFragments = ((FelixResolveContext) rc).getOndemandResources(resource); + Collection<Resource> ondemandFragments = rc.findRelatedResources(resource); for (Resource fragment : ondemandFragments) { if (m_session.isValidOnDemandResource(fragment)) diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/FelixResolveContext.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/FelixResolveContext.java index 9782d0a02..ddfb49bcf 100755 --- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/FelixResolveContext.java +++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/FelixResolveContext.java @@ -18,46 +18,22 @@ */package org.apache.felix.resolver; import java.util.Collection; - import org.osgi.framework.namespace.PackageNamespace; -import org.osgi.resource.Resource; -import org.osgi.resource.Wire; -import org.osgi.resource.Wiring; - -public interface FelixResolveContext -{ - /** - * Return the resources that the resolver should attempt to resolve on - * demand for specified resource which is being resolved. Inability to - * resolve one of the on demand resources will not result in a resolution - * exception. - * - * <p> - * The resolver will ask for on demand resources for each resource that is - * getting pulled into a resolve operation. An example of an on demand - * resource is a fragment. When a host is being resolved the resolve context - * will be asked if any additional resources should be added to the resolve - * operation. The resolve context may decide that the potential fragments of - * the host should be resolved along with the host. - * - * @return A collection of the resources that the resolver should attempt to - * resolve for this resolve context. May be empty if there are no on demand - * resources. The returned collection may be unmodifiable. - */ - public Collection<Resource> getOndemandResources(Resource host); +import org.osgi.resource.*; - /** - * Returns the subset of {@link Wiring#getRequiredResourceWires(String) require wires} - * that provide wires to {@link Capability capabilities} which substitute capabilities - * of the given wiring. For example, when a {@link PackageNamespace package} name is both - * provided and required by the same resource. If the package requirement is resolved - * to a capability hosted by a different wiring then the package capability is - * considered to be substituted. - * - * @param wiring the wiring to get the substitution wires from - * @return A collection containing a snapshot of the substitution {@link Wire}s - * for the {@link Requirement requirements} of this wiring, or an empty list - * if this wiring has no substitution wires. - */ - public Collection<Wire> getSubstitutionWires(Wiring wiring); +public interface FelixResolveContext { + /** + * Returns the subset of {@link Wiring#getRequiredResourceWires(String) require wires} + * that provide wires to {@link Capability capabilities} which substitute capabilities + * of the given wiring. For example, when a {@link PackageNamespace package} name is both + * provided and required by the same resource. If the package requirement is resolved + * to a capability hosted by a different wiring then the package capability is + * considered to be substituted. + * + * @param wiring the wiring to get the substitution wires from + * @return A collection containing a snapshot of the substitution {@link Wire}s + * for the {@link Requirement requirements} of this wiring, or an empty list + * if this wiring has no substitution wires. + */ + public Collection<Wire> getSubstitutionWires(Wiring wiring); } 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 128482c27..7735df71f 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 @@ -600,43 +600,18 @@ public class ResolverImpl implements Resolver return error; } - /** - * Resolves a dynamic requirement for the specified host resource using the - * specified {@link ResolveContext}. The dynamic requirement may contain - * wild cards in its filter for the package name. The matching candidates - * are used to resolve the requirement and the resolve context is not asked - * to find providers for the dynamic requirement. The host resource is - * expected to not be a fragment, to already be resolved and have an - * existing wiring provided by the resolve context. - * <p> - * This operation may resolve additional resources in order to resolve the - * dynamic requirement. The returned map will contain entries for each - * resource that got resolved in addition to the specified host resource. - * The wire list for the host resource will only contain a single wire which - * is for the dynamic requirement. - * - * @param rc the resolve context - * @param host the hosting resource - * @param dynamicReq the dynamic requirement - * @param matches a list of matching capabilities - * @return The new resources and wires required to satisfy the specified - * dynamic requirement. The returned map is the property of the caller and - * can be modified by the caller. - * @throws ResolutionException - */ - public Map<Resource, List<Wire>> resolve( - ResolveContext rc, Resource host, Requirement dynamicReq, - List<Capability> matches) - throws ResolutionException + public Map<Resource,List<Wire>> resolveDynamic(ResolveContext context, + Wiring hostWiring, Requirement dynamicRequirement) + throws ResolutionException { + Resource host = hostWiring.getResource(); + List<Capability> matches = context.findProviders(dynamicRequirement); // We can only create a dynamic import if the following // conditions are met: - // 1. The specified resource is resolved. - // 2. The package in question is not already imported. - // 3. The package in question is not accessible via require-bundle. - // 4. The package in question is not exported by the resource. - // 5. The package in question matches a dynamic import of the resource. - if (!matches.isEmpty() && rc.getWirings().containsKey(host)) + // 1. The package in question is not already imported. + // 2. The package in question is not accessible via require-bundle. + // 3. The package in question is not exported by the resource. + if (!matches.isEmpty()) { // Make sure all matching candidates are packages. for (Capability cap : matches) @@ -647,11 +622,11 @@ public class ResolverImpl implements Resolver "Matching candidate does not provide a package name."); } } - ResolveSession session = new ResolveSession(rc, new DumbExecutor(), host, dynamicReq, matches); + ResolveSession session = new ResolveSession(context, new DumbExecutor(), host, dynamicRequirement, matches); return doResolve(session); } - return Collections.emptyMap(); + throw new Candidates.MissingRequirementError(dynamicRequirement).toException(); } private static List<WireCandidate> getWireCandidates(ResolveSession session, Candidates allCandidates, Resource resource) diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/HostedCapability.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/HostedCapability.java index b25092b5e..e6a6917f6 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/HostedCapability.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/HostedCapability.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2012, 2013). All Rights Reserved. + * Copyright (c) OSGi Alliance (2012, 2015). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,7 @@ public interface HostedCapability extends Capability { * * @return The Resource that hosts this Capability. */ + @Override Resource getResource(); /** diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java index 39b26f1a3..4cf3f3568 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java @@ -20,6 +20,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; + import org.osgi.annotation.versioning.ConsumerType; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; @@ -30,7 +32,6 @@ import org.osgi.resource.Wiring; * A resolve context provides resources, options and constraints to the * potential solution of a {@link Resolver#resolve(ResolveContext) resolve} * operation. - * * <p> * Resolve Contexts: * <ul> @@ -46,17 +47,16 @@ import org.osgi.resource.Wiring; * <li>Filter requirements that are part of a resolve operation via the * {@link #isEffective(Requirement)}.</li> * </ul> - * * <p> * A resolver may call the methods on the resolve context any number of times * during a resolve operation using any thread. Implementors should ensure that * this class is properly thread safe. - * * <p> - * Except for {@link #insertHostedCapability(List, HostedCapability)}, the - * resolve context methods must be <i>idempotent</i>. This means that resources - * must have constant capabilities and requirements and the resolve context must - * return a consistent set of capabilities, wires and effective requirements. + * Except for {@link #insertHostedCapability(List, HostedCapability)} and + * {@link #onCancel(Runnable)}, the resolve context methods must be + * <i>idempotent</i>. This means that resources must have constant capabilities + * and requirements and the resolve context must return a consistent set of + * capabilities, wires and effective requirements. * * @ThreadSafe * @author $Id$ @@ -185,4 +185,63 @@ public abstract class ResolveContext { * unmodifiable. */ public abstract Map<Resource, Wiring> getWirings(); + + /** + * Find resources that are related to the given resource. + * <p> + * The resolver attempts to resolve related resources during the current + * resolve operation. Failing to resolve one of the related resources will + * not result in a resolution exception unless the related resource is also + * a {@link #getMandatoryResources() mandatory} resource. + * <p> + * The resolve context is asked to return related resources for each + * resource that is pulled into a resolve operation. This includes the + * {@link #getMandatoryResources() mandatory} and + * {@link #getOptionalResources() optional} resources and each related + * resource returned by this method. + * <p> + * For example, a fragment can be considered a related resource for a host + * bundle. When a host is being resolved the resolve context will be asked + * if any related resources should be added to the resolve operation. The + * resolve context may decide that the potential fragments of the host + * should be resolved along with the host. + * + * @param resource The Resource that a resolver is attempting to find + * related resources for. Must not be {@code null}. + * @return A collection of the resources that the resolver should attempt to + * resolve for this resolve context. May be empty if there are no + * related resources. The returned collection may be unmodifiable. + * @since 1.1 + */ + public Collection<Resource> findRelatedResources(Resource resource) { + return Collections.emptyList(); + } + + /** + * Registers a callback with the resolve context that is associated with the + * currently running resolve operation. The callback can be executed in + * order to cancel the currently running resolve operation. + * <p> + * When a resolve operation begins, the resolver must call this method once + * and only once for the duration of the resolve operation and that call + * must happen before calling any other method on this resolve context. If + * the specified callback is executed then the resolver must cancel the + * currently running resolve operation and throw a + * {@link ResolutionException} with a cause of type + * {@link CancellationException}. + * <p> + * The callback allows a resolve context to cancel a long running resolve + * operation that appears to be running endlessly or at risk of running out + * of resources. The resolve context may then decide to give up on resolve + * operation or attempt to try another resolve operation with a smaller set + * of resources which may allow the resolve operation to complete normally. + * + * @param callback the callback to execute in order to cancel the resolve + * operation + * @throws IllegalStateException if the resolver attempts to register more + * than one callback for a resolve operation + */ + public void onCancel(Runnable callback) { + // do nothing by default + } } diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java index 367c005c1..7fb3ca12a 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java @@ -22,9 +22,14 @@ package org.osgi.service.resolver; import java.util.List; import java.util.Map; + import org.osgi.annotation.versioning.ProviderType; +import org.osgi.framework.namespace.PackageNamespace; +import org.osgi.resource.Namespace; +import org.osgi.resource.Requirement; import org.osgi.resource.Resource; import org.osgi.resource.Wire; +import org.osgi.resource.Wiring; /** * A resolver service resolves the specified resources in the context supplied @@ -70,4 +75,60 @@ public interface Resolver { * @throws ResolutionException If the resolution cannot be satisfied. */ Map<Resource, List<Wire>> resolve(ResolveContext context) throws ResolutionException; + + /** + * Resolves a given dynamic requirement dynamically for the given host + * wiring using the given resolve context and return any new resources and + * wires to the caller. + * <p> + * The requirement must be a {@link Wiring#getResourceRequirements(String) + * requirement} of the wiring and must use the + * {@link PackageNamespace#PACKAGE_NAMESPACE package} namespace. + * <p> + * The resolve context is not asked for + * {@link ResolveContext#getMandatoryResources() mandatory} resources or for + * {@link ResolveContext#getMandatoryResources() optional} resources. The + * resolve context is asked to + * {@link ResolveContext#findProviders(Requirement) find providers} for the + * given requirement. The matching {@link PackageNamespace#PACKAGE_NAMESPACE + * package} capabilities returned by the resolve context must not have a + * {@link PackageNamespace#PACKAGE_NAMESPACE osgi.wiring.package} attribute + * equal to a {@link PackageNamespace#PACKAGE_NAMESPACE package} capability + * already {@link Wiring#getRequiredResourceWires(String) wired to} by the + * wiring or equal a {@link PackageNamespace#PACKAGE_NAMESPACE package} + * capability {@link Wiring#getResourceCapabilities(String) provided} by the + * wiring. The resolve context may be requested to + * {@link ResolveContext#findProviders(Requirement) find providers} for + * other requirements in order to resolve the resources that provide the + * matching capabilities to the given requirement. + * <p> + * If the requirement {@link Namespace#REQUIREMENT_CARDINALITY_DIRECTIVE + * cardinality} is not {@link Namespace#CARDINALITY_MULTIPLE multiple} then + * no new wire must be created if the + * {@link Wiring#getRequiredResourceWires(String) wires} of the wiring + * already contain a wire that uses the {@link Wire#getRequirement() + * requirement} + * <p> + * This operation may resolve additional resources in order to resolve the + * dynamic requirement. The returned map will contain entries for each + * resource that got resolved in addition to the specified wiring + * {@link Wiring#getResource() resource}. The wire list for the wiring + * resource will only contain one wire which is for the dynamic requirement. + * + * @param context The resolve context for the resolve operation. Must not be + * {@code null}. + * @param hostWiring The wiring with the dynamic + * {@link Wiring#getResourceRequirements(String) requirement}. + * Must not be {@code null}. + * @param dynamicRequirement The dynamic requirement. Must not be + * {@code null}. + * @return The new resources and wires required to satisfy the specified + * dynamic requirement. The returned map is the property of the + * caller and can be modified by the caller. If no new wires were + * created then a ResolutionException is thrown. + * @throws ResolutionException if the dynamic requirement cannot be resolved + */ + public Map<Resource,List<Wire>> resolveDynamic(ResolveContext context, + Wiring hostWiring, Requirement dynamicRequirement) + throws ResolutionException; } diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/package-info.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/package-info.java index 4fab41bbd..544d95611 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/package-info.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/package-info.java @@ -15,27 +15,25 @@ */ /** - * Resolver Service Package Version 1.0. - * + * Resolver Service Package Version 1.1. * <p> * Bundles wishing to use this package must list the package in the * Import-Package header of the bundle's manifest. This package has two types of * users: the consumers that use the API in this package and the providers that * implement the API in this package. - * * <p> * Example import for consumers using the API in this package: * <p> - * {@code Import-Package: org.osgi.service.resolver; version="[1.0,2.0)"} + * {@code Import-Package: org.osgi.service.resolver; version="[1.1,2.0)"} * <p> * Example import for providers implementing the API in this package: * <p> - * {@code Import-Package: org.osgi.service.resolver; version="[1.0,1.1)"} + * {@code Import-Package: org.osgi.service.resolver; version="[1.1,1.2)"} * * @author $Id$ */ -@Version("1.0.1") +@Version("1.1") package org.osgi.service.resolver; import org.osgi.annotation.versioning.Version; diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/packageinfo b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/packageinfo index b3d1f97f7..3987f9c4e 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/packageinfo +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/packageinfo @@ -1 +1 @@ -version 1.0.1 +version 1.1 |