Search in sources :

Example 1 with ResolveException

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);
        }
    }
}
Also used : CapabilitySet(org.apache.felix.framework.capabilityset.CapabilitySet) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) Wire(org.osgi.resource.Wire) BundleWire(org.osgi.framework.wiring.BundleWire) BundleRequirement(org.osgi.framework.wiring.BundleRequirement) Entry(java.util.Map.Entry) BundleRevision(org.osgi.framework.wiring.BundleRevision) List(java.util.List) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) BundleWireImpl(org.apache.felix.framework.wiring.BundleWireImpl) BundleWiring(org.osgi.framework.wiring.BundleWiring) Resource(org.osgi.resource.Resource) BundleWire(org.osgi.framework.wiring.BundleWire) BundleException(org.osgi.framework.BundleException) ResolveException(org.apache.felix.framework.resolver.ResolveException) ResolutionException(org.osgi.service.resolver.ResolutionException) NoSuchElementException(java.util.NoSuchElementException) ResolveException(org.apache.felix.framework.resolver.ResolveException) BundleCapability(org.osgi.framework.wiring.BundleCapability)

Example 2 with ResolveException

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;
}
Also used : Wire(org.osgi.resource.Wire) BundleWire(org.osgi.framework.wiring.BundleWire) BundleRequirement(org.osgi.framework.wiring.BundleRequirement) BundleRequirementImpl(org.apache.felix.framework.wiring.BundleRequirementImpl) BundleWiring(org.osgi.framework.wiring.BundleWiring) Wiring(org.osgi.resource.Wiring) BundleRevision(org.osgi.framework.wiring.BundleRevision) List(java.util.List) ArrayList(java.util.ArrayList) BundleWireImpl(org.apache.felix.framework.wiring.BundleWireImpl) BundleCapability(org.osgi.framework.wiring.BundleCapability) Capability(org.osgi.resource.Capability) Resource(org.osgi.resource.Resource) BundleWire(org.osgi.framework.wiring.BundleWire) ResolveException(org.apache.felix.framework.resolver.ResolveException) ResolutionException(org.osgi.service.resolver.ResolutionException) BundleRequirement(org.osgi.framework.wiring.BundleRequirement) Requirement(org.osgi.resource.Requirement) BundleCapability(org.osgi.framework.wiring.BundleCapability)

Example 3 with ResolveException

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);
}
Also used : ResolverHookFactory(org.osgi.framework.hooks.resolver.ResolverHookFactory) ResolverHook(org.osgi.framework.hooks.resolver.ResolverHook) BundleException(org.osgi.framework.BundleException) ResolveException(org.apache.felix.framework.resolver.ResolveException) ResolutionException(org.osgi.service.resolver.ResolutionException) NoSuchElementException(java.util.NoSuchElementException) ServiceReference(org.osgi.framework.ServiceReference) LinkedHashMap(java.util.LinkedHashMap) ResolveException(org.apache.felix.framework.resolver.ResolveException) BundleRevision(org.osgi.framework.wiring.BundleRevision) BundleException(org.osgi.framework.BundleException)

Example 4 with ResolveException

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);
}
Also used : Resource(org.osgi.resource.Resource) ResolveException(org.apache.felix.framework.resolver.ResolveException) ResolutionException(org.osgi.service.resolver.ResolutionException) BundleRevision(org.osgi.framework.wiring.BundleRevision) List(java.util.List) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet)

Aggregations

ResolveException (org.apache.felix.framework.resolver.ResolveException)4 BundleRevision (org.osgi.framework.wiring.BundleRevision)4 ResolutionException (org.osgi.service.resolver.ResolutionException)4 ArrayList (java.util.ArrayList)3 List (java.util.List)3 Resource (org.osgi.resource.Resource)3 HashSet (java.util.HashSet)2 LinkedHashMap (java.util.LinkedHashMap)2 NoSuchElementException (java.util.NoSuchElementException)2 BundleWireImpl (org.apache.felix.framework.wiring.BundleWireImpl)2 BundleException (org.osgi.framework.BundleException)2 BundleCapability (org.osgi.framework.wiring.BundleCapability)2 BundleRequirement (org.osgi.framework.wiring.BundleRequirement)2 BundleWire (org.osgi.framework.wiring.BundleWire)2 BundleWiring (org.osgi.framework.wiring.BundleWiring)2 Wire (org.osgi.resource.Wire)2 HashMap (java.util.HashMap)1 Entry (java.util.Map.Entry)1 Set (java.util.Set)1 CapabilitySet (org.apache.felix.framework.capabilityset.CapabilitySet)1