Chapter 12. Deploying a FAB
Abstract
Apache Karaf provides two different approaches for deploying FABs: hot deployment and manual deployment.
12.1. The FAB Deployment Model
Overview
FABs have a fundamentally different deployment model from standard OSGi bundles. When a FAB is installed, the FAB runtime automatically figures out what dependencies are required, by scanning the Maven metadata, and these dependencies are then installed dynamically.
What is a FAB?
A Fuse Application Bundle (FAB) is any JAR created using Apache Maven, or similar build tools, so that inside the JAR there is a
pom.xml
file at the following location (where groupId and artifactId are the Maven coordinates of the JAR):
META-INF/maven/groupId/artifactId/pom.xml
Which contains the transitive dependency information for the JAR.
Important
A FAB is not an OSGi bundle. At installation time, however, a FAB results in the creation of one or more bundles, which are constructed dynamically.
Manifest.mf file
It is possible to add some additional (optional) configuration to a FAB by including FAB-specific headers in the JAR's
Manifest.mf
file. For example, the FAB-Provided-Dependency
header can be used to specify whether some or all of the FAB's dependencies are to be shared.
For full details about FAB manifest headers, see Section 11.4, “Configuring a FAB”.
FAB deployment
Depending on how a FAB is configured, there are two basic alternatives for deploying a FAB:
Installing a FAB with private dependencies
Figure 12.1, “FAB Installed with Private Dependencies” shows how a FAB is installed when all of its dependencies are configured to be private.
Figure 12.1. FAB Installed with Private Dependencies
The figure shows the installation of the FAB,
Fab
, and its private dependencies, which proceeds as follows:
- The user explicitly deploys the FAB,
Fab
, into the OSGi container (either by hot deploying or manually deploying). - The FAB runtime scans the embedded
pom.xml
file and figures out all of the non-optional and non-test transitive dependencies. In this case, there are five private dependencies:DepA
,DepA1
,DepB
,DepB1
, andDepB2
. The FAB runtime auto-installs these dependencies by fetching them from the Maven repository. - The dependencies are added to the FAB's private class space and the whole collection is converted into a single OSGi bundle and installed in the OSGi container.
When a FAB is configured to have all of its dependencies private, as in this example, what you end up with is very similar to a WAR deployment (which also tends to keep its dependencies private, by default). An advantage that the FAB has over the WAR, however, is that the FAB does not need to be packaged together with its dependencies. Thus a FAB can be much smaller than a typical WAR package.
Optimising a FAB's shared dependencies
A FAB can have all private dependencies, some shared dependencies, or all shared dependencies. In other words, you can configure a FAB's dependencies anywhere on the spectrum from all-shared to all-private.
By default, a FAB keeps its dependencies private (except for the dependencies with Maven group ID
org.apache.camel
, org.apache.cxf
, or org.apache.activemq
). This deployment approach is relatively safe, because it minimizes the risk of version conflicts and so on. But it is also an expensive option, because it uses up a lot of system memory and resources. If you would like to experiment with sharing some of the FAB's dependencies, you can specify which artifacts to share using the FAB-Provided-Dependency:
header in the FAB's manifest, Manifest.mf
. For example:
FAB-Provided-Dependency: org.apache.camel:* org.apache.cxf:* org.apache.activemq:* org.springframework:*
In this way, you can easily optimize the performance of the FAB, while balancing the risk of version conflicts occurring.
Starting a FAB
Figure 12.3, “FAB Start” shows an outline of what happens when you start a FAB, in the case where the FAB shares its dependencies.
Figure 12.3. FAB Start
When you start a FAB using the
fab:start
console command, the FAB runtime iterates over the FAB's transitive dependencies and starts every single bundle in the tree of dependencies (starting with the leaves). This contrasts with the conventional osgi:start
console command, which starts only the specified bundle.
Default install behavior of a FAB
The default install behavior of a FAB is actually more complex than suggested by the all-private dependencies model (as shown in Figure 12.1, “FAB Installed with Private Dependencies”). In reality, the FAB runtime distinguishes between the following types of dependency:
- Plain FAB dependency (has
pom.xml
file, but no bundle headers)—by default, the plain FAB dependencies are added to the deployed FAB's private classpath and bundled together with the deployed FAB. - OSGi bundle dependency (has
pom.xml
file and bundle headers)—by default, the OSGi bundle dependencies are deployed as separate bundles (shared dependencies).
Figure 12.4, “Default FAB Install Behavior” shows how a FAB is installed, by default, when some its dependencies are plain FABs (
DepA
and DepA1
) and some of its dependencies are OSGi bundles (Bnd1
, Bnd2
, and Bnd3
):
Figure 12.4. Default FAB Install Behavior
The FAB runtime works on the assumption that whoever built an artifact as an OSGi bundle presumably intended for the artifact to be deployed as a bundle. Another good reason for deploying OSGi bundles separately is that this guarantees that the bundles will be properly activated when you invoke
fab:start
. If the dependent bundles (Bnd1
, Bnd2
, and Bnd3
) were merely added to the private classpath of the Fab
bundle, they would not be activated when fab:start
is invoked (in other words, any Spring configuration files or blueprint configuration files would fail to be activated).