use of org.apache.felix.framework.resolver.ResolveException in project felix 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);
}
}
}
use of org.apache.felix.framework.resolver.ResolveException in project felix by apache.
the class StatefulResolver method resolve.
BundleRevision resolve(BundleRevision revision, String pkgName) throws ResolutionException, BundleException {
BundleRevision provider = null;
// acquired the global lock below.
if ((revision.getWiring() != null) && isAllowedDynamicImport(revision, pkgName)) {
// Acquire global lock.
boolean locked = m_felix.acquireGlobalLock();
if (!locked) {
throw new ResolveException("Unable to acquire global lock for resolve.", revision, null);
}
// the case if a resolver hook does something bad.
if (m_isResolving) {
m_felix.releaseGlobalLock();
throw new IllegalStateException("Nested resolve operations not allowed.");
}
m_isResolving = true;
Map<Resource, List<Wire>> wireMap = null;
try {
// Double check to make sure that someone hasn't beaten us to
// dynamically importing the package, which can happen if two
// threads are racing to do so. If we have an existing wire,
// then just return it instead.
provider = ((BundleWiringImpl) revision.getWiring()).getImportedPackageSource(pkgName);
if (provider == null) {
// Prepare resolver hooks, if any.
ResolverHookRecord record = prepareResolverHooks(Collections.singleton(revision), Collections.EMPTY_SET);
// Select any singletons in the resolver state.
selectSingletons(record);
// Catch any resolve exception to rethrow later because
// we may need to call end() on resolver hooks.
ResolutionException rethrow = null;
try {
List<BundleRequirement> dynamics = Util.getDynamicRequirements(revision.getWiring().getRequirements(null));
// Loop through the importer's dynamic requirements to determine if
// there is a matching one for the package from which we want to
// load a class.
Map<String, Object> attrs = Collections.singletonMap(BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(revision, BundleRevision.PACKAGE_NAMESPACE, Collections.EMPTY_MAP, attrs);
final List<BundleCapability> candidates = findProvidersInternal(record, req, false, true);
// Try to find a dynamic requirement that matches the capabilities.
BundleRequirementImpl dynReq = null;
for (int dynIdx = 0; (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size()); dynIdx++) {
for (Iterator<BundleCapability> itCand = candidates.iterator(); (dynReq == null) && itCand.hasNext(); ) {
Capability cap = itCand.next();
if (CapabilitySet.matches(cap, ((BundleRequirementImpl) dynamics.get(dynIdx)).getFilter())) {
dynReq = (BundleRequirementImpl) dynamics.get(dynIdx);
}
}
}
// any candidates that do not match it.
if (dynReq != null) {
for (Iterator<BundleCapability> itCand = candidates.iterator(); itCand.hasNext(); ) {
Capability cap = itCand.next();
if (!CapabilitySet.matches(cap, dynReq.getFilter())) {
itCand.remove();
}
}
} else {
candidates.clear();
}
Map<Resource, Wiring> wirings = getWirings();
wireMap = wirings.containsKey(revision) ? m_resolver.resolveDynamic(new ResolveContextImpl(this, wirings, record, Collections.<BundleRevision>emptyList(), Collections.<BundleRevision>emptyList(), getFragments()) {
@Override
public List<Capability> findProviders(Requirement br) {
return (List) candidates;
}
}, revision.getWiring(), dynReq) : Collections.<Resource, List<Wire>>emptyMap();
} catch (ResolutionException ex) {
rethrow = ex;
}
// Release resolver hooks, if any.
releaseResolverHooks(record);
// If the resolve failed, rethrow the exception.
if (rethrow != null) {
throw rethrow;
}
if ((wireMap != null) && wireMap.containsKey(revision)) {
List<Wire> dynamicWires = wireMap.remove(revision);
Wire dynamicWire = dynamicWires.get(0);
// Mark all revisions as resolved.
markResolvedRevisions(wireMap);
// Dynamically add new wire to importing revision.
if (dynamicWire != null) {
// TODO can we optimize this?
if (dynamicWire.getRequirer() instanceof BundleRevision && dynamicWire.getRequirement() instanceof BundleRequirement && dynamicWire.getProvider() instanceof BundleRevision && dynamicWire.getCapability() instanceof BundleCapability) {
BundleRevision dwRequirer = (BundleRevision) dynamicWire.getRequirer();
BundleRequirement dwRequirement = (BundleRequirement) dynamicWire.getRequirement();
BundleRevision dwProvider = (BundleRevision) dynamicWire.getProvider();
BundleCapability dwCapability = (BundleCapability) dynamicWire.getCapability();
BundleWire bw = new BundleWireImpl(dwRequirer, dwRequirement, dwProvider, dwCapability);
m_felix.getDependencies().addDependent(bw);
((BundleWiringImpl) revision.getWiring()).addDynamicWire(bw);
m_felix.getLogger().log(Logger.LOG_DEBUG, "DYNAMIC WIRE: " + dynamicWire);
provider = ((BundleWiringImpl) revision.getWiring()).getImportedPackageSource(pkgName);
}
}
}
}
} finally {
// Clear resolving flag.
m_isResolving = false;
// Always release the global lock.
m_felix.releaseGlobalLock();
}
fireResolvedEvents(wireMap);
}
return provider;
}
use of org.apache.felix.framework.resolver.ResolveException in project felix by apache.
the class StatefulResolver method prepareResolverHooks.
private ResolverHookRecord prepareResolverHooks(Set<BundleRevision> mandatory, Set<BundleRevision> optional) throws BundleException, ResolutionException {
// This map maps the hook factory service to the actual hook objects. It
// needs to be a map that preserves insertion order to ensure that we call
// hooks in the correct order.
// The hooks are added in the order that m_felix.getHooks() returns them which
// is also the order in which they should be called.
Map<ServiceReference<ResolverHookFactory>, ResolverHook> hookMap = new LinkedHashMap<ServiceReference<ResolverHookFactory>, ResolverHook>();
// Get resolver hook factories.
Set<ServiceReference<ResolverHookFactory>> hookRefs = m_felix.getHookRegistry().getHooks(ResolverHookFactory.class);
Collection<BundleRevision> whitelist;
if (!hookRefs.isEmpty()) {
// Create triggers list.
Set<BundleRevision> triggers;
if (!mandatory.isEmpty() && !optional.isEmpty()) {
triggers = new HashSet<BundleRevision>(mandatory);
triggers.addAll(optional);
} else {
triggers = (mandatory.isEmpty()) ? optional : mandatory;
}
triggers = Collections.unmodifiableSet(triggers);
BundleException rethrow = null;
// Create resolver hook objects by calling begin() on factory.
for (ServiceReference<ResolverHookFactory> ref : hookRefs) {
try {
ResolverHookFactory rhf = m_felix.getService(m_felix, ref, false);
if (rhf != null) {
ResolverHook hook = Felix.m_secureAction.invokeResolverHookFactory(rhf, triggers);
if (hook != null) {
hookMap.put(ref, hook);
}
}
} catch (Throwable ex) {
rethrow = new BundleException("Resolver hook exception: " + ex.getMessage(), BundleException.REJECTED_BY_HOOK, ex);
// So we break here to make sure that no further resolver hooks are created.
break;
}
}
if (rethrow != null) {
for (ResolverHook hook : hookMap.values()) {
try {
Felix.m_secureAction.invokeResolverHookEnd(hook);
} catch (Exception ex) {
rethrow = new BundleException("Resolver hook exception: " + ex.getMessage(), BundleException.REJECTED_BY_HOOK, ex);
}
}
throw rethrow;
}
// Ask hooks to indicate which revisions should not be resolved.
whitelist = new ShrinkableCollection<BundleRevision>(getUnresolvedRevisions());
int originalSize = whitelist.size();
for (ResolverHook hook : hookMap.values()) {
try {
Felix.m_secureAction.invokeResolverHookResolvable(hook, whitelist);
} catch (Throwable ex) {
rethrow = new BundleException("Resolver hook exception: " + ex.getMessage(), BundleException.REJECTED_BY_HOOK, ex);
// So we break here to make sure that no further resolver operations are executed.
break;
}
}
if (rethrow != null) {
for (ResolverHook hook : hookMap.values()) {
try {
Felix.m_secureAction.invokeResolverHookEnd(hook);
} catch (Exception ex) {
rethrow = new BundleException("Resolver hook exception: " + ex.getMessage(), BundleException.REJECTED_BY_HOOK, ex);
}
}
throw rethrow;
}
// as an optimization.
if (whitelist.size() == originalSize) {
whitelist = null;
}
// Check to make sure the target revisions are allowed to resolve.
if (whitelist != null) {
// trigger revision in the mandatory set, so ignore that case.
if (mandatory.isEmpty() || !optional.isEmpty() || (mandatory.iterator().next().getWiring() == null)) {
mandatory.retainAll(whitelist);
optional.retainAll(whitelist);
if (mandatory.isEmpty() && optional.isEmpty()) {
throw new ResolveException("Resolver hook prevented resolution.", null, null);
}
}
}
} else {
whitelist = null;
}
return new ResolverHookRecord(hookMap, whitelist);
}
use of org.apache.felix.framework.resolver.ResolveException in project felix by apache.
the class StatefulResolver method resolve.
void resolve(Set<BundleRevision> mandatory, Set<BundleRevision> optional) throws ResolutionException, BundleException {
// Acquire global lock.
boolean locked = m_felix.acquireGlobalLock();
if (!locked) {
throw new ResolveException("Unable to acquire global lock for resolve.", null, null);
}
// the case if a resolver hook does something bad.
if (m_isResolving) {
m_felix.releaseGlobalLock();
throw new IllegalStateException("Nested resolve operations not allowed.");
}
m_isResolving = true;
Map<Resource, List<Wire>> wireMap = null;
try {
// Make our own copy of revisions.
mandatory = (mandatory.isEmpty()) ? mandatory : new HashSet<BundleRevision>(mandatory);
optional = (optional.isEmpty()) ? optional : new HashSet<BundleRevision>(optional);
// Prepare resolver hooks, if any.
ResolverHookRecord record = prepareResolverHooks(mandatory, optional);
// Select any singletons in the resolver state.
selectSingletons(record);
// Extensions are resolved differently.
for (Iterator<BundleRevision> it = mandatory.iterator(); it.hasNext(); ) {
BundleRevision br = it.next();
BundleImpl bundle = (BundleImpl) br.getBundle();
if (bundle.isExtension()) {
it.remove();
} else if (Util.isSingleton(br) && !isSelectedSingleton(br)) {
throw new ResolveException("Singleton conflict.", br, null);
}
}
for (Iterator<BundleRevision> it = optional.iterator(); it.hasNext(); ) {
BundleRevision br = it.next();
BundleImpl bundle = (BundleImpl) br.getBundle();
if (bundle.isExtension()) {
it.remove();
} else if (Util.isSingleton(br) && !isSelectedSingleton(br)) {
it.remove();
}
}
// Catch any resolve exception to rethrow later because
// we may need to call end() on resolver hooks.
ResolutionException rethrow = null;
try {
// Resolve the revision.
wireMap = m_resolver.resolve(new ResolveContextImpl(this, getWirings(), record, mandatory, optional, getFragments()));
} catch (ResolutionException ex) {
rethrow = ex;
}
// Release resolver hooks, if any.
releaseResolverHooks(record);
// If the resolve failed, rethrow the exception.
if (rethrow != null) {
throw rethrow;
}
// Otherwise, mark all revisions as resolved.
markResolvedRevisions(wireMap);
} finally {
// Clear resolving flag.
m_isResolving = false;
// Always release the global lock.
m_felix.releaseGlobalLock();
}
fireResolvedEvents(wireMap);
}
Aggregations