Bundle installBundle()

in framework/src/main/java/org/apache/felix/framework/Felix.java [3225:3449]


    Bundle installBundle(
        Bundle origin, String location, InputStream is)
        throws BundleException
    {
        BundleArchive ba = null;
        BundleImpl existing, bundle = null;

        // Acquire an install lock.
        acquireInstallLock(location);

        try
        {
            // Check to see if the framework is still running;
            if ((getState() == Bundle.STOPPING) ||
                (getState() == Bundle.UNINSTALLED))
            {
                throw new BundleException("The framework has been shutdown.");
            }

            // If bundle location is already installed, then
            // return it as required by the OSGi specification.
            existing = (BundleImpl) getBundle(location);
            if (existing == null)
            {
                // First generate an identifier for it.
                long id = getNextId();

                try
                {
                    // Add the bundle to the cache.
                    ba = m_cache.create(id, getInitialBundleStartLevel(), location, is, m_connectFramework);
                }
                catch (Exception ex)
                {
                    throw new BundleException(
                        "Unable to cache bundle: " + location, ex);
                }
                finally
                {
                    try
                    {
                        if (is != null) is.close();
                    }
                    catch (IOException ex)
                    {
                        m_logger.log(
                            Logger.LOG_ERROR,
                            "Unable to close input stream.", ex);
                    }
                }

                try
                {
                    // Acquire the global lock to create the bundle,
                    // since this impacts the global state.
                    boolean locked = acquireGlobalLock();
                    if (!locked)
                    {
                        throw new BundleException(
                            "Unable to acquire the global lock to install the bundle.");
                    }
                    try
                    {
                        bundle = new BundleImpl(this, origin, ba);
                    }
                    finally
                    {
                        // Always release the global lock.
                        releaseGlobalLock();
                    }

                    if (!bundle.isExtension())
                    {
                        Object sm = System.getSecurityManager();
                        if (sm != null)
                        {
                            ((SecurityManager) sm).checkPermission(
                                new AdminPermission(bundle, AdminPermission.LIFECYCLE));
                        }
                    }
                    else
                    {
                        m_extensionManager.addExtensionBundle(bundle);
                    }
                }
                catch (Throwable ex)
                {
                    // Remove bundle from the cache.
                    try
                    {
                        if (bundle != null)
                        {
                            bundle.closeAndDelete();
                        }
                        else if (ba != null)
                        {
                            ba.closeAndDelete();
                        }
                    }
                    catch (Exception ex1)
                    {
                        m_logger.log(bundle,
                            Logger.LOG_ERROR,
                            "Could not remove from cache.", ex1);
                    }
                    if (ex instanceof BundleException)
                    {
                        throw (BundleException) ex;
                    }
                    else if (ex instanceof AccessControlException)
                    {
                        throw (AccessControlException) ex;
                    }
                    else
                    {
                        throw new BundleException("Could not create bundle object.", ex);
                    }
                }

                // Acquire global lock.
                boolean locked = acquireGlobalLock();
                if (!locked)
                {
                    // If the calling thread holds bundle locks, then we might not
                    // be able to get the global lock.
                    throw new IllegalStateException(
                        "Unable to acquire global lock to add bundle.");
                }
                try
                {
                    // Use a copy-on-write approach to add the bundle
                    // to the installed maps.
                    Map[] maps = new Map[] {
                        new HashMap<String, BundleImpl>(m_installedBundles[LOCATION_MAP_IDX]),
                        new TreeMap<Long, BundleImpl>(m_installedBundles[IDENTIFIER_MAP_IDX])
                    };
                    maps[LOCATION_MAP_IDX].put(location, bundle);
                    maps[IDENTIFIER_MAP_IDX].put(Long.valueOf(bundle.getBundleId()), bundle);
                    m_installedBundles = maps;
                }
                finally
                {
                    releaseGlobalLock();
                }

                for (Bundle extension : m_extensionManager.resolveExtensionBundles(this))
                {
                    m_extensionManager.startExtensionBundle(this, (BundleImpl) extension);
                }
            }
        }
        finally
        {
            // Always release install lock.
            releaseInstallLock(location);

            // Always try to close the input stream.
            try
            {
                if (is != null) is.close();
            }
            catch (IOException ex)
            {
                m_logger.log(bundle,
                    Logger.LOG_ERROR,
                    "Unable to close input stream.", ex);
                // Not much else we can do.
            }
        }

        if (existing != null)
        {
            Set<ServiceReference<org.osgi.framework.hooks.bundle.FindHook>> hooks =
                    getHookRegistry().getHooks(org.osgi.framework.hooks.bundle.FindHook.class);
            if (!hooks.isEmpty())
            {
                Collection<Bundle> bundles = new ArrayList<>(1);
                bundles.add(existing);
                bundles = new ShrinkableCollection<>(bundles);
                for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
                {
                    org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook, false);
                    if (fh != null)
                    {
                        try
                        {
                            m_secureAction.invokeBundleFindHook(
                                fh, ((BundleImpl) origin)._getBundleContext(), bundles);
                        }
                        catch (Throwable th)
                        {
                            m_logger.doLog(
                                hook.getBundle(),
                                hook,
                                Logger.LOG_WARNING,
                                "Problem invoking bundle hook.",
                                th);
                        }
                    }
                }

                if (origin != this)
                {
                    // If the origin was something else than the system bundle, reject this action if
                    // the bundle has been removed by the hooks. However, if it is the system bundle,
                    // the install action should always succeed, regardless of whether the hooks are
                    // trying to prevent it.
                    if (bundles.isEmpty())
                    {
                        throw new BundleException(
                            "Bundle installation rejected by hook.",
                            BundleException.REJECTED_BY_HOOK);
                    }
                }
            }
        }
        else
        {
            // Fire bundle event.
            fireBundleEvent(BundleEvent.INSTALLED, bundle, origin);
        }

        // Return new bundle.
        return (existing != null) ? existing : bundle;
    }