use of org.osgi.framework.wiring.BundleCapability in project felix-dev by apache.
the class StatefulResolver method selectSingletonsUsingHooks.
/*
* Groups singletons based on resolver hook filtering and then selects
* the singleton from each group with the highest version that is in
* the resolver hook whitelist. No selection is made if a group already
* has a resolved singleton in it.
*/
private void selectSingletonsUsingHooks(ResolverHookRecord record) throws BundleException {
// Convert singleton bundle revision map into a map using
// bundle capabilities instead, since this is what the resolver
// hooks require.
Map<BundleCapability, Collection<BundleCapability>> allCollisions = new HashMap<BundleCapability, Collection<BundleCapability>>();
for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet()) {
Collection<BundleCapability> bundleCaps = new ArrayList<BundleCapability>();
for (BundleRevision br : entry.getValue()) {
List<BundleCapability> caps = br.getDeclaredCapabilities(BundleRevision.BUNDLE_NAMESPACE);
if (!caps.isEmpty()) {
bundleCaps.add(caps.get(0));
}
}
for (BundleCapability bc : bundleCaps) {
Collection<BundleCapability> capCopy = new ShrinkableCollection<BundleCapability>(new ArrayList<BundleCapability>(bundleCaps));
capCopy.remove(bc);
allCollisions.put(bc, capCopy);
}
}
// Invoke hooks to allow them to filter singleton collisions.
for (ResolverHook hook : record.getResolverHooks()) {
for (Entry<BundleCapability, Collection<BundleCapability>> entry : allCollisions.entrySet()) {
try {
Felix.m_secureAction.invokeResolverHookSingleton(hook, entry.getKey(), entry.getValue());
} catch (Throwable ex) {
throw new BundleException("Resolver hook exception: " + ex.getMessage(), BundleException.REJECTED_BY_HOOK, ex);
}
}
}
// Create groups according to how the resolver hooks filtered the
// collisions.
List<List<BundleRevision>> groups = new ArrayList<List<BundleRevision>>();
while (!allCollisions.isEmpty()) {
BundleCapability target = allCollisions.entrySet().iterator().next().getKey();
groups.add(groupSingletons(allCollisions, target, new ArrayList<BundleRevision>()));
}
// Now select the singletons available for this resolve operation.
for (List<BundleRevision> group : groups) {
selectSingleton(record, group);
}
}
use of org.osgi.framework.wiring.BundleCapability in project felix-dev by apache.
the class StatefulResolver method indexCapabilities.
private synchronized void indexCapabilities(BundleRevision br) {
List<BundleCapability> caps = (Util.isFragment(br) || (br.getWiring() == null)) ? br.getDeclaredCapabilities(null) : br.getWiring().getCapabilities(null);
if (caps != null) {
for (BundleCapability cap : caps) {
// attached hosts for fragments.
if (cap.getRevision() == br) {
CapabilitySet capSet = m_capSets.get(cap.getNamespace());
if (capSet == null) {
capSet = new CapabilitySet(null, true);
m_capSets.put(cap.getNamespace(), capSet);
}
capSet.addCapability(cap);
}
}
}
}
use of org.osgi.framework.wiring.BundleCapability in project felix-dev by apache.
the class StatefulResolver method groupSingletons.
private List<BundleRevision> groupSingletons(Map<BundleCapability, Collection<BundleCapability>> allCollisions, BundleCapability target, List<BundleRevision> group) {
if (!group.contains(target.getRevision())) {
// Add the target since it is implicitly part of the group.
group.add(target.getRevision());
// Recursively add the revisions of any singleton's in the
// target's collisions.
Collection<BundleCapability> collisions = allCollisions.remove(target);
for (BundleCapability collision : collisions) {
groupSingletons(allCollisions, collision, group);
}
// Need to check the values of other collisions for this target
// and add those to the target's group too, since collisions are
// treated as two-way relationships. Repeat until there are no
// collision groups left that contain the target capability.
boolean repeat;
do {
repeat = false;
for (Entry<BundleCapability, Collection<BundleCapability>> entry : allCollisions.entrySet()) {
if (entry.getValue().contains(target)) {
repeat = true;
groupSingletons(allCollisions, entry.getKey(), group);
break;
}
}
} while (repeat);
}
return group;
}
use of org.osgi.framework.wiring.BundleCapability in project felix-dev by apache.
the class StatefulResolver method findProvidersInternal.
synchronized List<BundleCapability> findProvidersInternal(final ResolverHookRecord record, final Requirement req, final boolean obeyMandatory, final boolean invokeHooksAndSecurity) {
List<BundleCapability> result = new ArrayList<BundleCapability>();
CapabilitySet capSet = m_capSets.get(req.getNamespace());
if (capSet != null) {
// Get the requirement's filter; if this is our own impl we
// have a shortcut to get the already parsed filter, otherwise
// we must parse it from the directive.
SimpleFilter sf;
if (req instanceof BundleRequirementImpl) {
sf = ((BundleRequirementImpl) req).getFilter();
} else {
String filter = req.getDirectives().get(Constants.FILTER_DIRECTIVE);
if (filter == null) {
sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
} else {
sf = SimpleFilter.parse(filter);
}
}
// Find the matching candidates.
Set<Capability> matches = capSet.match(sf, obeyMandatory);
// Filter matching candidates.
for (Capability cap : matches) {
if (!(cap instanceof BundleCapability))
continue;
BundleCapability bcap = (BundleCapability) cap;
// Filter according to security.
if (invokeHooksAndSecurity && filteredBySecurity((BundleRequirement) req, bcap)) {
continue;
}
// dynamic attachment of fragments.
if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE) && (bcap.getRevision().getWiring() != null)) {
continue;
}
result.add(bcap);
}
}
if (invokeHooksAndSecurity) {
// based on a whitelist and/or fine-grained candidate filtering.
if (!result.isEmpty() && !record.getResolverHookRefs().isEmpty()) {
// from disallowed revisions.
if (record.getBundleRevisionWhitelist() != null) {
for (Iterator<BundleCapability> it = result.iterator(); it.hasNext(); ) {
if (!record.getBundleRevisionWhitelist().contains(it.next().getRevision())) {
it.remove();
}
}
}
// Now give the hooks a chance to do fine-grained filtering.
ShrinkableCollection<BundleCapability> shrinkable = new ShrinkableCollection<BundleCapability>(result);
for (ResolverHook hook : record.getResolverHooks()) {
try {
Felix.m_secureAction.invokeResolverHookMatches(hook, (BundleRequirement) req, shrinkable);
} catch (Throwable th) {
m_logger.log(Logger.LOG_WARNING, "Resolver hook exception.", th);
}
}
}
}
Collections.sort(result, new CandidateComparator());
return result;
}
use of org.osgi.framework.wiring.BundleCapability in project felix-dev by apache.
the class StatefulResolver method markResolvedRevisions.
private void markResolvedRevisions(Map<Resource, List<Wire>> wireMap) throws ResolveException {
boolean debugLog = m_felix.getLogger().getLogLevel() >= Logger.LOG_DEBUG;
// First pass.
if (wireMap != null) {
// First pass: Loop through the wire map to find the host wires
// for any fragments and map a host to all of its fragments.
Map<Resource, List<BundleRevision>> hosts = new HashMap<Resource, List<BundleRevision>>();
for (Entry<Resource, List<Wire>> entry : wireMap.entrySet()) {
Resource revision = entry.getKey();
List<Wire> wires = entry.getValue();
if (Util.isFragment(revision)) {
for (Wire w : wires) {
List<BundleRevision> fragments = hosts.get(w.getProvider());
if (fragments == null) {
fragments = new ArrayList<BundleRevision>();
hosts.put(w.getProvider(), fragments);
}
if (w.getRequirer() instanceof BundleRevision)
fragments.add((BundleRevision) w.getRequirer());
}
}
}
// Second pass: Loop through the wire map to do three things:
// 1) convert resolver wires to bundle wires 2) create wiring
// objects for revisions and 3) record dependencies among
// revisions. We don't actually set the wirings here because
// that indicates that a revision is resolved and we don't want
// to mark anything as resolved unless we succussfully create
// all wirings.
Map<BundleRevision, BundleWiringImpl> wirings = new HashMap<BundleRevision, BundleWiringImpl>(wireMap.size());
for (Entry<Resource, List<Wire>> entry : wireMap.entrySet()) {
Resource resource = entry.getKey();
if (!(resource instanceof BundleRevision))
continue;
BundleRevision revision = (BundleRevision) resource;
List<Wire> resolverWires = entry.getValue();
List<BundleWire> bundleWires = new ArrayList<BundleWire>(resolverWires.size());
// the new ones.
if ((revision.getWiring() != null) && Util.isFragment(revision)) {
// Fragments only have host wires, so just add them all.
bundleWires.addAll(revision.getWiring().getRequiredWires(null));
}
// Loop through resolver wires to calculate the package
// space implied by the wires as well as to record the
// dependencies.
Map<String, BundleRevision> importedPkgs = new HashMap<String, BundleRevision>();
Map<String, List<BundleRevision>> requiredPkgs = new HashMap<String, List<BundleRevision>>();
for (Wire rw : resolverWires) {
// TODO can we optimize this?
if (!(rw.getRequirer() instanceof BundleRevision))
continue;
BundleRevision requirer = (BundleRevision) rw.getRequirer();
if (!(rw.getRequirement() instanceof BundleRequirement))
continue;
BundleRequirement requirement = (BundleRequirement) rw.getRequirement();
if (!(rw.getProvider() instanceof BundleRevision))
continue;
BundleRevision provider = (BundleRevision) rw.getProvider();
if (!(rw.getCapability() instanceof BundleCapability))
continue;
BundleCapability capability = (BundleCapability) rw.getCapability();
BundleWire bw = new BundleWireImpl(requirer, requirement, provider, capability);
bundleWires.add(bw);
if (Util.isFragment(revision)) {
if (debugLog) {
m_felix.getLogger().log(Logger.LOG_DEBUG, "FRAGMENT WIRE: " + rw.toString());
}
} else {
if (debugLog) {
m_felix.getLogger().log(Logger.LOG_DEBUG, "WIRE: " + rw.toString());
}
if (capability.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) {
importedPkgs.put((String) capability.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE), provider);
} else if (capability.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)) {
Set<String> pkgs = calculateExportedAndReexportedPackages(provider, wireMap, new HashSet<String>(), new HashSet<BundleRevision>());
for (String pkg : pkgs) {
List<BundleRevision> revs = requiredPkgs.get(pkg);
if (revs == null) {
revs = new ArrayList<BundleRevision>();
requiredPkgs.put(pkg, revs);
}
revs.add(provider);
}
}
}
}
List<BundleRevision> fragments = hosts.get(revision);
try {
wirings.put(revision, new BundleWiringImpl(m_felix.getLogger(), m_felix.getConfig(), this, (BundleRevisionImpl) revision, fragments, bundleWires, importedPkgs, requiredPkgs));
} catch (Exception ex) {
// throw an exception.
for (Entry<BundleRevision, BundleWiringImpl> wiringEntry : wirings.entrySet()) {
// Dispose of wiring.
try {
wiringEntry.getValue().dispose();
} catch (Exception ex2) {
// We are in big trouble.
RuntimeException rte = new RuntimeException("Unable to clean up resolver failure.", ex2);
m_felix.getLogger().log(Logger.LOG_ERROR, rte.getMessage(), ex2);
throw rte;
}
}
ResolveException re = new ResolveException("Unable to resolve " + revision, revision, null);
re.initCause(ex);
m_felix.getLogger().log(Logger.LOG_ERROR, re.getMessage(), ex);
throw re;
}
}
// and update the resolver state.
for (Entry<BundleRevision, BundleWiringImpl> entry : wirings.entrySet()) {
BundleRevisionImpl revision = (BundleRevisionImpl) entry.getKey();
// Mark revision as resolved.
BundleWiring wiring = entry.getValue();
revision.resolve(entry.getValue());
// Record dependencies.
for (BundleWire bw : wiring.getRequiredWires(null)) {
m_felix.getDependencies().addDependent(bw);
}
// Reindex the revision's capabilities since its resolved
// capabilities could be different than its declared ones
// (e.g., due to substitutable exports).
addRevision(revision);
// Update the state of the revision's bundle to resolved as well.
markBundleResolved(revision);
}
}
}
Aggregations