Fuse Bundle Overview

This document hopes to explain what Fuse Bundles (or FABs) are and how you use them.

Why Fuse Bundles?

Fuse Bundles are designed to make it very easy for application developers to create applications that can be deployed in OSGi containers or web containers so that its:-

For more detail see the motivations behind creating Fuse Bundles

What is a Fuse Bundle?

A Fuse Bundle, or FAB, is any jar created using Apache Maven or similar build tools so that inside the jar there is a pom.xml file at

META-INF/maven/groupId/artifactId/pom.xml (and pom.properties file)

which contain the transitive dependency information for the jar.

Installing a FAB

In your OSGi container such as Fuse ESB or Apache Karaf with the Fuse bundle feature installed - you can then install any FAB as if it were a WAR or Karaf feature.

To install a FAB with some value of groupId, artfactId, version type the following command into the console of either Fuse ESB or Apache Karaf (if it has the Fuse bundle feature installed)

install fab:mvn:groupId/artifactId/version

The fab: prefix means treat the given jar as a FAB (Fuse Bundle). This also works with other URIs to mvn: such as file: or http: etc.

Or you can copy a FAB as a file ending in .fab (rather than .jar) to the deploy directory of your container, or use the command line shell in Fuse ESB or Karaf

How does it work?

When a FAB is installed it is converted into a valid OSGi bundle dealing with its transitive dependencies.

To do this the pom.xml is extracted from the jar and used to figure out, by default, the non-optional and non-test transitive dependencies for the FAB to be able to create the OSGi bundle so that it fully respects the pom.xml dependencies.

So when you deploy a FAB into an OSGi container it is transformed into a regular OSGi bundle which other OSGi bundles or FABs can work with. A FAB can depend on any number of regular jars or actual OSGi bundles.

By default when you install a FAB into a container all its transient dependencies are also installed (if they are not already) so things just work as you'd expect.

Configuration

There are a number of optional manifest headers you can use to help configure how the pom.xml transitive dependencies are included in a FAB.

Configure the sharing of classes

The default in FAB is to use simple flat class loaders - like building a WAR using Maven - rather than using complex shared class loaders. Typically flat class loaders tend to just work in your IDE, build tool and then your container. Class loader problems typically occur when you try to share classes across different deployments; so FABs aim to just work by default; but then let you optimise things later to improve your sharing as and when you need it rather than forcing you to think about sharing issues for all dependencies and deployment units up front.

However we often want to share code across deployment units. For example you may wish to share slf4j, Apache Camel or Spring across a number of deployment units to avoid having to load that code multiple times in memory for the same JVM.

So to share a dependency (and its transitive dependencies) you just declare a dependency with a provided scope in your pom.xml. e.g.

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-core</artifactId>
  <version>${camel-version}</version>
  <scope>provided</scope>
</dependency>

This is the same approach you use when building a WAR using Maven to avoid things like the servlet API or JSP being included inside the WAR.

FAB-Provided-Dependency

An alternative approach to the <scope>provided</scope> XML is to use the jar manifest header FAB-Provided-Dependency which denotes which artefacts (transitively) should be shared across deployment units. This header, like most FAB headers, uses a simple concise syntax which supports wildcards.

The syntax lets you specify zero to many artifacts as follows

FAB-Provided-Dependency: groupId:artifactId someGroup:someArtifact

You can use wildcards for the groupId or artifactId. So for example if you wish to share all Apache Camel and Spring dependencies (transitively) in your FAB just add this

FAB-Provided-Dependency: org.apache.camel:* org.springframework:*

which some find a little simpler and more DRY than using the <scope>provided</scope> XML on every dependency to be shared

FAB-Dependency-Require-Bundle

Specifies a list of artefacts which should not use the regular OSGi mechanism of importing packages, but instead should use the OSGi Require-Bundle directive.

By default the packages are imported from shared dependencies using the OSGi Import-Package directive for all artefacts not selected via the FAB-Dependency-Require-Bundle expression.

FAB-Include-Optional-Dependency

Optional dependencies are marked in a pom.xml using the <optional>true</optional> XML on a dependency.

By default optional dependencies are excluded in a FAB. To explicitly include them you need to add them with the FAB-Include-Optional-Dependency manifest entry.

So to include all optional dependencies use

FAB-Include-Optional-Dependency: *:*

What are the drawbacks?

None :). Fuse Bundles create regular valid OSGi bundles and they provide a nice simple abstraction so you don't need to work with OSGi metadata; but if you really want to you can either still write OSGi bundles by hand, reuse existing OSGi bundles or reuse FABs in other OSGi bundles or put OSGi metadata explicitly into your FAB.