package biz.aQute.resolve;
import static org.osgi.framework.namespace.BundleNamespace.BUNDLE_NAMESPACE;
import static org.osgi.framework.namespace.PackageNamespace.PACKAGE_NAMESPACE;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
import org.osgi.framework.namespace.BundleNamespace;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.framework.namespace.PackageNamespace;
import org.osgi.namespace.contract.ContractNamespace;
import org.osgi.resource.Capability;
import org.osgi.resource.Namespace;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import org.osgi.resource.Wiring;
import org.osgi.service.log.LogService;
import org.osgi.service.repository.ContentNamespace;
import org.osgi.service.repository.Repository;
import org.osgi.service.resolver.HostedCapability;
import org.osgi.service.resolver.ResolveContext;
import aQute.bnd.deployer.repository.CapabilityIndex;
import aQute.bnd.deployer.repository.MapToDictionaryAdapter;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Domain;
import aQute.bnd.osgi.Processor;
import aQute.bnd.osgi.repository.ResourcesRepository;
import aQute.bnd.osgi.resource.CapReqBuilder;
import aQute.bnd.osgi.resource.Filters;
import aQute.bnd.osgi.resource.ResourceBuilder;
import aQute.bnd.osgi.resource.ResourceUtils;
import aQute.bnd.service.resolve.hook.ResolverHook;
import aQute.bnd.version.VersionRange;
import aQute.lib.io.IO;
import aQute.libg.filters.AndFilter;
import aQute.libg.filters.Filter;
import aQute.libg.filters.LiteralFilter;
import aQute.libg.filters.SimpleFilter;
/**
* This is the Resolve Context as outlined in the Resolver specification. It
* manages the access to the repository and orders the capabilities. It also
* provides the capabilities of the environment.
*/
public abstract class AbstractResolveContext extends ResolveContext {
/**
* These are the namespaces that we ignore when we copy capabilities from
* -runpath resources.
*/
static Set<String> IGNORED_NAMESPACES_FOR_SYSTEM_RESOURCES = new HashSet<String>();
static {
// TODO BJ?
// IGNORED_NAMESPACES_FOR_SYSTEM_RESOURCES.add(BundleNamespace.BUNDLE_NAMESPACE);
IGNORED_NAMESPACES_FOR_SYSTEM_RESOURCES.add(IdentityNamespace.IDENTITY_NAMESPACE);
IGNORED_NAMESPACES_FOR_SYSTEM_RESOURCES.add(ContentNamespace.CONTENT_NAMESPACE);
// IGNORED_NAMESPACES_FOR_SYSTEM_RESOURCES.add(HostNamespace.HOST_NAMESPACE);
}
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 CapabilityIndex systemCapabilityIndex = new CapabilityIndex();
private final List<Repository> repositories = new ArrayList<Repository>();
private final List<Requirement> failed = new ArrayList<Requirement>();
private final Map<CacheKey,List<Capability>> providerCache = new HashMap<CacheKey,List<Capability>>();
private final Set<Resource> optionalRoots = new HashSet<Resource>();
private final ConcurrentMap<Resource,Integer> resourcePriorities = new ConcurrentHashMap<Resource,Integer>();
private final Comparator<Capability> capabilityComparator;
private Map<String,Set<String>> effectiveSet = new HashMap<String,Set<String>>();
private final List<ResolverHook> resolverHooks = new ArrayList<ResolverHook>();
private final List<ResolutionCallback> callbacks = new LinkedList<ResolutionCallback>();
private boolean initialised = false;
private Resource systemResource;
private Resource inputResource;
private Set<Resource> blacklistedResources = new HashSet<Resource>();
private int level = 0;
private Resource framework;
public AbstractResolveContext(LogService log) {
this.log = log;
this.capabilityComparator = new CapabilityComparator(log);
}
protected synchronized void init() {
if (initialised)
return;
try {
failed.clear();
systemCapabilityIndex.addResource(systemResource);
if (level > 0) {
DebugReporter dr = new DebugReporter(System.out, this, level);
dr.report();
}
initialised = true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public List<Capability> findProviders(Requirement requirement) {
init();
List<Capability> result = findProviders0(requirement);
if (result.isEmpty()) {
failed.add(requirement);
}
return result;
}
@Override
public Collection<Resource> getMandatoryResources() {
init();
return Collections.singleton(getInputResource());
}
@Override
public int insertHostedCapability(List<Capability> caps, HostedCapability hc) {
init();
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;
}
}
int newIndex = caps.size();
// the List passed by Felix does not support the
// single-arg version of add()... it throws
// UnsupportedOperationException
caps.add(newIndex, hc);
return newIndex;
}
@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() {
init();
return Collections.emptyMap();
}
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
processMandatoryResource(requirement, firstStageResult, requirement.getResource());
// Next find out if the requirement is satisfied by a capability on
// a Mandatory resource
for (Resource res : getMandatoryResources()) {
processMandatoryResource(requirement, firstStageResult, res);
}
// 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 {
ArrayList<Capability> secondStageList = findProvidersFromRepositories(requirement, firstStageResult);
// Concatenate both stages, eliminating duplicates between the
// two
firstStageResult.addAll(secondStageList);
result = new ArrayList<Capability>(firstStageResult);
}
providerCache.put(cacheKey, result);
}
log.log(LogService.LOG_DEBUG, "for " + requirement + " found " + result);
return result;
}
protected void processMandatoryResource(Requirement requirement, LinkedHashSet<Capability> firstStageResult,
Resource resource) {
if (resource != null) {
List<Capability> selfCaps = resource.getCapabilities(requirement.getNamespace());
if (selfCaps != null) {
for (Capability selfCap : selfCaps) {
if (matches(requirement, selfCap))
firstStageResult.add(selfCap);
}
}
}
}
protected ArrayList<Capability> findProvidersFromRepositories(Requirement requirement,
LinkedHashSet<Capability> existingWiredCapabilities) {
// 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();
Collection<Capability> capabilities = findProviders(repo, requirement);
if (capabilities != null && !capabilities.isEmpty()) {
repoCapabilities.ensureCapacity(capabilities.size());
for (Capability capability : capabilities) {
if (isPermitted(capability.getResource()) && isCorrectEffectiveness(requirement, capability)) {
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, existingWiredCapabilities, secondStageList);
return secondStageList;
}
/**
* 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 Collection<Capability> findProviders(Repository repo, Requirement requirement) {
Map<Requirement,Collection<Capability>> map = repo.findProviders(Collections.singleton(requirement));
if (map.isEmpty())
return Collections.emptySet();
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 caps;
}
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;
if (isCorrectEffectiveness(requirement, selfCap)) {
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;
}
private boolean isCorrectEffectiveness(Requirement requirement, Capability cap) {
boolean result = false;
String reqEffective = requirement.getDirectives().get(Namespace.REQUIREMENT_EFFECTIVE_DIRECTIVE);
if (reqEffective == null || Namespace.EFFECTIVE_RESOLVE.equals(reqEffective)) {
// Resolve time effective requirements will be used by the runtime
// resolver in the OSGi framework, and will only be matched by
// resolve time capabilities!
String capEffective = cap.getDirectives().get(Namespace.CAPABILITY_EFFECTIVE_DIRECTIVE);
result = capEffective == null || Namespace.EFFECTIVE_RESOLVE.equals(capEffective);
} else {
// If we're not a resolve time requirement then any capability
// effectiveness is ok
result = true;
}
return result;
}
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;
}
private static CacheKey getCacheKey(Requirement requirement) {
return new CacheKey(requirement.getNamespace(), requirement.getDirectives(), requirement.getAttributes(),
requirement.getResource());
}
private static class CacheKey {
final String namespace;
final Map<String,String> directives;
final Map<String,Object> attributes;
final Resource resource;
final int hashcode;
CacheKey(String namespace, Map<String,String> directives, Map<String,Object> attributes, Resource resource) {
this.namespace = namespace;
this.directives = directives;
this.attributes = attributes;
this.resource = resource;
this.hashcode = calculateHashCode(namespace, directives, attributes, resource);
}
private static int calculateHashCode(String namespace, Map<String,String> directives,
Map<String,Object> attributes, Resource resource) {
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());
result = prime * result + ((resource == null) ? 0 : resource.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;
if (resource == null) {
if (other.resource != null)
return false;
} else if (!resourceIdentityEquals(resource, other.resource))
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> {
private final LogService log;
public CapabilityComparator(LogService log) {
this.log = log;
}
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 capability version
String ns1 = o1.getNamespace();
String ns2 = o2.getNamespace();
if (ns1 == ns2 || (ns1 != null && ns1.equals(ns2))) {
try {
// We use package namespace, as that defines the general
// contract for versions
Version v1 = getVersion(o1, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
Version v2 = getVersion(o2, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
if (!v1.equals(v2))
return v2.compareTo(v1);
} catch (Exception e) {
log.log(LogService.LOG_INFO,
"Unable to determine the versions of the capabilities " + o1 + " and " + o2, e);
}
}
// 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() {
return inputResource;
}
public void setInputResource(Resource inputResource) {
this.inputResource = inputResource;
}
public Resource getSystemResource() {
return systemResource;
}
public void setSystemResource(Resource system) {
systemResource = system;
}
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>());
}
public void addEffectiveSet(Map<String,Set<String>> effectiveSet) {
this.effectiveSet.putAll(effectiveSet);
}
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 AbstractResolveContext.resourceIdentityEquals(resource, inputResource);
}
public boolean isSystemResource(Resource resource) {
return AbstractResolveContext.resourceIdentityEquals(resource, systemResource);
}
public Resource getHighestResource(String bsn, String range) {
List<Resource> resources = getResources(getRepositories(), bsn, range);
if (resources.isEmpty())
return null;
Collections.sort(resources, Collections.reverseOrder(ResourceUtils.IDENTITY_VERSION_COMPARATOR));
return resources.get(0);
}
/**
* Get the framework repository from the
*
* @param repos
* @param bsn
*/
public List<Resource> getResources(List<Repository> repos, String bsn, String range) {
Requirement bundle = CapReqBuilder.createBundleRequirement(bsn, range).buildSyntheticRequirement();
return getResources(repos, bundle);
}
public List<Resource> getResources(List<Repository> repos, Requirement req) {
Set<Resource> resources = new HashSet<Resource>();
for (Repository repo : repos) {
Collection<Capability> providers = findProviders(repo, req);
resources.addAll(ResourceUtils.getResources(providers));
}
return new ArrayList<>(resources);
}
/**
* Add a framework resource to the system resource builder
*
* @param system the system resource being build up
* @param framework the framework resource
* @throws Exception
*/
protected void setFramework(ResourceBuilder system, Resource framework) throws Exception {
//
// We copy the framework capabilities
//
system.addCapabilities(framework.getCapabilities(null));
//
// Add system.bundle alias. This is mandated by the spec that a
// framework has a bundle namespace capability.
//
CapReqBuilder cap = new CapReqBuilder(BundleNamespace.BUNDLE_NAMESPACE);
cap.addAttribute(BundleNamespace.BUNDLE_NAMESPACE, Constants.SYSTEM_BUNDLE_SYMBOLICNAME);
//
// TODO BJ is this right? Use the version of the provider framework?
//
String frameworkVersion = ResourceUtils.getIdentityVersion(framework);
cap.addAttribute(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, frameworkVersion);
system.addCapability(cap);
//
// Add a HOST namespace capability for fragments
//
cap = new CapReqBuilder(HostNamespace.HOST_NAMESPACE);
cap.addAttribute(HostNamespace.HOST_NAMESPACE, Constants.SYSTEM_BUNDLE_SYMBOLICNAME);
//
// TODO BJ is this right? Use the version of the provider framework?
//
cap.addAttribute(HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, frameworkVersion);
system.addCapability(cap);
this.framework = framework;
}
/*
* Add all the capabilities from a system resource, i.e. something on
* -runpath
*/
protected void addSystemResource(ResourceBuilder system, Resource resource) throws Exception {
system.copyCapabilities(IGNORED_NAMESPACES_FOR_SYSTEM_RESOURCES, resource);
}
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 Repository createRepository(final List<Resource> resources) {
return new ResourcesRepository(resources);
}
public static Capability createPackageCapability(String packageName, String versionString) throws Exception {
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());
}
}
}
}
public List<ResolutionCallback> getCallbacks() {
return callbacks;
}
public Set<Resource> getBlackList() {
return blacklistedResources;
}
public void setLevel(int n) {
this.level = n;
}
public int getLevel() {
return level;
}
public Resource getFramework() {
return framework;
}
/**
* Load a bnd path from the OSGi repositories. We assume the highest version
* allowed. This mimics Project.getBundles()
*
* @param system
* @param path
* @param what
* @throws IOException
* @throws Exception
*/
public void loadPath(ResourceBuilder system, String path, String what) throws IOException, Exception {
Parameters p = new Parameters(path);
if (p.isEmpty())
return;
for (Entry<String,Attrs> e : p.entrySet()) {
String bsn = Processor.removeDuplicateMarker(e.getKey());
String version = e.getValue().getVersion();
Resource resource;
if ("latest".equals(version) || "snapshot".equals(version))
version = null;
if ("file".equals(version)) {
File f = IO.getFile(bsn);
if (f.isFile()) {
try (InputStream fin = IO.stream(f)) {
Manifest m;
if (f.getName().endsWith(".mf"))
m = new Manifest(fin);
else {
try (JarInputStream jin = new JarInputStream(fin)) {
m = jin.getManifest();
}
}
if (m != null) {
ResourceBuilder rb = new ResourceBuilder();
rb.addManifest(Domain.domain(m));
resource = rb.build();
} else {
continue; // ok to have no manifest, might be a jar
}
}
} else {
log.log(LogService.LOG_ERROR,
"Found fileresource " + bsn + ";" + version + " but file does not exist");
continue;
}
} else if (version == null || VersionRange.isVersionRange(version)) {
resource = getHighestResource(bsn, version);
if (resource == null) {
log.log(LogService.LOG_ERROR, "Could not find resource " + bsn + ";" + version);
}
} else {
log.log(LogService.LOG_ERROR, "Cannot find resource " + bsn + ";" + version);
continue;
}
addSystemResource(system, resource);
}
}
public void setInputRequirements(Requirement... reqs) throws Exception {
ResourceBuilder rb = new ResourceBuilder();
for (Requirement r : reqs) {
rb.addRequirement(r);
}
setInputResource(rb.build());
}
public Map<String,Set<String>> getEffectiveSet() {
return effectiveSet;
}
}