Search in sources :

Example 1 with BundleWireImpl

use of org.apache.felix.framework.wiring.BundleWireImpl in project felix by apache.

the class ExtensionManager method resolveExtensionBundles.

public List<Bundle> resolveExtensionBundles(Felix felix) {
    if (m_unresolvedExtensions.isEmpty()) {
        return Collections.emptyList();
    }
    // Collect the highest version of unresolved that are not already resolved by bsn
    List<BundleRevisionImpl> extensions = new ArrayList<BundleRevisionImpl>();
    // Collect the unresolved that where filtered out as alternatives in case the highest version doesn't resolve
    List<BundleRevisionImpl> alt = new ArrayList<BundleRevisionImpl>();
    outer: for (BundleRevisionImpl revision : m_unresolvedExtensions) {
        // Already resolved by bsn?
        for (BundleRevisionImpl existing : m_resolvedExtensions) {
            if (existing.getSymbolicName().equals(revision.getSymbolicName())) {
                // Then ignore it
                continue outer;
            }
        }
        // Otherwise, does a higher version exist by bsn?
        for (BundleRevisionImpl other : m_unresolvedExtensions) {
            if ((revision != other) && (revision.getSymbolicName().equals(other.getSymbolicName())) && revision.getVersion().compareTo(other.getVersion()) < 0) {
                // Add this one to alternatives and filter it
                alt.add(revision);
                continue outer;
            }
        }
        // no higher version and not resolved yet by bsn - try to resolve it
        extensions.add(revision);
    }
    // This will return all resolvable revisions with the wires they need
    Map<BundleRevisionImpl, List<BundleWire>> wirings = findResolvableExtensions(extensions, alt);
    List<Bundle> result = new ArrayList<Bundle>();
    for (Map.Entry<BundleRevisionImpl, List<BundleWire>> entry : wirings.entrySet()) {
        BundleRevisionImpl revision = entry.getKey();
        // move this revision from unresolved to resolved
        m_unresolvedExtensions.remove(revision);
        m_resolvedExtensions.add(revision);
        BundleWire wire = new BundleWireImpl(revision, revision.getDeclaredRequirements(BundleRevision.HOST_NAMESPACE).get(0), m_systemBundleRevision, getCapabilities(BundleRevision.HOST_NAMESPACE).get(0));
        try {
            revision.resolve(new BundleWiringImpl(m_logger, m_configMap, null, revision, null, Collections.singletonList(wire), Collections.EMPTY_MAP, Collections.EMPTY_MAP));
        } catch (Exception ex) {
            m_logger.log(revision.getBundle(), Logger.LOG_ERROR, "Error resolving extension bundle : " + revision.getBundle(), ex);
        }
        felix.getDependencies().addDependent(wire);
        appendCapabilities(entry.getKey().getDeclaredExtensionCapabilities(null));
        for (BundleWire w : entry.getValue()) {
            if (!w.getRequirement().getNamespace().equals(BundleRevision.HOST_NAMESPACE) && !w.getRequirement().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) {
                ((BundleWiringImpl) w.getRequirer().getWiring()).addDynamicWire(w);
                felix.getDependencies().addDependent(w);
            }
        }
        final File f;
        Content revisionContent = revision.getContent();
        if (revisionContent instanceof JarContent) {
            f = ((JarContent) revisionContent).getFile();
        } else {
            f = ((DirectoryContent) revisionContent).getFile();
        }
        try {
            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {

                @Override
                public Void run() throws Exception {
                    m_extenderFramework.add(f);
                    return null;
                }
            });
        } catch (Exception ex) {
            m_logger.log(revision.getBundle(), Logger.LOG_ERROR, "Error adding extension bundle to framework classloader: " + revision.getBundle(), ex);
        }
        felix.setBundleStateAndNotify(revision.getBundle(), Bundle.RESOLVED);
        result.add(revision.getBundle());
    }
    // at this point, all revisions left in unresolved are not resolvable
    m_failedExtensions.addAll(m_unresolvedExtensions);
    m_unresolvedExtensions.clear();
    if (!wirings.isEmpty()) {
        felix.getResolver().addRevision(getRevision());
    }
    return result;
}
Also used : JarContent(org.apache.felix.framework.cache.JarContent) BundleWireImpl(org.apache.felix.framework.wiring.BundleWireImpl) Bundle(org.osgi.framework.Bundle) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) BundleWire(org.osgi.framework.wiring.BundleWire) BundleException(org.osgi.framework.BundleException) NoSuchElementException(java.util.NoSuchElementException) IOException(java.io.IOException) JarContent(org.apache.felix.framework.cache.JarContent) Content(org.apache.felix.framework.cache.Content) DirectoryContent(org.apache.felix.framework.cache.DirectoryContent) List(java.util.List) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ImmutableList(org.apache.felix.framework.util.ImmutableList) ArrayList(java.util.ArrayList) Map(java.util.Map) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) StringMap(org.apache.felix.framework.util.StringMap) File(java.io.File)

Example 2 with BundleWireImpl

use of org.apache.felix.framework.wiring.BundleWireImpl 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 3 with BundleWireImpl

use of org.apache.felix.framework.wiring.BundleWireImpl 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)

Aggregations

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