Skip to content

OSGI bundles configuration

Fathardie edited this page May 11, 2017 · 3 revisions

An OSGI implementation, such as Felix, loads OSGI bundles and handles any dependencies between the code that is exported and imported by the different bundles. OSGI bundles contain the code, a MANIFEST and an Activator. As stated by the specification, OSGI bundles can decide which code to publicly export and which code to hide. They can also specify which code they are dependent on. This page details how OSGI can decide which code there is and how the code is executed and used. It also details which guidelines we used on when to bundle code.

MANIFEST

Each bundle can depend on code which is contained by other bundles. Which bundle imports and exports which code is specified in the MANIFEST file. See Configuring bundle plugin on which elements in the MANIFEST do what. This page further explains how OSGI uses the MANIFEST

Activator

Other than a MANIFEST, each bundle can also include an Activator. This Activator is an class which details how the bundle should be initialized and destroyed. As we use the Felix Dependency Manager, our Activators have to inherit from the type DependencyActivatorBase. The abstract method init should then tell the DependencyManager argument that the bundle exists, which interface and implementation belong to the bundle and what its dependencies are. An example of the PhysicsEngineDriver bundle with its dependencies:

    @Override
    public void init(BundleContext bundleContext, DependencyManager dependencyManager) throws Exception {
        dependencyManager.add(createComponent()
            .setInterface(IPhysicsEngineDriver.class.getName(), null)
            .setImplementation(PhysicsEngineDriver.class)
            .add(createServiceDependency()
                .setService(IPhysicsEngine.class)
                .setRequired(true)
            )
            .add(createServiceDependency()
                .setService(IGameStateManager.class)
                .setRequired(true)
            )
        );
    }

To bundle or not to bundle

Common code

Normally with default Java loading, all code is thrown onto a single pile and if any code needs anything from that pile they can load it. If there are duplicated classes e.g. DuplicateClass, we found that Java chooses the DuplicateClass that is closest to the calling code in terms of classloaders. Java does not resolve this duplication itself and there exist multiple DuplicateClass which are not the same. This can cause issues with reflection where classes are sometimes checked for equivalence. Therefor, if there are common code dependencies between multiple OSGI bundles which do not belong to one of those bundles, it is best practice to wrap that into a separate OSGI bundle without an Activator.

Split big bundles into separate bundles

OSGI allows communication through interfaces. Sometimes a bundle is big and the codebase contained is already split through communication channels and interfaces. This may sound like a prime-target to split into multiple subbundles. We deem that such a split depends completely on the situation. In our case, we have the game-engine bundle with a number of sub-bundles e.g. gameengine-gamestate-manager. These sub-bundles can now be swapped easily by using a different bundle with the same interface. This is especially useful for the aforementioned gamestate-manager and the physicsengine-driver. However, if there are no reusability or swappable concerns, this might increase the amount of bundles without any added benefit.

Embeddable dependencies

Sometimes you need a dependency for a single bundle and you do not want to add it as a bundle. You can choose to either bundle the dependency as java code which is not exported or embed the dependency .jar. The respective difference is noted in the Configuring bundle plugin as Private Package and EmbedDependency