package biz.aQute.resolve;
import static org.osgi.framework.namespace.BundleNamespace.*;
import static org.osgi.framework.namespace.PackageNamespace.*;
import java.io.*;
import java.text.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.*;
import org.osgi.framework.*;
import org.osgi.framework.namespace.*;
import org.osgi.namespace.contract.*;
import org.osgi.resource.*;
import org.osgi.service.log.*;
import org.osgi.service.repository.*;
import org.osgi.service.resolver.*;
import aQute.bnd.build.model.*;
import aQute.bnd.deployer.repository.*;
import aQute.bnd.header.*;
import aQute.bnd.osgi.resource.*;
import aQute.bnd.service.resolve.hook.*;
import aQute.lib.utf8properties.*;
import aQute.libg.filters.*;
import aQute.libg.filters.Filter;
import biz.aQute.resolve.internal.*;
/**
* This is the Resolve Context as outlined in the Resolver specfication. It
* manages the access to the repository and orders the capabilities. It also
* provides the capabilities of the environment.
*/
public class GenericResolveContext extends ResolveContext {
protected static final String CONTRACT_OSGI_FRAMEWORK = "OSGiFramework";
protected static final String IDENTITY_INITIAL_RESOURCE = "<<INITIAL>>";
protected static final String IDENTITY_SYSTEM_RESOURCE = "<<SYSTEM>>";
protected final LogService log;
private final List<Capability> systemCapabilities;
private final List<Capability> capabilities = new ArrayList<Capability>();
private final List<Requirement> systemRequirements;
private final List<Requirement> requirements = new ArrayList<Requirement>();
protected CapabilityIndex systemCapabilityIndex;
protected final List<Repository> repositories = new ArrayList<Repository>();
protected final List<Requirement> failed = new ArrayList<Requirement>();
protected final Map<CacheKey,List<Capability>> providerCache = new HashMap<CacheKey,List<Capability>>();
protected final Set<Resource> optionalRoots = new HashSet<Resource>();
protected final ConcurrentMap<Resource,Integer> resourcePriorities = new ConcurrentHashMap<Resource,Integer>();
protected final Comparator<Capability> capabilityComparator = new CapabilityComparator();
protected Map<String,Set<String>> effectiveSet;
protected final List<ResolverHook> resolverHooks = new ArrayList<ResolverHook>();
protected final List<ResolutionCallback> callbacks = new LinkedList<ResolutionCallback>();
protected boolean initialised = false;
protected Resource systemResource;
protected Resource inputResource;
protected Set<Resource> blacklistedResources = new HashSet<Resource>();
public GenericResolveContext(LogService log) {
this(Collections.<Capability> emptyList(), Collections.<Requirement> emptyList(), log);
}
/**
* @param systemCapabilities
* @param systemRequirements
* @param blacklist
* @param log
*/
public GenericResolveContext(List<Capability> systemCapabilities, List<Requirement> systemRequirements,
LogService log) {
this.systemCapabilities = systemCapabilities;
this.systemRequirements = systemRequirements;
this.log = log;
systemCapabilityIndex = new CapabilityIndex();
}
protected synchronized void init() {
if (initialised)
return;
try {
failed.clear();
getSystemResource();
getInputResource();
initialised = true;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public void addInputRequirement(Requirement requirement) {
requirements.add(requirement);
}
public void addInputCapability(Capability capability) {
capabilities.add(capability);
}
@Override
public List<Capability> findProviders(Requirement requirement) {
List<Capability> result = findProviders0(requirement);
if (result == null || result.isEmpty()) {
failed.add(requirement);
}
return result;
}
private List<Capability> findProviders0(Requirement requirement) {
init();
List<Capability> result;
CacheKey cacheKey = getCacheKey(requirement);
List<Capability> cached = providerCache.get(cacheKey);
if (cached != null) {
result = new ArrayList<Capability>(cached);
} else {
// First stage: framework and self-capabilities. This should never
// be reordered by preferences or resolver
// hooks
LinkedHashSet<Capability> firstStageResult = new LinkedHashSet<Capability>();
// The selected OSGi framework always has the first chance to
// provide the capabilities
systemCapabilityIndex.appendMatchingCapabilities(requirement, firstStageResult);
// Next find out if the requirement is satisfied by a capability on
// the same resource
Resource resource = requirement.getResource();
if (resource != null) {
List<Capability> selfCaps = resource.getCapabilities(requirement.getNamespace());
if (selfCaps != null) {
for (Capability selfCap : selfCaps) {
if (matches(requirement, selfCap))
firstStageResult.add(selfCap);
}
}
}
// If the requirement is optional and doesn't come from an optional
// root resource,
// then we are done already, no need to look for providers from the
// repos.
boolean optional = Namespace.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(
Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE));
if (optional && !optionalRoots.contains(requirement.getResource())) {
result = new ArrayList<Capability>(firstStageResult);
Collections.sort(result, capabilityComparator);
} else {
// Second stage results: repository contents; may be reordered.
ArrayList<Capability> secondStageResult = new ArrayList<Capability>();
// Iterate over the repos
int order = 0;
ArrayList<Capability> repoCapabilities = new ArrayList<Capability>();
for (Repository repo : repositories) {
repoCapabilities.clear();
Map<Requirement,Collection<Capability>> providers = findProviders(repo, requirement);
Collection<Capability> capabilities = providers.get(requirement);
if (capabilities != null && !capabilities.isEmpty()) {
repoCapabilities.ensureCapacity(capabilities.size());
for (Capability capability : capabilities) {
if (isPermitted(capability.getResource())) {
repoCapabilities.add(capability);
setResourcePriority(order, capability.getResource());
}
}
secondStageResult.addAll(repoCapabilities);
}
order++;
}
Collections.sort(secondStageResult, capabilityComparator);
// Convert second-stage results to a list and post-process
ArrayList<Capability> secondStageList = new ArrayList<Capability>(secondStageResult);
// Post-processing second stage results
postProcessProviders(requirement, firstStageResult, secondStageList);
// Concatenate both stages, eliminating duplicates between the
// two
firstStageResult.addAll(secondStageList);
result = new ArrayList<Capability>(firstStageResult);
}
providerCache.put(cacheKey, result);
}
return result;
}
/**
* Return any capabilities from the given repo. This method will filter the
* blacklist.
*
* @param repo
* The repo to fetch requirements from
* @param requirement
* the requirement
* @return a list of caps for the asked requirement minus and capabilities
* that are skipped.
*/
protected Map<Requirement,Collection<Capability>> findProviders(Repository repo, Requirement requirement) {
Map<Requirement,Collection<Capability>> map = repo.findProviders(Collections.singleton(requirement));
if (map.isEmpty())
return map;
Collection<Capability> caps = map.get(requirement);
for (Iterator<Capability> c = caps.iterator(); c.hasNext();) {
Capability capability = c.next();
if (blacklistedResources.contains(capability.getResource()))
c.remove();
}
return map;
}
private void setResourcePriority(int priority, Resource resource) {
resourcePriorities.putIfAbsent(resource, priority);
}
public static Requirement createBundleRequirement(String bsn, String versionStr) {
return CapReqBuilder.createBundleRequirement(bsn, versionStr).buildSyntheticRequirement();
}
private boolean matches(Requirement requirement, Capability selfCap) {
boolean match = false;
try {
String filterStr = requirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
org.osgi.framework.Filter filter = filterStr != null ? org.osgi.framework.FrameworkUtil
.createFilter(filterStr) : null;
if (filter == null)
match = true;
else
match = filter.match(new MapToDictionaryAdapter(selfCap.getAttributes()));
}
catch (InvalidSyntaxException e) {
log.log(LogService.LOG_ERROR, "Invalid filter directive on requirement: " + requirement, e);
}
return match;
}
@Override
public int insertHostedCapability(List<Capability> caps, HostedCapability hc) {
Integer prioObj = resourcePriorities.get(hc.getResource());
int priority = prioObj != null ? prioObj.intValue() : Integer.MAX_VALUE;
for (int i = 0; i < caps.size(); i++) {
Capability c = caps.get(i);
Integer otherPrioObj = resourcePriorities.get(c.getResource());
int otherPriority = otherPrioObj != null ? otherPrioObj.intValue() : 0;
if (otherPriority > priority) {
caps.add(i, hc);
return i;
}
}
caps.add(hc);
return caps.size() - 1;
}
@Override
public boolean isEffective(Requirement requirement) {
init();
String effective = requirement.getDirectives().get(Namespace.REQUIREMENT_EFFECTIVE_DIRECTIVE);
if (effective == null || Namespace.EFFECTIVE_RESOLVE.equals(effective))
return true;
if (effectiveSet != null && effectiveSet.containsKey(effective)
&& !effectiveSet.get(effective).contains(requirement.getNamespace()))
return true;
return false;
}
@Override
public Map<Resource,Wiring> getWirings() {
return Collections.emptyMap();
}
public void setOptionalRoots(Collection<Resource> roots) {
this.optionalRoots.clear();
this.optionalRoots.addAll(roots);
}
public void addRepository(Repository repo) {
repositories.add(repo);
}
public List<Repository> getRepositories() {
return repositories;
}
public List<Requirement> getFailed() {
return failed;
}
private boolean isPermitted(Resource resource) {
// OSGi frameworks cannot be selected as ordinary resources
Capability fwkCap = findFrameworkContractCapability(resource);
if (fwkCap != null) {
return false;
}
// Remove osgi.core and any ee JAR
List<Capability> idCaps = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
if (idCaps == null || idCaps.isEmpty()) {
log.log(LogService.LOG_ERROR, "Resource is missing an identity capability (osgi.identity).");
return false;
}
if (idCaps.size() > 1) {
log.log(LogService.LOG_ERROR, "Resource has more than one identity capability (osgi.identity).");
return false;
}
String identity = (String) idCaps.get(0).getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE);
if (identity == null) {
log.log(LogService.LOG_ERROR, "Resource is missing an identity capability (osgi.identity).");
return false;
}
if ("osgi.core".equals(identity))
return false;
if (identity.startsWith("ee."))
return false;
return true;
}
protected static Capability findFrameworkContractCapability(Resource resource) {
List<Capability> contractCaps = resource.getCapabilities(ContractNamespace.CONTRACT_NAMESPACE);
if (contractCaps != null)
for (Capability cap : contractCaps) {
if (CONTRACT_OSGI_FRAMEWORK.equals(cap.getAttributes().get(ContractNamespace.CONTRACT_NAMESPACE)))
return cap;
}
return null;
}
public static boolean isInputRequirementResource(Resource resource) {
Capability id = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE).get(0);
return IDENTITY_INITIAL_RESOURCE.equals(id.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
}
private static CacheKey getCacheKey(Requirement requirement) {
return new CacheKey(requirement.getNamespace(), requirement.getDirectives(), requirement.getAttributes());
}
private static class CacheKey {
final String namespace;
final Map<String,String> directives;
final Map<String,Object> attributes;
final int hashcode;
CacheKey(String namespace, Map<String,String> directives, Map<String,Object> attributes) {
this.namespace = namespace;
this.directives = directives;
this.attributes = attributes;
this.hashcode = calculateHashCode(namespace, directives, attributes);
}
private static int calculateHashCode(String namespace, Map<String,String> directives,
Map<String,Object> attributes) {
final int prime = 31;
int result = 1;
result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((directives == null) ? 0 : directives.hashCode());
result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
return result;
}
@Override
public int hashCode() {
return hashcode;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheKey other = (CacheKey) obj;
if (attributes == null) {
if (other.attributes != null)
return false;
} else if (!attributes.equals(other.attributes))
return false;
if (directives == null) {
if (other.directives != null)
return false;
} else if (!directives.equals(other.directives))
return false;
if (namespace == null) {
if (other.namespace != null)
return false;
} else if (!namespace.equals(other.namespace))
return false;
return true;
}
}
static Version getVersion(Capability cap, String attr) {
Object versionatt = cap.getAttributes().get(attr);
if (versionatt instanceof Version)
return (Version) versionatt;
else if (versionatt instanceof String)
return Version.parseVersion((String) versionatt);
else
return Version.emptyVersion;
}
private class CapabilityComparator implements Comparator<Capability> {
public CapabilityComparator() {}
public int compare(Capability o1, Capability o2) {
Resource res1 = o1.getResource();
Resource res2 = o2.getResource();
// 1. Framework bundle
if (isSystemResource(res1))
return -1;
if (isSystemResource(res2))
return +1;
// 2. Wired
Map<Resource,Wiring> wirings = getWirings();
Wiring w1 = wirings.get(res1);
Wiring w2 = wirings.get(res2);
if (w1 != null && w2 == null)
return -1;
if (w1 == null && w2 != null)
return +1;
// 3. Input requirements
if (isInputResource(res1)) {
if (!isInputResource(res2))
return -1;
}
if (isInputResource(res2)) {
if (!isInputResource(res1))
return +1;
}
// 4. Higher package version
String ns1 = o1.getNamespace();
String ns2 = o2.getNamespace();
if (PACKAGE_NAMESPACE.equals(ns1) && PACKAGE_NAMESPACE.equals(ns2)) {
Version v1 = getVersion(o1, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
Version v2 = getVersion(o2, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
if (!v1.equals(v2))
return v2.compareTo(v1);
}
// 5. Higher resource version
if (BUNDLE_NAMESPACE.equals(ns1) && BUNDLE_NAMESPACE.equals(ns2)) {
Version v1 = getVersion(o1, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
Version v2 = getVersion(o2, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
if (!v1.equals(v2))
return v2.compareTo(v1);
} else if (IdentityNamespace.IDENTITY_NAMESPACE.equals(ns1)
&& IdentityNamespace.IDENTITY_NAMESPACE.equals(ns2)) {
Version v1 = getVersion(o1, IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
Version v2 = getVersion(o2, IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
if (!v1.equals(v2))
return v2.compareTo(v1);
}
// 6. Same package version, higher bundle version
if (PACKAGE_NAMESPACE.equals(ns1) && PACKAGE_NAMESPACE.equals(ns2)) {
String bsn1 = (String) o1.getAttributes().get(aQute.bnd.osgi.Constants.BUNDLE_SYMBOLIC_NAME_ATTRIBUTE);
String bsn2 = (String) o2.getAttributes().get(aQute.bnd.osgi.Constants.BUNDLE_SYMBOLIC_NAME_ATTRIBUTE);
if (bsn1 != null && bsn1.equals(bsn2)) {
Version v1 = getVersion(o1, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
Version v2 = getVersion(o2, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
if (!v1.equals(v2))
return v2.compareTo(v1);
}
}
// 7. The resource with the fewest requirements
int diff = res1.getRequirements(null).size() - res2.getRequirements(null).size();
if (diff != 0)
return diff;
// 8. The resource with most capabilities
return res2.getCapabilities(null).size() - res1.getCapabilities(null).size();
}
}
public Resource getInputResource() {
if (inputResource != null) {
return inputResource;
}
ResourceBuilder resBuilder = new ResourceBuilder();
CapReqBuilder identity = new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE).addAttribute(
IdentityNamespace.IDENTITY_NAMESPACE, IDENTITY_INITIAL_RESOURCE);
resBuilder.addCapability(identity);
for (Requirement req : requirements) {
resBuilder.addRequirement(req);
}
for (Capability cap : capabilities) {
resBuilder.addCapability(cap);
}
inputResource = resBuilder.build();
return inputResource;
}
public Resource getSystemResource() {
if (systemResource != null) {
return systemResource;
}
ResourceBuilder resBuilder = new ResourceBuilder();
CapReqBuilder identity = new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE).addAttribute(
IdentityNamespace.IDENTITY_NAMESPACE, IDENTITY_SYSTEM_RESOURCE);
resBuilder.addCapability(identity);
for (Requirement req : systemRequirements) {
resBuilder.addRequirement(req);
}
for (Capability cap : systemCapabilities) {
resBuilder.addCapability(cap);
}
systemResource = resBuilder.build();
for (Capability capability : systemResource.getCapabilities(null)) {
systemCapabilityIndex.addCapability(capability);
}
return systemResource;
}
@Override
public Collection<Resource> getMandatoryResources() {
init();
List<Resource> resources = new ArrayList<Resource>();
Resource resource = getSystemResource();
if (resource != null) {
resources.add(resource);
}
resource = getInputResource();
if (resource != null) {
resources.add(resource);
}
return resources;
}
public void addEffectiveDirective(String effectiveDirective) {
this.effectiveSet.put(effectiveDirective, new HashSet<String>());
}
public void addEffectiveDirective(String effectiveDirective, Set<String> excludedNamespaces) {
this.effectiveSet.put(effectiveDirective, excludedNamespaces != null ? excludedNamespaces
: new HashSet<String>());
}
protected void postProcessProviders(Requirement requirement, Set<Capability> wired, List<Capability> candidates) {
if (candidates.size() == 0)
return;
// Call resolver hooks
for (ResolverHook resolverHook : resolverHooks) {
resolverHook.filterMatches(requirement, candidates);
}
// If preferences were applied, then don't need to call the callbacks
for (ResolutionCallback callback : callbacks) {
callback.processCandidates(requirement, wired, candidates);
}
}
public void addResolverHook(ResolverHook resolverHook) {
resolverHooks.add(resolverHook);
}
public void addCallbacks(Collection<ResolutionCallback> callbacks) {
this.callbacks.addAll(callbacks);
}
public static Requirement createIdentityRequirement(String identity, String versionRange) {
// Construct a filter & requirement to find matches
Filter filter = new SimpleFilter(IdentityNamespace.IDENTITY_NAMESPACE, identity);
if (versionRange != null)
filter = new AndFilter().addChild(filter).addChild(
new LiteralFilter(Filters.fromVersionRange(versionRange)));
Requirement frameworkReq = new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE).addDirective(
Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString()).buildSyntheticRequirement();
return frameworkReq;
}
public boolean isInputResource(Resource resource) {
return GenericResolveContext.resourceIdentityEquals(resource, inputResource);
}
public boolean isSystemResource(Resource resource) {
return GenericResolveContext.resourceIdentityEquals(resource, systemResource);
}
public Resource getFrameworkResource(List<Repository> repos, String bsn, String version) {
Requirement frameworkRequirement = GenericResolveContext.createIdentityRequirement(bsn, version);
if (frameworkRequirement == null) {
return null;
}
Version current = null;
Resource result = null;
for (Repository repo : repos) {
Map<Requirement,Collection<Capability>> providers = findProviders(repo,frameworkRequirement);
Collection<Capability> frameworkCaps = providers.get(frameworkRequirement);
if (frameworkCaps != null) {
for (Capability frameworkCap : frameworkCaps) {
if (findFrameworkContractCapability(frameworkCap.getResource()) != null) {
Version foundVersion = toVersion(frameworkCap.getAttributes().get(
IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE));
if (foundVersion != null) {
if (current == null || (foundVersion.compareTo(current) > 0)) {
result = frameworkCap.getResource();
ResourceBuilder resBuilder = new ResourceBuilder();
for (Capability cap : result.getCapabilities(null)) {
resBuilder.addCapability(cap);
}
for (Requirement req : result.getRequirements(null)) {
resBuilder.addRequirement(req);
}
// Add system.bundle alias
Version frameworkVersion = Utils.findIdentityVersion(result);
resBuilder.addCapability(new CapReqBuilder(BundleNamespace.BUNDLE_NAMESPACE)
.addAttribute(BundleNamespace.BUNDLE_NAMESPACE,
Constants.SYSTEM_BUNDLE_SYMBOLICNAME)
.addAttribute(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE,
frameworkVersion).setResource(result).buildCapability());
resBuilder.addCapability(new CapReqBuilder(HostNamespace.HOST_NAMESPACE)
.addAttribute(HostNamespace.HOST_NAMESPACE,
Constants.SYSTEM_BUNDLE_SYMBOLICNAME)
.addAttribute(HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE,
frameworkVersion).setResource(result).buildCapability());
result = resBuilder.build();
current = foundVersion;
}
}
}
}
}
}
return result;
}
protected static Version toVersion(Object object) throws IllegalArgumentException {
if (object == null)
return null;
if (object instanceof Version)
return (Version) object;
if (object instanceof String)
return Version.parseVersion((String) object);
throw new IllegalArgumentException(MessageFormat.format("Cannot convert type {0} to Version.", object
.getClass().getName()));
}
public static List<Capability> getEECapabilities(EE ee) {
List<Capability> caps = new ArrayList<Capability>();
addEECapability(ee, caps);
for (EE compatibleEE : ee.getCompatible()) {
addEECapability(compatibleEE, caps);
}
getJRECapabilities(ee);
return caps;
}
public static List<Capability> getJRECapabilities(EE ee) {
List<Capability> caps = new ArrayList<Capability>();
loadJREPackages(ee, caps);
return caps;
}
private static void addEECapability(EE ee, List<Capability> capabilities) {
CapReqBuilder builder;
// Correct version according to R5 specification section 3.4.1
// BREE J2SE-1.4 ==> osgi.ee=JavaSE, version:Version=1.4
// See bug 329, https://github.com/bndtools/bnd/issues/329
builder = new CapReqBuilder(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE);
builder.addAttribute(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, ee.getCapabilityName());
builder.addAttribute(ExecutionEnvironmentNamespace.CAPABILITY_VERSION_ATTRIBUTE, ee.getCapabilityVersion());
capabilities.add(builder.buildSyntheticCapability());
// Compatibility with old version...
builder = new CapReqBuilder(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE);
builder.addAttribute(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE, ee.getEEName());
capabilities.add(builder.buildSyntheticCapability());
}
protected static void loadJREPackages(EE ee, List<Capability> capabilities) {
InputStream stream = FrameworkResourceRepository.class.getResourceAsStream(ee.name() + ".properties");
if (stream != null) {
try {
Properties properties = new UTF8Properties();
properties.load(stream);
Parameters params = new Parameters(properties.getProperty("org.osgi.framework.system.packages", ""));
for (String packageName : params.keySet()) {
CapReqBuilder builder = new CapReqBuilder(PackageNamespace.PACKAGE_NAMESPACE);
builder.addAttribute(PackageNamespace.PACKAGE_NAMESPACE, packageName);
builder.addAttribute(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, new Version(0, 0, 0));
Capability cap = builder.buildSyntheticCapability();
capabilities.add(cap);
}
}
catch (IOException e) {
throw new IllegalStateException("Error loading JRE package properties", e);
}
}
}
public static Repository createRepository(final List<Resource> resources) {
return new Repository() {
@Override
public Map<Requirement,Collection<Capability>> findProviders(Collection< ? extends Requirement> requirements) {
Map<Requirement,Collection<Capability>> reqMap = null;
for (Requirement requirement : requirements) {
Resource resource = requirement.getResource();
List<Capability> result = new ArrayList<Capability>();
for (Resource found : resources) {
String filterStr = requirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
try {
org.osgi.framework.Filter filter = filterStr != null ? org.osgi.framework.FrameworkUtil
.createFilter(filterStr) : null;
List<Capability> caps = found.getCapabilities(requirement.getNamespace());
for (Capability c : caps) {
if (filter != null && filter.matches(c.getAttributes())) {
result.add(c);
}
}
}
catch (InvalidSyntaxException e) {}
}
if (result.size() > 0) {
if (reqMap == null) {
reqMap = new LinkedHashMap<Requirement,Collection<Capability>>();
}
reqMap.put(requirement, result);
}
}
if (reqMap != null) {
return reqMap;
}
return Collections.emptyMap();
}
};
}
public static Capability createPackageCapability(String packageName, String versionString) {
CapReqBuilder builder = new CapReqBuilder(PackageNamespace.PACKAGE_NAMESPACE);
builder.addAttribute(PackageNamespace.PACKAGE_NAMESPACE, packageName);
Version version = versionString != null ? new Version(versionString) : Version.emptyVersion;
builder.addAttribute(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, version);
return builder.buildSyntheticCapability();
}
public static boolean resourceIdentityEquals(Resource r1, Resource r2) {
String id1 = getResourceIdentity(r1);
String id2 = getResourceIdentity(r2);
if (id1 != null && id1.equals(id2)) {
Version v1 = getResourceVersion(r1);
Version v2 = getResourceVersion(r2);
if (v1 == null && v2 == null || v1 != null && v1.equals(v2)) {
return true;
}
}
return false;
}
public static Capability getIdentityCapability(Resource resource) {
if (resource == null) {
return null;
}
List<Capability> identityCaps = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
if (identityCaps == null || identityCaps.isEmpty()) {
return null;
}
return identityCaps.iterator().next();
}
public static String getResourceIdentity(Resource resource) {
Capability cap = getIdentityCapability(resource);
if (cap == null) {
return null;
}
return (String) cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE);
}
public static Version getResourceVersion(Resource resource) {
Capability cap = getIdentityCapability(resource);
if (cap == null) {
return null;
}
return getVersion(cap, IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
}
/**
* If the blacklist is set, we have a list of requirements of resources that
* should not be included (blacklist). We try to find those resources and
* add them to the blacklistedResources
*/
protected void setBlackList(Collection<Requirement> reject) {
for (Repository repo : repositories) {
Map<Requirement,Collection<Capability>> caps = repo.findProviders(reject);
for (Entry<Requirement,Collection<Capability>> entry : caps.entrySet()) {
for (Capability cap : entry.getValue()) {
blacklistedResources.add(cap.getResource());
}
}
}
}
}