Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Wiki Markup
_\[This document describes framework launching introduced in Felix Framework 2.0.0 and continuing with the latest releases; it is incompatible with older versions of the Felix framework.\]_

...

Introduction

The Apache Felix framework Framework is intended to be easily launchable and embeddable. For example, the Felix framework implementation avoids the use of system properties for configuration, since these are globals and can cause interference if multiple framework instances are created in the same VM. Felix The framework also tries to multiplex singleton facilities, like the URL stream handler factory. The goal is to make it possible to use Felix the framework in a variety of scenarios; however, this is still just a goal. In other words, this is a work in progress and if any issues arise, it would be greatly appreciated if they are brought to the attention of the Felix community. The next section provides a Felix API overviewan overview of the standard OSGi launching and embedding API for frameworks, while the remainder of the document is divided into two sections, one focusing on how to launch Felix and one focusing on how to embed Felix into a host application.

Anchor
overview
overview

OSGi Launching and Embedding API Overview

The Felix framework is implemented by the org.apache.felix.framework.Felix class or just Felix for short. As part of the R4.2 OSGi specification, the launching and embedding API of the OSGi framework has been standardized. The approach is to have the framework implement the org.osgi.framework.launch.Framework interface, which extends the org.osgi.framework.Bundle interface. These interfaces provide the necessary means to launch and manage framework instances. The Bundle interface is defined as:

...

Code Block
public interface Framework extends Bundle
{
    void init();
    FrameworkEvent waitForStop(long timeout);
}

To actually construct a framework instance, the R4.2 specification defines the FrameworkFactory interface:

Code Block
public interface FrameworkFactory
{
    Framework newFramework(Map configMapconfig);
}

The framework factory can be used to create configured framework instances. It is obtained following the standard META-INF/services approach.

...

  • org.osgi.framework.system.packages - specifies a list of packages the system bundle should export from the environment; if this is not set, then the framework uses a reasonable default fault.
  • org.osgi.framework.system.packages.extra - specifies a list of additional packages the system bundle should export from the environment that are appended to the packages specified in org.osgi.framework.system.packages; there is no default value for this property.
  • org.osgi.framework.bootdelegation - specifies a list of packages that should be made implicitly available to all bundles from the environment (i.e., no need to import them); there is no default value for this property and its use should be avoided.
  • org.osgi.framework.bundle.parent - Specifies which class loader is used for boot delegation. Possible values are: boot for the boot class loader, app for the application class loader, ext for the extension class loader, and framework for the framework's class loader. The default is boot.
  • org.osgi.framework.storage - specifies the path to a directory, which will be created if it does not exist, to use for bundle cache storage; the default value for this property is "felix-cache" in the current working directory.
  • org.osgi.framework.storage.clean - specifies whether the bundle cache should be flushed; the default value for this property is "none", but it can be changed to "onFirstInit" to flush the bundle cache when the framework is initialized.
  • org.osgi.framework.startlevel.beginning - specifies the start level the framework enters upon startup; the default value for this property is 1.

...

The init() method is necessary since the framework does not have a BundleContext when it is first created, so a transition to the Bundle.STARTING state is required to acquire its context (via Bundle.getBundleContext()) for performing various tasks, such as installing bundles. Note that the Felix framework also provides the felix.systembundle.activators property that serves a similar purpose, but is not standard. After the init() method completes, the follow actions have been performed:

...

In reality, the first step is optional, since all properties will have reasonable defaults, but if you are creating a launcher you will generally want to more than that, such as automatically installing and starting bundles when you start the framework instance. The default Felix launcher defines reusable functionality to automatically install and/or start bundles upon framework startup; see the usage document for more information on configuring the Felix framework and on the various configuration properties.

The remainder of this section describes how the standard Felix launcher works as well as how to create a custom launcher for Felix.

Anchor
standard-launcher
standard-launcher

Standard Felix Framework Launcher

The standard Felix framework launcher is very simple and is not intended to solve every possible requirement; it is intended to work for most standard situations. Most special launching requirements should be resolved by creating a custom launcher. This section describes how the standard launcher works. The following code represents the complete main() method of the standard launcher, each numbered comment will be described in more detail below:

Code Block
public static void main(String[] args) throws Exception
{
    // (1) Check for command line arguments and verify usage.
    String bundleDir = null;
    String cacheDir = null;
    boolean expectBundleDir = false;
    for (int i = 0; i < args.length; i++)
    {
        if (args[i].equals(BUNDLE_DIR_SWITCH))
        {
            expectBundleDir = true;
        }
        else if (expectBundleDir)
        {
            bundleDir = args[i];
            expectBundleDir = false;
        }
        else
        {
            cacheDir = args[i];
        }
    }

    if ((args.length > 3) || (expectBundleDir && bundleDir == null))
    {
        System.out.println("Usage: [-b <bundle-deploy-dir>] [<bundle-cache-dir>]");
        System.exit(0);
    }

    // (2) Load system properties.
    Main.loadSystemProperties();

    // (3) Read configuration properties.
    Properties configProps = Main.loadConfigProperties();
    if (configProps == null)
    {
        System.err.println("No " + CONFIG_PROPERTIES_FILE_VALUE + " found.");
        configProps = new Properties();
    }

    // (4) Copy framework properties from the system properties.
    Main.copySystemProperties(configProps);
        
    // (5) Use the specified auto-deploy directory over default.
    if (bundleDir != null)
    {
        configProps.setProperty(AutoProcessor.AUTO_DEPLOY_DIR_PROPERY, bundleDir);
    }

    // (6) Use the specified bundle cache directory over default.
    if (cacheDir != null)
    {
        configProps.setProperty(Constants.FRAMEWORK_STORAGE, cacheDir);
    }

    // (7) Add a shutdown hook to clean stop the framework.
    String enableHook = configProps.getProperty(SHUTDOWN_HOOK_PROP);
    if ((enableHook == null) || !enableHook.equalsIgnoreCase("false"))
    {
        Runtime.getRuntime().addShutdownHook(new Thread("Felix Shutdown Hook") {
            public void run()
            {
                try
                {
                    if (m_fwk != null)
                    {
                        m_fwk.stop();
                        m_fwk.waitForStop(0);
                    }
                }
                catch (Exception ex)
                {
                    System.err.println("Error stopping framework: " + ex);
                }
            }
        });
    }

    // Print welcome banner.
    System.out.println("\nWelcome to Felix");
    System.out.println("================\n");

    try
    {
        // (8) Create an instance and initialize the framework.
        FrameworkFactory factory = getFrameworkFactory();
        m_fwk = factory.newFramework(configProps);
        m_fwk.init();
        // (9) Use the system bundle context to process the auto-deploy
        // and auto-install/auto-start properties.
        AutoProcessor.process(configProps, m_fwk.getBundleContext());
        // (10) Start the framework.
        m_fwk.start();
        // (11) Wait for framework to stop to exit the VM.
        m_fwk.waitForStop(0);
        System.exit(0);
    }
    catch (Exception ex)
    {
        System.err.println("Could not create framework: " + ex);
        ex.printStackTrace();
        System.exit(-10);
    }
}

The general steps of the standard launcher are quite straightforward:

  1. The launcher supports setting the auto-deploy directory (with the -b switch) and setting the bundle cache path with a single argument, so check for this and issue a usage message it there are more than one arguments.
  2. Load any system properties specified in the system.properties file; this file is typically located in the conf/ directory of the Felix installation directory, but it can be specified directly using the felix.system.properties system property. This file is not needed to launch Felix and is provided merely for convenience when system properties must be specified. The file is a standard Java properties file, but it also supports property substitution using ${<property-name} syntax. Property substitution can be nested; only system properties will be used for substitution.
  3. Load any configuration properties specified in the config.properties file; this file is typically located in the conf/ directory of the Felix installation directory, but it can be specified directly using the felix.config.properties system property. This file is used to configure the Felix framework instance created by the launcher. The file is a standard Java properties file, but it also supports property substitution using "${<property-name>}" syntax. Property substitution can be nested; configuration and system properties will be used for substitution with configuration properties having precedence.
  4. For convenience, any configuration properties that are set as system properties are copied into the set of configuration properties. This provide an easy way to add to or override configuration properties specified in the config.properties file, since the Felix instance will never look at system properties for configuration.
  5. If the -b switch was used to specify an auto-deploy directory, then use that to set the value of felix.auto.deploy.dir.
  6. If a single command-line argument is specified, then use that to set the value of org.osgi.framework.storage; relative paths are relative to the current directory unless the felix.cache.rootdir property is set.
  7. Add a shutdown hook to cleanly stop the framework, unless the hook is disabled.
  8. Create a framework instance using the FrameworkFactory passing in the configuration properties, then initialize the factory instance; see the custom launcher example below to see how the META-INF/services FrameworkFactory is obtained.
  9. Use org.apache.felix.main.AutoProcessor, which will automatically deploy any bundles in the auto-deploy directory as well as bundles specified in the felix.auto.install and felix.auto.start configuration properties during framework startup to automatically install and/or start bundles; see the usage document for more information configuration properties and bundle auto-deploy.
  10. Invoke waitForStop() to wait for the framework to stop to force the VM to exit; this is necessary because the framework never calls System.exit() and some libraries (e.g., Swing) create threads that will not allow the VM to exit.

...