LibraryPrintFeedback

Deploying into the Container

Version 7.1

December 2012
Trademark Disclaimer
Third Party Acknowledgements

Updated: 08 Jan 2014

Table of Contents

I. The Fuse ESB Enterprise Container
1. Fuse ESB Enterprise Overview
Fuse ESB Enterprise Container Architecture
Deployment Models
Dependency Injection Frameworks
Synchronous Communication
Asynchronous Communication
Fuse Fabric
2. Dependency Injection Frameworks
Spring and Blueprint Frameworks
Hot Deployment
Using OSGi Configuration Properties
3. Building with Maven
Maven Directory Structure
Preparing to use Maven
4. Locating Dependencies
Understanding Where Fuse ESB Enterprise Bundles are Stored
Locating Maven Artifacts at Build Time
Locating Maven Artifacts at Run Time
Locating Artifacts in a Fabric
Generating a Custom Offline Repository
II. The Fuse Application Bundle Deployment Model
5. Building a FAB
Generating a FAB Project
Class Sharing
Modifying an Existing Maven Project
Configuring a FAB
6. Deploying a FAB
The FAB Deployment Model
FABs and Features
Hot Deployment
Manual Deployment
Configuring Maven for FAB
7. FAB Tutorial
Generating and Running an EIP FAB
III. WAR Deployment Model
8. Building a WAR
Modifying an Existing Maven Project
Bootstrapping a CXF Servlet in a WAR
Bootstrapping a Spring Context in a WAR
9. Deploying a WAR
Converting the WAR Using the war Scheme
Configuring the Web Container
IV. OSGi Bundle Deployment Model
10. Introduction to OSGi
Fuse ESB Enterprise
OSGi Framework
OSGi Services
OSGi Bundles
11. Building an OSGi Bundle
Generating a Bundle Project
Modifying an Existing Maven Project
Packaging a Web Service in a Bundle
Configuring the Bundle Plug-In
12. Deploying an OSGi Bundle
Hot Deployment
Manual Deployment
Lifecycle Management
Troubleshooting Dependencies
13. Deploying Features
Creating a Feature
Deploying a Feature
14. Deploying a Plain JAR
Bundle Tool (Bnd)
Converting a JAR Using Bnd
Converting a JAR Using the wrap Scheme
15. OSGi Bundle Tutorials
Generating and Running an EIP Bundle
Generating and Running a Web Services Bundle
V. OSGi Service Layer
16. OSGi Services
The Blueprint Container
Blueprint Configuration
Defining a Service Bean
Exporting a Service
Importing a Service
Publishing an OSGi Service
Accessing an OSGi Service
Integration with Apache Camel
VI. Asynchronous Communication
17. JMS Broker
Working with the Default Broker
JMS Endpoints in a Router Application
18. Inter-Bundle Communication with the NMR
Architecture of the NMR
The Apache Camel NMR Component
A. URL Handlers
File URL Handler
HTTP URL Handler
Mvn URL Handler
Wrap URL Handler
War URL Handler
B. OSGi Best Practices
OSGi Tooling
Building OSGi Bundles
Sample POM File
C. Pax-Exam Testing Framework
Introduction to Pax-Exam
Sample Pax-Exam Test Class
Index

List of Figures

1.1. Fuse ESB Enterprise Container Architecture
1.2. Installing an OSGi Bundle
1.3. Installing a FAB
1.4. Installing a WAR
4.1. How Maven Locates Artifacts at Build Time
4.2. How the Container Locates Artifacts at Run Time
4.3. How Containers Locate Artifacts in a Fabric
6.1. FAB Installed with Private Dependencies
6.2. FAB Installed with Shared Dependencies
6.3. FAB Start
6.4. Default FAB Install Behavior
10.1. Fuse ESB Architecture
16.1. Reference to Stateless Service
16.2. List of References to Stateful Services
18.1. NMR Architecture

List of Tables

1.1. Alternative Deployment Packages
16.1. Comparison of Spring bean with Blueprint bean
A.1. Default Instructions for Wrapping a JAR
A.2. Default Instructions for Wrapping a WAR File

List of Examples

2.1. Using OSGi Configuration Properties in Spring XML
2.2. Using OSGi Configuration Properties in Blueprint
3.1. Standard Maven Directory Layout
3.2. Adding the FuseSource Repositories to Maven
4.1. Initial Setting for a Container's Default Repositories
4.2. Setting a Container's Remote Repositories
4.3. Adding a Fabric Maven Proxy to a POM
5.1. Configuring FAB Manifest Headers in the POM
6.1. Changing the Local Repository
11.1. Configuration of Mandatory Import Packages
11.2. Setting a bundle's symbolic name
11.3. Setting a bundle's name
11.4. Setting a bundle's version
11.5. Including a private package in a bundle
11.6. Specifying the packages imported by a bundle
14.1. The example-jpa-osgi Feature
16.1. Sample Service Export with a Single Interface
16.2. Sample Account Classes and Interfaces
16.3. The HelloWorldSvc Interface
16.4. The HelloWorldSvcImpl Class
16.5. Blueprint File for Exporting a Service
16.6. Blueprint File for Importing a Service
16.7. The Client Class
17.1. Configuring the Default Broker's Data Directory
17.2. Deleting the Default Broker Configuration
17.3. Sample Route with JMS Endpoints
18.1. Creating the NMR Component Bean
18.2. Spring XML Defining a Route with an NMR Endpoint
B.1. Sample POM File Illustrating Best Practices
C.1. Pax-Exam and Related Maven Dependencies
C.2. FeaturesText Class

Figure 1.1 shows a high-level overview of the Fuse ESB Enterprise container architecture, showing the variety of deployment models that are supported.


Fuse ESB Enterprise is a multi-faceted container that supports a variety of deployment models. You can deploy any of the following kinds of deployment unit:

OSGi bundle

An OSGi bundle is a JAR file augmented with metadata in the JAR's META-INF/MANIFEST.MF file. Because the Fuse ESB Enterprise container is fundamentally an OSGi container, the OSGi bundle is also the native format for the container. Ultimately, after deployment, all of the other deployment unit types are converted into OSGi bundles.

Fuse Application Bundle, FAB

A Fuse Application Bundle (FAB) is a Fuse-specific deployment unit optimised for the Fuse ESB Enterprise container. FABs are a plain JAR built using the Apache Maven. FABs address some of the issues when using OSGi such as dependency resolution and class-loader conflicts. The FAB deployer in Fuse ESB Enterprise scans the metadata in the POM and automatically downloads any dependencies needed by the bundle.

WAR

A Web application ARchive (WAR) is the standard archive format for applications that run inside a Web server. As originally conceived by the Java servlet specification, a WAR packages Web pages, JSP pages, Java classes, servlet code, and so on, as required for a typical Web application. More generally, however, a WAR can be any deployment unit that obeys the basic WAR packaging rules (which, in particular, require the presence of a Web application deployment descriptor, web.xml).

JBI service assembly

A Java Business Integration (JBI) service assembly is the basic unit of deployment for JBI applications. A discussion of the JBI container lies outside the scope of this document. For details, see Using Java Business Integration.

The Spring framework is a popular dependency injection framework, which is fully integrated into the Fuse ESB Enterprise container. In other words, Spring enables you to create instances of Java objects and wire them together by defining a file in XML format. In addition, you can also access a wide variety of utilities and services (such as security, persistence, and transactions) through the Spring framework.

The blueprint framework is a dependency injection framework defined by the OSGi Alliance. It is similar to Spring (in fact, it was originally sponsored by SpringSource), but is a more lightweight framework that is optimized for the OSGi environment.

At its heart, Fuse ESB Enterprise is an OSGi container, based on Apache Karaf, whose architecture is defined by the OSGi Service Platform Core Specification (available from http://www.osgi.org/Release4/Download). OSGi is a flexible and dynamic container, whose particular strengths include: sophisticated management of version dependencies; sharing libraries between applications; and support for dynamically updating libraries at run time (hot fixes).

For more details about the OSGi framework, see Introduction to OSGi.

While installing bundles to a fabric container is not radically different from installing bundles in a standalone container, there are a number of things to consider when thinking about creating profiles to deploy your applications:

You can deploy a camelContext using a Spring configuration file, where the root element is a Spring beans element and the camelContext element is a child of the beans element. In this case, the camelContext namespace must be http://camel.apache.org/schema/spring.

For example, the following Spring configuration defines a route that generates timer messages every two seconds, sending the messages to the ExampleRouter log (which get incorporated into the console log file, InstallDir/data/log/servicemix.log):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       >

  <camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
      <from uri="timer://myTimer?fixedRate=true&amp;period=2000"/>
      <to uri="log:ExampleRouter"/>
    </route>
  </camelContext>

</beans>

It is not necessary to specify schema locations in the configuration. But if you are editing the configuration file with an XML editor, you might want to add the schema locations in order to support schema validation and content completion in the editor. For the preceding example, you could specify the schema locations as follows:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
    ...

Example 2.1 shows how to pass the value of the prefix variable to the constructor of the myTransform bean in Spring XML, where the value of prefix is set by the OSGi Configuration Admin service.


The syntax, ${prefix}, substitutes the value of the prefix variable into the Spring XML file. The OSGi properties are set up using the following XML elements:

osgix:cm-properties

To integrate Spring properties with the properties from the OSGi Configuration Admin service, insert an osgix:cm-properties element into the Spring XML file. This element creates a bean that gets injected with all of the properties from the OSGi ManagedService instance that is identified by the persistent-id attribute. The minimal configuration consists of an empty osgix:cm-properties element that sets the persistent-id attribute and the id attribute—for example:

<osgix:cm-properties id="preProps" persistent-id="org.fusesource.example"/>

For an example of how the persistent ID relates to OSGi configuration settings, see the example in Add OSGi configurations to the feature.

If you want to define defaults for some of the properties in the Spring XML file, add prop elements as children of the osgix:cm-properties element, as shown in Example 2.1.

ctx:property-placeholder

Property placeholder is a Spring mechanism that enables you to use the syntax, ${PropName}, to substitute variables in a Spring XML file. By defining a ctx:property-placeholder element with a reference to the preProps bean (as in Example 2.1), you enable the property placeholder mechanism to substitute any of the variables from the preProps bean (which encapsulates the OSGi configuration properties) into the Spring XML file.

Example 2.2 shows how to pass the value of the prefix variable to the constructor of the myTransform bean in blueprint XML, where the value of prefix is set by the OSGi Configuration Admin service.


The syntax, {{prefix}}, substitutes the value of the prefix variable into the blueprint XML file. The OSGi properties are set up using the following XML elements:

cm:property-placeholder

This element gives you access to the properties associated with the specified persistent ID. After defining this element, you can use the syntax, {{PropName}}, to substitute variables belonging to the specified persistent ID.

cm:property-placeholder/cm:default-properties

You can optionally specify default values for properties by defining cm:property elements inside the cm:default-properties element. If the corresponding etc/PersistentID.cfg file defines property values, however, these will be used instead.

Maven is an open source build system which is available from the Apache Maven project. This chapter explains some of the basic Maven concepts and describes how to set up Maven to work with Fuse ESB Enterprise. In principle, you could use any build system to build an OSGi bundle. But Maven is strongly recommended, because it is well supported by Fuse ESB Enterprise. Moreover, Maven is a requirement for building FABs.

Example 3.1 shows the elements of the standard Maven directory layout that are relevant to building OSGi bundle projects. In addition, the standard locations for Spring-DM and Blueprint configuration files (which are not defined by Maven) are also shown.


[Note]Note

It is possible to override the standard directory layout, but this is not a recommended practice in Maven.

By default, Fuse ESB Enterprise installs and activates support for Spring Dynamic Modules (Spring DM), which integrates Spring with the OSGi container. This means that it is possible for you to include Spring configuration files, META-INF/spring/*.xml, in your bundle. One of the key consequences of having Spring DM enabled in the OSGi container is that the lifecycle of the Spring application context is automatically synchronized with the OSGi bundle lifecycle:

  • Activation—when a bundle is activated, Spring DM automatically scans the bundle to look for Spring configuration files in the standard location (any .xml files found under the META-INF/spring/ directory). If any Spring files are found, Spring DM creates an application context for the bundle and creates the beans defined in the Spring configuration files.

  • Stopping—when a bundle is stopped, Spring DM automatically shuts down the bundle's Spring application context, causing any Spring beans to be deleted.

In practice, this means that you can treat your Spring-enabled bundle as if it is being deployed in a Spring container. Using Spring DM, the features of the OSGi container and a Spring container are effectively merged. In addition, Spring DM provides additional features to support the OSGi container environment—some of these features are discussed in OSGi Services.

In order to build a project using Maven, you must have the following prerequisites:

In order to access artifacts from the FuseSource Maven repository, you need to add it to Maven's settings.xml file. Maven looks for your settings.xml file in the .m2 directory of the user's home directory. If there is not a user specified settings.xml file, Maven will use the system-level settings.xml file at M2_HOME/conf/settings.xml.

To add the FuseSource repository to Maven's list of repositories, you can either create a new .m2/settings.xml file or modify the system-level settings. In the settings.xml file, add the repository element for the FuseSource repository as shown in bold text in Example 3.2.


The preceding example also shows repository element for the following repositories:

  • fusesource-snapshot repository—if you want to experiment with building your application using an Fuse ESB Enterprise snapshot kit, you can include this repository.

  • apache-public repository—you might not always need this repository, but it is often useful to include it, because Fuse ESB Enterprise depends on many of the artifacts from Apache.

A key aspect of Maven functionality is the ability to locate artifacts and manage the dependencies between them. Maven defines the location of an artifact using the system of Maven coordinates, which uniquely define the location of a particular artifact. A basic coordinate tuple has the form, {groupId, artifactId, version}. Sometimes Maven augments the basic set of coordinates with the additional coordinates, packaging and classifier. A tuple can be written with the basic coordinates, or with the additional packaging coordinate, or with the addition of both the packaging and classifier coordinates, as follows:

groupdId:artifactId:version
groupdId:artifactId:packaging:version
groupdId:artifactId:packaging:classifier:version

Each coordinate can be explained as follows:

The group ID, artifact ID, packaging, and version are defined by the corresponding elements in an artifact's POM file. For example:

<project ... >
  ...
  <groupId>org.fusesource.example</groupId>
  <artifactId>bundle-demo</artifactId>
  <packaging>bundle</packaging>
  <version>1.0-SNAPSHOT</version>
  ...
</project>

For example, to define a dependency on the preceding artifact, you could add the following dependency element to a POM:

<project ... >
  ...
  <dependencies>
    <dependency>
      <groupId>org.fusesource.example</groupId>
      <artifactId>bundle-demo</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
  ...
</project>
[Note]Note

It is not necessary to specify the bundle package type in the preceding dependency, because a bundle is just a particular kind of JAR file and jar is the default Maven package type. If you do need to specify the packaging type explicitly in a dependency, however, you can use the type element.

Figure 4.2 shows an overview of the procedure that Fuse ESB Enterprise follows when a feature or bundle is installed at run time.


The steps followed to locate the required Maven artifacts are:

  1. The container searches for artifacts in the system repository.

    This repository contains all of the artifacts provided with the Fuse ESB Enterprise installation. The system repository is located at EsbInstallDir/system.

  2. If an artifact is not available in the system repository, the container searches any other configured default repositories.

    Fuse ESB Enterprise allows you to specify one or more repositories into which you can place artifacts. For example, you could use a shared folder as a default repository that provides an easy way to distribute bundles to remote machines. See Default repositories for details on configuring the default repositories.

  3. If the artifact is not available in the default repositories, the container searches the Maven local repository.

    The default location of the local repository is the .m2/repository/ directory under the user's home directory. See Local repository for details on configuring the local repository.

  4. If the artifact is not available in any of the local repositories, the container searches the remote repositories specified in the Fuse ESB Enterprise configuration.

    The remote repositories are specified by the org.ops4j.pax.url.mvn.repositories property in the org.ops4j.pax.url.mvn. PID. See Remote repositories for details on configuring the remote repositories that the container will check.

    [Note]Note

    If an artifact is found in a remote repository, it is automatically downloaded and installed into the local repository.

Because fabric containers generally do not check a repository local to the machine on which it is running, you must load all of an application's artifacts into a repository that the fabric's Maven proxy knows about. There are two ways to do this:

A feature repository is a location that stores feature descriptor files. Generally, because features can depend recursively on other features and because of the complexity of the dependency chains, the project normally requires access to all of the standard Fuse ESB Enterprise feature repositories.

To see the full list of standard feature repositories used by your installation of Fuse ESB Enterprise, open the etc/org.apache.karaf.features.cfg configuration file and look at the featuresRepository setting, which is a comma-separated list of feature repositories, like the following:

Now, add the listed feature repositories to the configuration of the features-maven-plugin in your POM file. Open the project's pom.xml file and add a descriptor element (as a child of the descriptors element) for each of the standard feature repositories. For example, given the preceding value of the featuresRepositories list, you would define the features-maven-plugin descriptors list in pom.xml as follows:

Generally, the project requires access to all of the standard Fuse ESB Enterprise remote repositories. To see the full list of standard remote repositories, open the etc/org.ops4j.pax.url.mvn.cfg configuration file and look at the org.ops4j.pax.url.mvn.repositories setting, which is a comma-separated list of URLs like the following:

Each entry in this list must be converted into a repository element, which is then inserted as a child element of the respositories element in the project's pom.xml file. The preceding repository URLs have slightly different formats and must be converted as follows:

RepoURL

The value of the repository URL, RepoURL, is inserted directly into the url child element of the repository element. For example, the http://repo1.maven.org/maven2 repository URL translates to the following repository element:

<repository>
  <!-- 'id' can be whatever you like -->
  <id>repo1.maven.org</id>
  <!-- 'name' can be whatever you like -->
  <name>Maven central</name>
  <url>http://repo1.maven.org/maven2</url>
  <snapshots>
    <enabled>false</enabled>
  </snapshots>
  <releases>
    <enabled>true</enabled>
  </releases>
</repository>
RepoURL@snapshots

The @snapshots suffix indicates that downloading snapshots should be enabled for this repository. When specifying the value of the url element, remove the @snapshots suffix from the URL. Change the snapshots/enabled flag to true, as shown in the following example:

<repository>
  <id>IdOfRepo</id>
  <name>LongNameOfRepo</name>
  <url>RepoURL</url>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
  <releases>
    <enabled>true</enabled>
  </releases>
</repository>
RepoURL@snapshots@noreleases

The combination of the @snapshots suffix and the @noreleases suffix indicates that downloading snapshots should be enabled and downloading releases should be disabled for this repository. When specifying the value of the url element, remove both suffixes from the URL. Change the snapshots/enabled flag to true and change the releases/enabled flag to false, as shown in the following example:

<repository>
  <id>IdOfRepo</id>
  <name>LongNameOfRepo</name>
  <url>RepoURL</url>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
  <releases>
    <enabled>false</enabled>
  </releases>
</repository>

To configure a FAB, you can optionally specify any of the following FAB manifest headers:

FAB-Version-Range-Digits

See Specifying version ranges.

FAB-Provided-Dependency

See Sharing dependencies.

FAB-Include-Optional-Dependency

See Including optional dependencies.

FAB-Dependency-Require-Bundle

See Specifying OSGi Require-Bundle.

FAB-Exclude-Dependency

See Excluding dependencies.

Import-Package

See Customising import packages.

FAB-Skip-Matching-Feature-Detection

See Automatic feature detection.

FAB-Require-Feature-URL, FAB-Require-Feature

See Requiring features.

FAB-Install-Provided-Bundle-Dependencies

See Respecting pre-installed features and bundles.

Fuse ESB Enterprise comes with a collection of features that have been carefully crafted and manually adjusted so that they install exactly the right set of dependencies for a particular piece of functionality. For example, to install all of the required dependencies for the Apache Camel Jetty component, you can install the camel-jetty feature by entering the following console command:

karaf@root> features:install camel-jetty

If you want to use the Jetty component in a FAB, you would add the following Maven dependency to the FAB's POM:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-jetty</artifactId>
  <version>2.10.0.fuse-71-047</version>
  <scope>provided</scope>
</dependency>

If the camel-jetty feature is not already installed in the runtime, however, it is unlikely that the FAB mechanism would be able to install all of the required transitive dependencies successfully (after all, the camel-jetty feature was created in the first place precisely because it has third-party dependencies that are not well integrated with OSGi or FAB).

This is where automatic feature detection comes in. By default, whenever FAB encounters a Maven dependency that matches a known feature, it automatically maps the dependency to the corresponding feature and installs the feature instead. For example, when the FAB runtime encounters the org.apache.camel/camel-jetty Maven dependency, it automatically maps the dependency to the camel-jetty feature and installs the camel-jetty feature.

[Note]Note

Automatic feature detection is not yet available for all standard features. At the time of writing, auto-detection is supported for Apache Camel component features, camel-ComponentName, and some Apache CXF features, cxf, cxf-sts, and cxf-wsn.

Automatic feature detection is enabled by default. If you want to explicitly disable feature detection, you can set the FAB-Skip-Matching-Feature-Detection, specifying a space-separated list of artifact patterns. For example, to disable automatic feature detection for the Apache Camel components, add the following entry to the manifest:

FAB-Skip-Matching-Feature-Detection: org.apache.camel

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]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.

The default install behavior of a FAB is actually more complex than suggested by the all-private dependencies model (as shown in Figure 6.1). 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 6.4 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):


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).

When specifying the FAB's URL to the osgi:install command, you can combine fab: with any of the URL schemes supported by Fuse ESB Enterprise, which includes the following scheme types:

The properties used to configure a Standalone container's Maven URL handler are in the org.ops4j.pax.url.mvn PID. See Mvn URL Handler.

A fabric container will also have a profile assigned to it that contains the org.ops4j.pax.url.mvn PID. This PID should not be modified for purposes of configuring FAB dependency resolution. Instead, you should modify the fabric's Maven proxy as described in Configuring a Fabric's Maven Proxy in Configuring and Running Fuse ESB Enterprise.

In order to generate a project using an Fuse ESB Enterprise Maven archetype, you must have the following prerequisites:

This chapter describes how to build and package a WAR using Maven.

Note: Consider using FABs instead of WARs as your unit of deployment, because FABs are smaller (dependent JARs do not have to be packaged inside the FAB) and more flexible (you can optionally share specific dependencies as OSGi bundles).

It is possible to customize the Maven WAR plug-in by adding an entry to the plugins section of the pom.xml file. Most of the configuration options are concerned with adding additonal resources to the WAR package. For example, to include all of the resources under the src/main/resources directory (specified relative to the location of pom.xml) in the WAR package, you could add the following WAR plug-in configuration to your POM:

<project ...>
  ...
  <build>
    ...
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
    	<version>2.1.1</version>
        <configuration>
          <!-- Optionally specify where the web.xml file comes from -->
          <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
          <!-- Optionally specify extra resources to include -->
          <webResources>
            <resource>
              <directory>src/main/resources</directory>
              <targetPath>WEB-INF</targetPath>
              <includes>
                <include>**/*</include>
              </includes>
            </resource>
          </webResources>
        </configuration>
      </plugin>
      ...
    </plugins>
  </build>
</project>

The preceding plug-in configuration customizes the following settings:

For complete details of how to configure the Maven WAR plug-in, see http://maven.apache.org/plugins/maven-war-plugin/index.html.

[Note]Note

Do not use version 2.1 of the maven-war-plugin plug-in, which has a bug that causes two copies of the web.xml file to be inserted into the generated .war file.

The war scheme has the following basic syntax:

war:LocationURL[?Options]

The location URL, LocationURL, can be any of the location URLs described in Appendix A (for example, an mvn: or a file: URL). Options can be appended to the URL in the following format:

?Option=Value&Option=Value&...

Or if the war URL appears in an XML file:

?Option=Value&amp;Option=Value&amp;...

Support for running WARs in the OSGi container is provided by the PAX WAR Extender, which monitors each bundle as it starts and, if the bundle contains a web.xml file, automatically deploys the WAR in a Web container. The War Protocol page has the original reference documentation for the War URL handler.

Fuse ESB Enterprisehas the following layered architecture:

Figure 10.1 shows the architecture of Fuse ESB.


Fuse ESB is based on Apache Karaf, a powerful, lightweight, OSGi-based runtime container for deploying and managing bundles to facilitate componentization of applications. Fuse ESB also provides native OS integration and can be integrated into the operating system as a service so that the lifecycle is bound to the operating system.

As shown in Figure 10.1, Fuse ESB extends the OSGi layers with:

The OSGi Alliance is an independent organization responsible for defining the features and capabilities of the OSGi Service Platform Release 4. The OSGi Service Platform is a set of open specifications that simplify building, deploying, and managing complex software applications.

OSGi technology is often referred to as the dynamic module system for Java. OSGi is a framework for Java that uses bundles to modularly deploy Java components and handle dependencies, versioning, classpath control, and class loading. OSGi's lifecycle management allows you to load, start, and stop bundles without shutting down the JVM.

OSGi provides the best runtime platform for Java, a superior class loading architecture, and a registry for services. Bundles can export services, run processes, and have their dependencies managed. Each bundle can have its requirements managed by the OSGi container.

Fuse ESB uses Apache Felix as its default OSGi implementation. The framework layers form the container where you install bundles. The framework manages the installation and updating of bundles in a dynamic, scalable manner, and manages the dependencies between bundles and services.

As shown in Figure 10.1, the OSGi framework contains the following:

  • Bundles — Logical modules that make up an application. See OSGi Bundles.

  • Service layer — Provides communication among modules and their contained components. This layer is tightly integrated with the lifecycle layer. See OSGi Services.

  • Lifecycle layer — Provides access to the underlying OSGi framework. This layer handles the lifecycle of individual bundles so you can manage your application dynamically, including starting and stopping bundles.

  • Module layer — Provides an API to manage bundle packaging, dependency resolution, and class loading.

  • Execution environment — A configuration of a JVM. This environment uses profiles that define the environment in which bundles can work.

  • Security layer — Optional layer based on Java 2 security, with additional constraints and enhancements.

Each layer in the framework depends on the layer beneath it. For example, the lifecycle layer requires the module layer. The module layer can be used without the lifecycle and service layers.

In the OSGi framework, the service layer provides communication between bundles and their contained components using the publish, find, and bind service model. The service layer contains a service registry where:

  • Service providers register services with the framework to be used by other bundles

  • Service requesters find services and bind to service providers

Services are owned by, and run within, a bundle. The bundle registers an implementation of a service with the framework service registry under one or more Java interfaces. Thus, the service’s functionality is available to other bundles under the control of the framework, and other bundles can look up and use the service. Lookup is performed using the Java interface and service properties.

Each bundle can register multiple services in the service registry using the fully qualified name of its interface and its properties. Bundles use names and properties with LDAP syntax to query the service registry for services.

A bundle is responsible for runtime service dependency management activities including publication, discovery, and binding. Bundles can also adapt to changes resulting from the dynamic availability (arrival or departure) of the services that are bound to the bundle.

In addition to your own services, the OSGi framework provides the following optional services to manage the operation of the framework:

  • Package Admin service—allows a management agent to define the policy for managing Java package sharing by examining the status of the shared packages. It also allows the management agent to refresh packages and to stop and restart bundles as required. This service enables the management agent to make decisions regarding any shared packages when an exporting bundle is uninstalled or updated.

    The service also provides methods to refresh exported packages that were removed or updated since the last refresh, and to explicitly resolve specific bundles. This service can also trace dependencies between bundles at runtime, allowing you to see what bundles might be affected by upgrading.

  • Start Level service—enables a management agent to control the starting and stopping order of bundles. The service assigns each bundle a start level. The management agent can modify the start level of bundles and set the active start level of the framework, which starts and stops the appropriate bundles. Only bundles that have a start level less than, or equal to, this active start level can be active.

  • URL Handlers service—dynamically extends the Java runtime with URL schemes and content handlers enabling any component to provide additional URL handlers.

  • Permission Admin service—enables the OSGi framework management agent to administer the permissions of a specific bundle and to provide defaults for all bundles. A bundle can have a single set of permissions that are used to verify that it is authorized to execute privileged code. You can dynamically manipulate permissions by changing policies on the fly and by adding new policies for newly installed components. Policy files are used to control what bundles can do.

  • Conditional Permission Admin service—extends the Permission Admin service with permissions that can apply when certain conditions are either true or false at the time the permission is checked. These conditions determine the selection of the bundles to which the permissions apply. Permissions are activated immediately after they are set.

The OSGi framework services are described in detail in separate chapters in the OSGi Service Platform Release 4 specification available from the release 4 download page on the OSGi Alliance web site.

In addition to the OSGi framework services, the OSGi Alliance defines a set of optional, standardized compendium services. The OSGi compendium services provide APIs for tasks such as logging and preferences. These services are described in the OSGi Service Platform, Service Compendium available from the release 4 download page on the OSGi Alliance Web site.

The Configuration Admin compendium service is like a central hub that persists configuration information and distributes it to interested parties. The Configuration Admin service specifies the configuration information for deployed bundles and ensures that the bundles receive that data when they are active. The configuration data for a bundle is a list of name-value pairs. See Fuse ESB.

By default, the OSGi manifest's Export-Package list is populated by all of the packages in your local Java source code (under src/main/java), except for the deault package, ., and any packages containing .impl or .internal.

[Important]Important

If you use a Private-Package element in your plug-in configuration and you do not specify a list of packages to export, the default behavior includes only the packages listed in the Private-Package element in the bundle. No packages are exported.

The default behavior can result in very large packages and in exporting packages that should be kept private. To change the list of exported packages you can add an Export-Package child to the plug-in's instructions element.

The Export-Package element specifies a list of packages that are to be included in the bundle and that are to be exported. The package names can be specified using the * wildcard symbol. For example, the entry com.fuse.demo.* includes all packages on the project's classpath that start with com.fuse.demo.

You can specify packages to be excluded be prefixing the entry with !. For example, the entry !com.fuse.demo.private excludes the package com.fuse.demo.private.

When excluding packages, the order of entries in the list is important. The list is processed in order from the beginning and any subsequent contradicting entries are ignored.

For example, to include all packages starting with com.fuse.demo except the package com.fuse.demo.private, list the packages using:

!com.fuse.demo.private,com.fuse.demo.*

However, if you list the packages using com.fuse.demo.*,!com.fuse.demo.private, then com.fuse.demo.private is included in the bundle because it matches the first pattern.

Applications in an OSGi environment are subject to the lifecycle of its bundles. Bundles have six lifecycle states:

  1. Installed — All bundles start in the installed state. Bundles in the installed state are waiting for all of their dependencies to be resolved, and once they are resolved, bundles move to the resolved state.

  2. Resolved — Bundles are moved to the resolved state when the following conditions are met:

    • The runtime environment meets or exceeds the environment specified by the bundle.

    • All of the packages imported by the bundle are exposed by bundles that are either in the resolved state or that can be moved into the resolved state at the same time as the current bundle.

    • All of the required bundles are either in the resolved state or they can be resolved at the same time as the current bundle.

    [Important]Important

    All of an application's bundles must be in the resolved state before the application can be started.

    If any of the above conditions ceases to be satisfied, the bundle is moved back into the installed state. For example, this can happen when a bundle that contains an imported package is removed from the container.

  3. Starting — The starting state is a transitory state between the resolved state and the active state. When a bundle is started, the container must create the resources for the bundle. The container also calls the start() method of the bundle's bundle activator when one is provided.

  4. Active — Bundles in the active state are available to do work. What a bundle does in the active state depends on the contents of the bundle. For example, a bundle containing a JAX-WS service provider indicates that the service is available to accept requests.

  5. Stopping — The stopping state is a transitory state between the active state and the resolved state. When a bundle is stopped, the container must clean up the resources for the bundle. The container also calls the stop() method of the bundle's bundle activator when one is provided.

  6. Uninstalled — When a bundle is uninstalled it is moved from the resolved state to the uninstalled state. A bundle in this state cannot be transitioned back into the resolved state or any other state. It must be explicitly re-installed.

The most important lifecycle states for application developers are the starting state and the stopping state. The endpoints exposed by an application are published during the starting state. The published endpoints are stopped during the stopping state.

If all of the required features and bundles are already installed and you are still getting a ClassNotFound error, this means that the Import-Package header in your bundle's MANIFEST.MF file is incomplete. The maven-bundle-plugin (see Modifying an Existing Maven Project) is a great help when it comes to generating your bundle's Import-Package header, but you should note the following points:

  • Make sure that you include the wildcard, *, in the Import-Package element of the Maven bundle plug-in configuration. The wildcard directs the plug-in to scan your Java source code and automatically generates a list of package dependencies.

  • The Maven bundle plug-in is not able to figure out dynamic dependencies. For example, if your Java code explicitly calls a class loader to load a class dynamically, the bundle plug-in does not take this into account and the required Java package will not be listed in the generated Import-Package header.

  • If you define a Spring XML file (for example, in the META-INF/spring directory), the Maven bundle plug-in is not able to figure out dependencies arising from the Spring XML configuration. Any dependencies arising from Spring XML must be added manually to the bundle plug-in's Import-Package element.

  • If you define a blueprint XML file (for example, in the OSGI-INF/blueprint directory), any dependencies arising from the blueprint XML file are automatically resolved at run time. This is an important advantage of blueprint over Spring.

To track down missing dependencies, perform the following steps:

  1. Perform a quick check to ensure that all of the required bundles and features are actually installed in the OSGi container. You can use osgi:list to check which bundles are installed and features:list to check which features are installed.

  2. Install (but do not start) your bundle, using the osgi:install console command. For example:

    karaf@root> osgi:install MyBundleURL
  3. Use the dev:dynamic-import console command to enable dynamic imports on the bundle you just installed. For example, if the bundle ID of your bundle is 218, you would enable dynamic imports on this bundle by entering the following command:

    karaf@root> dev:dynamic-import 218

    This setting allows OSGi to resolve dependencies using any of the bundles already installed in the container, effectively bypassing the usual dependency resolution mechanism (based on the Import-Package header). This is not recommemded for normal deployment, because it bypasses version checks: you could easily pick up the wrong version of a package, causing your application to malfunction.

  4. You should now be able to resolve your bundle. For example, if your bundle ID is 218, enter the followng console command:

    karaf@root> osgi:resolve 218
  5. Assuming your bundle is now resolved (check the bundle status using osgi:list), you can get a complete list of all the packages wired to your bundle using the package:imports command. For example, if your bundle ID is 218, enter the following console command:

    karaf@root> package:imports 218

    You should see a list of dependent packages in the console window (where the package names are highlighted in this example):

    Spring Beans (67): org.springframework.beans.factory.xml; version=3.0.5.RELEASE
    Apache ServiceMix :: Specs :: JAXB API 2.2 (87): javax.xml.bind.annotation; version=2.2.1
    Apache ServiceMix :: Specs :: JAXB API 2.2 (87): javax.xml.bind; version=2.2.1
    Web Services Metadata 2.0 (104): javax.jws; version=2.0.0
    Apache ServiceMix :: Specs :: JAXWS API 2.2 (105): javax.xml.ws.handler; version=2.2.0
    Apache ServiceMix :: Specs :: JAXWS API 2.2 (105): javax.xml.ws; version=2.2.0
    Apache CXF Bundle Jar (125): org.apache.cxf.helpers; version=2.4.2.fuse-00-08
    Apache CXF Bundle Jar (125): org.apache.cxf.transport.jms.wsdl11; version=2.4.2.fuse-00-08
    ...
  6. Unpack your bundle JAR file and look at the packages listed under the Import-Package header in the META-INF/MANIFEST.MF file. Compare this list with the list of packages found in the previous step. Now, compile a list of the packages that are missing from the manifest's Import-Package header and add these package names to the Import-Package element of the Maven bundle plug-in configuration in your project's POM file.

  7. To cancel the dynamic import option, you must uninstall the old bundle from the OSGi container. For example, if your bundle ID is 218, enter the following command:

    karaf@root> osgi:uninstall 218
  8. You can now rebuild your bundle with the updated list of imported packages and test it in the OSGi container.

To add a feature to the custom feature repository, insert a new feature element as a child of the root features element. You must give the feature a name and you can list any number of bundles belonging to the feature, by inserting bundle child elements. For example, to add a feature named example-camel-bundle containing the single bundle, C:\Projects\camel-bundle\target\camel-bundle-1.0-SNAPSHOT.jar, add a feature element as follows:

<?xml version="1.0" encoding="UTF-8"?>
<features name="MyFeaturesRepo">
  <feature name="example-camel-bundle">
    <bundle>file:C:/Projects/camel-bundle/target/camel-bundle-1.0-SNAPSHOT.jar</bundle>
  </feature>
</features>

The contents of the bundle element can be any valid URL, giving the location of a bundle (see Appendix A). You can optionally specify a version attribute on the feature element, to assign a non-zero version to the feature (you can then specify the version as an optional argument to the features:install command).

To check whether the features service successfully parses the new feature entry, enter the following pair of console commands:

karaf@root> features:refreshUrl
karaf@root> features:list
...
[uninstalled] [0.0.0                 ] example-camel-bundle                 MyFeaturesRepo
...

The features:list command typically produces a rather long listing of features, but you should be able to find the entry for your new feature (in this case, example-camel-bundle) by scrolling back through the listing. The features:refreshUrl command forces the kernel to reread all the feature repositories: if you did not issue this command, the kernel would not be aware of any recent changes that you made to any of the repositories (in particular, the new feature would not appear in the listing).

To avoid scrolling through the long list of features, you can grep for the example-camel-bundle feature as follows:

karaf@root> features:list | grep example-camel-bundle
[uninstalled] [0.0.0                 ] example-camel-bundle                 MyFeaturesRepo

Where the grep command (a standard UNIX pattern matching utility) is built into the shell, so this command also works on Windows platforms.

In order to make the new feature repository available to Apache Karaf, you must add the feature repository using the features:addUrl console command. For example, to make the contents of the repository, C:\Projects\features.xml, available to the kernel, you would enter the following console command:

features:addUrl file:C:/Projects/features.xml

Where the argument to features:addUrl can be specified using any of the supported URL formats (see Appendix A).

You can check that the repository's URL is registered correctly by entering the features:listUrl console command, to get a complete listing of all registered feature repository URLs, as follows:

karaf@root> features:listUrl
mvn:org.apache.servicemix.nmr/apache-servicemix-nmr/1.1.0-fuse-01-00/xml/features
mvn:org.apache.servicemix.camel/features/7.1.0.fuse-047/xml/features
file:C:/Projects/features.xml
mvn:org.apache.ode/ode-jbi-karaf/1.3.3-fuse-01-00/xml/features
mvn:org.apache.felix.karaf/apache-felix-karaf/1.2.0-fuse-01-00/xml/features
mvn:org.apache.servicemix/apache-servicemix/7.1.0.fuse-047/xml/features

If your application uses the OSGi Configuration Admin service, you can specify configuration settings for this service using the config child element of your feature definition. For example, to specify that the prefix property has the value, MyTransform, add the following config child element to your feature's configuration:

<?xml version="1.0" encoding="UTF-8"?>
<features name="MyFeaturesRepo">
  <feature name="example-camel-bundle">
    <config name="org.fusesource.fuseesb.example">
      prefix=MyTransform
    </config>
  </feature>
</features>

Where the name attribute of the config element specifies the persistent ID of the property settings (where the persistent ID acts effectively as a name scope for the property names). The content of the config element is parsed in the same way as a Java properties file.

The settings in the config element can optionally be overriden by the settings in the Java properties file located in the InstallDir/etc directory, which is named after the persistent ID, as follows:

InstallDir/etc/org.fusesource.fuseesb.example.cfg

As an example of how the preceding configuration properties can be used in practice, consider the following Spring XML file that accesses the OSGi configuration properties using Spring DM:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:ctx="http://www.springframework.org/schema/context"
       xmlns:osgi="http://camel.apache.org/schema/osgi"
       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium" ...>
    ...
    <bean id="myTransform" class="org.fusesource.fuseesb.example.MyTransform">
      <property name="prefix" value="${prefix}"/>
    </bean>
   
    <osgix:cm-properties id="preProps" persistent-id="org.fusesource.fuseesb.example">
        <prop key="prefix">DefaultValue</prop>
    </osgix:cm-properties>

    <ctx:property-placeholder properties-ref="preProps" />

</beans>

When this Spring XML file is deployed in the example-camel-bundle bundle, the property reference, ${prefix}, is replaced by the value, MyTransform, which is specified by the config element in the feature repository.

To uninstall a feature, invoke the features:uninstall command as follows:

karaf@root> features:uninstall example-camel-bundle
[Note]Note

After uninstalling, the feature will still be visible when you invoke features:list, but its status will now be flagged as [uninstalled].

If you want to provision copies of the Apache Karaf for deployment on multiple hosts, you might be interested in adding a feature to the boot configuration, which determines the collection of features that are installed when Apache Karaf boots up for the very first time.

The configuration file, /etc/org.apache.felix.karaf.features.cfg, in your install directory contains the following settings:

This configuration file has two properties:

You can modify the configuration to customize the features that are installed as Fuse ESB starts up. You can also modify this configuration file, if you plan to distribute Fuse ESB with pre-installed features.

[Important]Important

This method of adding a feature is only effective the first time a particular Apache Karaf instance boots up. Any changes made subsequently to the featuresRepositories setting and the featuresBoot setting are ignored, even if you restart the Apache Karaf.

You could force the Apache Karaf instance to revert back to its initial state, however, by deleting the complete contents of the InstallDir/data/cache (thereby losing all of the Apache Karaf instance's custom settings).

The Bnd tool is a an open source utility for creating and diagnosing OSGi bundles. It has been developed by Peter Kriens and is freely downloadable from the aQute Web site (subject to an Apache version 2.0 open source license). The key feature of the Bnd tool is that it automatically generates Manifest headers for the OSGi bundle, thus relieving you of this tedious task. The main tasks that Bnd can perform are:

  • Print the manifiest and show the package dependencies of a JAR file or bundle file.

  • Wrap a vanilla JAR file, converting it into a bundle.

  • Build a bundle from the class path, based on specifications in a .bnd file.

  • Validate manifest entries.

You have the option of invoking Bnd in any of the following ways: from the command line; as an Ant task; or through the Maven bundle plug-in, maven-bundle-plugin. In fact, the approach to building bundles described in Building with Maven is based on the Maven bundle plug-in and therefore, implicitly, is also based on the Bnd tool.

To demonstrate how to convert a plain JAR into a bundle, we will consider the example of the commons-logging-Version.jar, which is available from the Apache Commons project and can be downloaded from the following location:

http://commons.apache.org/downloads/download_logging.cgi
[Note]Note

Actually, this is a rather artificial example, because the Apache Commons logging API is not intended to be deployed as an OSGi bundle (which is why it does not have the requisite Manifest headers in the first place). Most of the other JARs from Apache Commons are already provided as bundles.

The Bnd print command is a useful diagnostic tool that displays most of the information about a JAR that is relevant to bundle creation. For example, to print the Manifest headers and package dependencies of the commons logging JAR, you can invoke the Bnd print command as follows:

java -jar bnd.jar print commons-logging-1.1.1.jar

The preceding command produces the following output:

From this output, you can see that the JAR does not define any bundle manifest headers. The output consists of the following sections:

To display the Manifest headers and package dependencies of the newly created bundle JAR, enter the following Bnd print command:

java -jar bnd.jar print commons-logging-1.1.1.bar

The preceding command should produce output like the following:

[MANIFEST commons-logging-1.1.1-bnd.jar]
Archiver-Version                        Plexus Archiver
Bnd-LastModified                        1263987809524
Build-Jdk                               1.4.2_16
Built-By                                dlg01
Bundle-ManifestVersion                  2
Bundle-Name                             commons-logging-1.1.1
Bundle-SymbolicName                     commons-logging-1.1.1
Bundle-Version                          0
Created-By                              1.5.0_08 (Sun Microsystems Inc.)
Export-Package                          org.apache.commons.logging;uses:="org.ap
ache.commons.logging.impl",org.apache.commons.logging.impl;uses:="org.apache.ava
lon.framework.logger,org.apache.commons.logging,org.apache.log4j,org.apache.log,
javax.servlet"
Extension-Name                          org.apache.commons.logging
Implementation-Title                    Commons Logging
Implementation-Vendor                   Apache Software Foundation
Implementation-Vendor-Id                org.apache
Implementation-Version                  1.1.1
Import-Package                          javax.servlet;resolution:=optional,org.a
pache.avalon.framework.logger;resolution:=optional,org.apache.commons.logging;re
solution:=optional,org.apache.commons.logging.impl;resolution:=optional,org.apac
he.log;resolution:=optional,org.apache.log4j;resolution:=optional
Manifest-Version                        1.0
Originally-Created-By                   Apache Maven
Specification-Title                     Commons Logging
Specification-Vendor                    Apache Software Foundation
Specification-Version                   1.0
Tool                                    Bnd-0.0.384
X-Compile-Source-JDK                    1.2
X-Compile-Target-JDK                    1.1


[IMPEXP]
Import-Package
  javax.servlet                         {resolution:=optional}
  org.apache.avalon.framework.logger    {resolution:=optional}
  org.apache.log                        {resolution:=optional}
  org.apache.log4j                      {resolution:=optional}
Export-Package
  org.apache.commons.logging
  org.apache.commons.logging.impl

[USES]
org.apache.commons.logging              org.apache.commons.logging.impl
org.apache.commons.logging.impl         javax.servlet
                                        org.apache.avalon.framework.logger
                                        org.apache.commons.logging
                                        org.apache.log
                                        org.apache.log4j

If you want to have more control over the way the Bnd wrap command generates a bundle, you can define a Bnd properties file to control the conversion process. For a detailed description of the syntax and capabilities of the Bnd properties file, see the Bnd tool documentation.

For example, in the case of the commons logging JAR, you might decide to hide the org.apache.commons.logging.impl package, while exporting the org.apache.commons.logging package. You could do this by creating a Bnd properties file called commons-logging-1.1.1.bnd and inserting the following lines using a text editor:

version=1.1.1
Export-Package: org.apache.commons.logging;version=${version}
Private-Package: org.apache.commons.logging.impl
Bundle-Version: ${version}

Notice how a version number is assigned to the exported package by substituting the version variable (any properties starting with a lowercase letter are interpreted as variables).

The wrap scheme has the following basic syntax:

wrap:LocationURL

The wrap scheme can prefix any URL that locates a JAR. The locating part of the URL, LocationURL, is used to obtain the (non-bundlized) JAR and the URL handler for the wrap scheme then converts the JAR automatically into a bundle.

[Note]Note

The wrap scheme also supports a more elaborate syntax, which enables you to customize the conversion by specifying a Bnd properties file or by specifying individual Bnd properties in the URL. Typically, however, the wrap scheme is used just with its default settings.

The wrap scheme is provided by the Pax project, which is the umbrella project for a variety of open source OSGi utilities. For full documentation on the wrap scheme, see the Wrap Protocol reference page.

In order to generate a project using an Fuse ESB Enterprise Maven archetype, you must have the following prerequisites:

To install and run the generated camel-bundle project, perform the following steps:

  1. Build the project—open a command prompt and change directory to ProjectDir/camel-bundle. Use Maven to build the demonstration by entering the following command:

    mvn install

    If this command runs successfully, the ProjectDir/camel-bundle/target directory should contain the bundle file, camel-bundle-1.0-SNAPSHOT.jar and the bundle will also be installed in the local Maven repository.

  2. Install prerequisite features (optional)—by default, the camel-core feature and some related features are pre-installed in the OSGi container. But many of the Apache Camel components are not installed by default. To check which features are available and whether or not they are installed, enter the following console command:

    karaf@root> features:list

    Apache Camel features are identifiable by the camel- prefix. For example, if one of your routes requires the HTTP component, you can make sure that it is installed in the OSGi container by issuing the following console command:

    karaf@root> features:install camel-http
  3. Install and start the camel-bundle bundle—at the Fuse ESB Enterprise console, enter the following command:

    karaf@root> osgi:install -s file:ProjectDir/camel-bundle/target/camel-bundle-1.0-SNAPSHOT.jar

    Where ProjectDir is the directory containing your Maven projects and the -s flag directs the container to start the bundle right away. For example, if your project directory is C:\Projects on a Windows machine, you would enter the following command:

    karaf@root> osgi:install -s file:C:/Projects/camel-bundle/target/camel-bundle-1.0-SNAPSHOT.jar

    Alternatively, you could install the bundle from the local Maven repository using an Mvn URL (see Mvn URL Handler) as follows:

    karaf@root> osgi:install -s mvn:org.fusesource.example/camel-bundle

    After entering this command, you should soon see output like the following being logged to the console screen:

    >>>> MyTransform set body:  Mon Sep 22 11:43:42 BST 2008
    >>>> MyTransform set body:  Mon Sep 22 11:43:44 BST 2008
    >>>> MyTransform set body:  Mon Sep 22 11:43:46 BST 2008
    [Note]Note

    On Windows machines, be careful how you format the file URL—for details of the syntax understood by the file URL handler, see File URL Handler.

  4. Stop the camel-bundle bundle—to stop the camel-bundle bundle, you first need to discover the relevant bundle number. To find the bundle number, enter the following console command (this might look a bit confusing, because the text you are typing will intermingle with the output that is being logged to the screen):

    karaf@root> osgi:list

    At the end of the listing, you should see an entry like the following:

    [ 189] [Active     ] [            ] [       ] [   60] A Camel OSGi Service Unit (1.0.0.SNAPSHOT)

    Where, in this example, the bundle number is 189. To stop this bundle, enter the following console command:

    karaf@root> osgi:stop 189

In order to generate a project using a Fuse ESB Enterprise Maven archetype, you must have the following prerequisites:

To install and run the generated cxf-code-first-bundle project, perform the following steps:

  1. Build the project—open a command prompt and change directory to ProjectDir/cxf-code-first-bundle. Use Maven to build the demonstration by entering the following command:

    mvn install

    If this command runs successfully, the ProjectDir/cxf-code-first-bundle/target directory should contain the bundle file, cxf-code-first-bundle-1.0-SNAPSHOT.jar.

  2. Install and start the cxf-code-first-bundle bundle—at the Fuse ESB Enterprise console, enter the following command:

    karaf@root> osgi:install -s file:ProjectDir/cxf-code-first-bundle/target/cxf-code-first-bundle-1.0-SNAPSHOT.jar

    Where ProjectDir is the directory containing your Maven projects and the -s flag directs the container to start the bundle right away. For example, if your project directory is C:\Projects on a Windows machine, you would enter the following command:

    karaf@root> osgi:install -s file:C:/Projects/cxf-code-first-bundle/target/cxf-code-first-bundle-1.0-SNAPSHOT.jar
    [Note]Note

    On Windows machines, be careful how you format the file URL—for details of the syntax understood by the file URL handler, see File URL Handler.

    Alternatively, you could install the bundle from your local Maven repository, using the following PAX mvn URL:

    karaf@root> osgi:install -s mvn:org.fusesource.example/cxf-code-first-bundle/1.0-SNAPSHOT
  3. Test the Web serivce—to test the Web service deployed in the previous step, you can use a web browser to query the service's WSDL. Open your favorite web browser and navigate to the following URL:

    http://localhost:8181/cxf/PersonServiceCF?wsdl

    When the web service receives the query, ?wsdl, it returns a WSDL description of the running service.

  4. Stop the cxf-code-first-bundle bundle—to stop the cxf-code-first-bundle bundle, you first need to discover the relevant bundle number. To find the bundle number, enter the following console command:

    karaf@root> osgi:list

    At the end of the listing, you should see an entry like the following:

    [ 191] [Active     ] [            ] [       ] [   60] A CXF Code First OSGi Project (1.0.0.SNAPSHOT)

    Where, in this example, the bundle number is 191. To stop this bundle, enter the following console command:

    karaf@root> osgi:stop 191

Dependencies on an OSGi service are mandatory by default (although this can be changed by setting the availability attribute to optional on a reference element or a reference-list element). Declaring a dependency to be mandatory means that the bundle cannot function properly without that dependency and the dependency must be available at all times.

Normally, while a blueprint container is initializing, it passes through a grace period, during which time it attempts to resolve all mandatory dependencies. If the mandatory dependencies cannot be resolved in this time (the default timeout is 5 minutes), container initialization is aborted and the bundle is not started. The following settings can be appended to the Bundle-SymbolicName manifest header to configure the grace period:

For example, to enable a grace period of 10 seconds, you could define the following Bundle-SymbolicName header in the manifest file:

Bundle-SymbolicName: org.fusesource.example.osgi-client;
 blueprint.graceperiod:=true;
 blueprint.timeout:= 10000

The value of the Bundle-SymbolicName header is a semi-colon separated list, where the first item is the actual bundle symbolic name, the second item, blueprint.graceperiod:=true, enables the grace period and the third item, blueprint.timeout:= 10000, specifies a 10 second timeout.

If you want to keep track of service registration and unregistration events, you can define a registration listener callback bean that receives registration and unregistration event notifications. To define a registration listener, add a registration-listener child element to a service element.

For example, the following blueprint configuration defines a listener bean, listenerBean, which is referenced by a registration-listener element, so that the listener bean receives callbacks whenever an Account service is registered or unregistered:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" ...>
  ...
  <bean id="listenerBean" class="org.fusesource.example.Listener"/>

  <service ref="savings" auto-export="interfaces">
    <registration-listener
        ref="listenerBean"
        registration-method="register"
        unregistration-method="unregister"/>
  </service>
  ...
</blueprint>

Where the registration-listener element's ref attribute references the id of the listener bean, the registration-method attribute specifies the name of the listener method that receives the registration callback, and unregistration-method attribute specifies the name of the listener method that receives the unregistration callback.

The following Java code shows a sample definition of the Listener class that receives notifications of registration and unregistration events:

// Java
package org.fusesource.example;

public class Listener
{
    public void register(Account service, java.util.Map serviceProperties) {
        ...
    }

    public void unregister(Account service, java.util.Map serviceProperties) {
        ...
    }
}

The method names, register and unregister, are specified by the registration-method and unregistration-method attributes respectively. The signatures of these methods must conform to the following syntax:

A reference manager instance is created by the blueprint reference element. This element returns a single service reference and is the preferred approach for accessing stateless services. Figure 16.1 shows an overview of the model for accessing a stateless service using the reference manager.


Beans in the client blueprint container get injected with a proxy object (the provided object), which is backed by a service object (the backing service) from the OSGi service registry. This model explicitly takes advantage of the fact that stateless services are interchangeable, in the following ways:

  • If multiple services instances are found that match the criteria in the reference element, the reference manager can arbitrarily choose one of them as the backing instance (because they are interchangeable).

  • If the backing service disappears, the reference manager can immediately switch to using one of the other available services of the same type. Hence, there is no guarantee, from one method invocation to the next, that the proxy remains connected to the same backing service.

The contract between the client and the backing service is thus stateless, and the client must not assume that it is always talking to the same service instance. If no matching service instances are available, the proxy will wait for a certain length of time before throwing the ServiceUnavailable exception. The length of the timeout is configurable by setting the timeout attribute on the reference element.

The simplest way to obtain a stateles service reference is by specifying the interface to match, using the interface attribute on the reference element. The service is deemed to match, if the interface attribute value is a super-type of the service or if the attribute value is a Java interface implemented by the service (the interface attribute can specify either a Java class or a Java interface).

For example, to reference a stateless SavingsAccount service (see Example 16.1), define a reference element as follows:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  
  <reference id="savingsRef"
             interface="org.fusesource.example.SavingsAccount"/>

  <bean id="client" class="org.fusesource.example.client.Client">
    <property name="savingsAccount" ref="savingsRef"/>
  </bean>

</blueprint>

Where the reference element creates a reference manager bean with the ID, savingsRef. To use the referenced service, inject the savingsRef bean into one of your client classes, as shown.

The bean property injected into the client class can be any type that is assignable from SavingsAccount. For example, you could define the Client class as follows:

package org.fusesource.example.client;

import org.fusesource.example.SavingsAccount;

public class Client {
    SavingsAccount savingsAccount;
    
    // Bean properties
    public SavingsAccount getSavingsAccount() {
        return savingsAccount;
    }

    public void setSavingsAccount(SavingsAccount savingsAccount) {
        this.savingsAccount = savingsAccount;
    }
    ...
}

The simplest way to obtain a stateful service reference is by specifying the interface to match, using the interface attribute on the reference-list element. The reference list manager then obtains a list of all the services, whose interface attribute value is either a super-type of the service or a Java interface implemented by the service (the interface attribute can specify either a Java class or a Java interface).

For example, to reference a stateful SavingsAccount service (see Example 16.1), define a reference-list element as follows:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  
  <reference-list id="savingsListRef"
                  interface="org.fusesource.example.SavingsAccount"/>

  <bean id="client" class="org.fusesource.example.client.Client">
    <property name="savingsAccountList" ref="savingsListRef"/>
  </bean>

</blueprint>

Where the reference-list element creates a reference list manager bean with the ID, savingsListRef. To use the referenced service list, inject the savingsListRef bean reference into one of your client classes, as shown.

By default, the savingsAccountList bean property is a list of service objects (for example, java.util.List<SavingsAccount>). You could define the client class as follows:

package org.fusesource.example.client;

import org.fusesource.example.SavingsAccount;

public class Client {
    java.util.List<SavingsAccount> accountList;
    
    // Bean properties
    public java.util.List<SavingsAccount> getSavingsAccountList() {
        return accountList;
    }

    public void setSavingsAccountList(
                    java.util.List<SavingsAccount> accountList
    ) {
        this.accountList = accountList;
    }
    ...
}

You can select services by matching service properties against a filter. The filter is specified using the filter attribute on the reference element or on the reference-list element. The value of the filter attribute must be an LDAP filter expression. For example, to define a filter that matches when the bank.name service property equals HighStreetBank, you could use the following LDAP filter expression:

(bank.name=HighStreetBank)

To match two service property values, you can use & conjunction, which combines expressions with a logical and.For example, to require that the foo property is equal to FooValue and the bar property is equal to BarValue, you could use the following LDAP filter expression:

(&(foo=FooValue)(bar=BarValue))

For the complete syntax of LDAP filter expressions, see section 3.2.7 of the OSGi Core Specification.

Filters can also be combined with the interface and component-name settings, in which case all of the specified conditions are required to match.

For example, to match a stateless service of SavingsAccount type, with a bank.name service property equal to HighStreetBank, you could define a reference element as follows:

<reference id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           filter="(bank.name=HighStreetBank)"/>

To match a stateful service of SavingsAccount type, with a bank.name service property equal to HighStreetBank, you could define a reference-list element as follows:

<reference-list id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           filter="(bank.name=HighStreetBank)"/>

By default, a reference to an OSGi service is assumed to be mandatory (see Mandatory dependencies). It is possible, however, to customize the dependency behavior of a reference element or a reference-list element by setting the availability attribute on the element. There are two possible values of the availability attribute: mandatory (the default), means that the dependency must be resolved during a normal blueprint container initialization; and optional, means that the dependency need not be resolved during initialization.

The following example of a reference element shows how to declare explicitly that the reference is a mandatory dependency:

<reference id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           availability="mandatory"/>

To cope with the dynamic nature of the OSGi environment—for example, if you have declared some of your service references to have optional availability—it is often useful to track when a backing service gets bound to the registry and when it gets unbound from the registry. To receive notifications of service binding and unbinding events, you can define a reference-listener element as the child of either the reference element or the reference-list element.

For example, the following blueprint configuration shows how to define a reference listener as a child of the reference manager with the ID, savingsRef:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  
  <reference id="savingsRef"
             interface="org.fusesource.example.SavingsAccount"
             >
    <reference-listener bind-method="onBind" unbind-method="onUnbind">
      <bean class="org.fusesource.example.client.Listener"/>
    </reference-listener>
  </reference>

  <bean id="client" class="org.fusesource.example.client.Client">
    <property name="savingsAcc" ref="savingsRef"/>
  </bean>

</blueprint>

The preceding configuration registers an instance of org.fusesource.example.client.Listener type as a callback that listens for bind and unbind events. Events are generated whenever the savingsRef reference manager's backing service binds or unbinds.

The following example shows a sample implementation of the Listener class:

package org.fusesource.example.client;

import org.osgi.framework.ServiceReference;

public class Listener {
    
    public void onBind(ServiceReference ref) {
        System.out.println("Bound service: " + ref);
    }
    
    public void onUnbind(ServiceReference ref) {
        System.out.println("Unbound service: " + ref);
    }
    
}

The method names, onBind and onUnbind, are specified by the bind-method and unbind-method attributes respectively. Both of these callback methods take an org.osgi.framework.ServiceReference argument.

In order to generate a project using the Maven Quickstart archetype, you must have the following prerequisites:

You must customize the POM file in order to generate an OSGi bundle, as follows:

  1. Follow the POM customization steps described in Generating a Bundle Project.

  2. In the configuration of the Maven bundle plug-in, modify the bundle instructions to export the org.fusesource.example.service package, as follows:

    <project ... >
      ...
      <build>
        ...
        <plugins>
          ...
          <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
              <instructions>
                <Bundle-SymbolicName>${pom.groupId}.${pom.artifactId}</Bundle-SymbolicName>
            	    <Export-Package>org.fusesource.example.service</Export-Package>
              </instructions>
            </configuration>
          </plugin>
        </plugins>
      </build>
      ...
    </project>

To install and run the osgi-service project, perform the following steps:

  1. Build the project—open a command prompt and change directory to ProjectDir/osgi-service. Use Maven to build the demonstration by entering the following command:

    mvn install

    If this command runs successfully, the ProjectDir/osgi-service/target directory should contain the bundle file, osgi-service-1.0-SNAPSHOT.jar.

  2. Install and start the osgi-service bundle—at the Fuse ESB Enterprise console, enter the following command:

    karaf@root> osgi:install -s file:ProjectDir/osgi-service/target/osgi-service-1.0-SNAPSHOT.jar

    Where ProjectDir is the directory containing your Maven projects and the -s flag directs the container to start the bundle right away. For example, if your project directory is C:\Projects on a Windows machine, you would enter the following command:

    karaf@root> osgi:install -s file:C:/Projects/osgi-service/target/osgi-service-1.0-SNAPSHOT.jar
    [Note]Note

    On Windows machines, be careful how you format the file URL—for details of the syntax understood by the file URL handler, see File URL Handler.

  3. Check that the service has been created—to check that the bundle has started successfully, enter the following Fuse ESB Enterprise console command:

    karaf@root> osgi:list

    Somewhere in this listing, you should see a line for the osgi-service bundle, for example:

    [ 236] [Active     ] [Created     ] [       ] [   60] osgi-service (1.0.0.SNAPSHOT)

    To check that the service is registered in the OSGi service registry, enter a console command like the following:

    karaf@root> osgi:ls 236

    Where the argument to the preceding command is the osgi-service bundle ID. You should see some output like the following at the console:

    osgi-service (236) provides:
    ----------------------------
    osgi.service.blueprint.compname = hello
    objectClass = org.fusesource.example.service.HelloWorldSvc
    service.id = 272
    ----
    osgi.blueprint.container.version = 1.0.0.SNAPSHOT
    osgi.blueprint.container.symbolicname = org.fusesource.example.osgi-service
    objectClass = org.osgi.service.blueprint.container.BlueprintContainer
    service.id = 273

In order to generate a project using the Maven Quickstart archetype, you must have the following prerequisites:

You must customize the POM file in order to generate an OSGi bundle, as follows:

  1. Follow the POM customization steps described in Generating a Bundle Project.

  2. Because the client uses the HelloWorldSvc Java interface, which is defined in the osgi-service bundle, it is necessary to add a Maven dependency on the osgi-service bundle. Assuming that the Maven coordinates of the osgi-service bundle are org.fusesource.example:osgi-service:1.0-SNAPSHOT, you should add the following dependency to the client's POM file:

    <project ... >
      ...
      <dependencies>
        ...
        <dependency>
            <groupId>org.fusesource.example</groupId>
            <artifactId>osgi-service</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
      </dependencies>
      ...
    </project>

In order to run the sample router application, you need to have the camel-activemq feature installed in the OSGi container. The camel-activemq component is needed for defining Apache ActiveMQ-based JMS endpoints in Apache Camel. This feature is not installed by default, so you must install it using the following console command:

karaf@root> features:install camel-activemq

You also need the activemq feature, but this feature is normally available, because Fuse ESB Enterprise installs it by default.

[Tip]Tip

Most of the Apache Camel components are not installed by default. Whenever you are about to define an endpoint in a Apache Camel route, remember to check whether the corresponding component feature is installed. Apache Camel component features generally have the same name as the corresponding Apache Camel component artifact ID, camel-ComponentName.

Example 17.3 gives an example of a Apache Camel route defined using the Spring XML DSL. Messages generated by the timer endpoint are propagated through the JMS broker and then written out to the file system.


Example 17.3 defines two routes, as follows:

  1. The first route uses a timer endpoint to generate messages at four-second intervals. The setBody element places a dummy string in the body of the message (which would otherwise be null). The messages are then sent to the camel.timer queue on the broker (the activemq:camel.timer endpoint).

    [Note]Note

    The activemq scheme in activemq:camel.timer is resolved by looking up activemq in the bean registry, which resolves to the locally instantiated bean with ID, activemq.

  2. The second route pulls messages off the camel.timer queue and then writes the messages to the specified directory, C:\temp\sandpit\timer, in the file system.

To run the sample router application, perform the following steps:

  1. Using your favorite text editor, copy and paste the router configuration from Example 17.3 into a file called camel-timer.xml.

    Edit the file endpoint in the second route, in order to change the target directory to a suitable location on your file system:

        <route>
          <from uri="activemq:camel.timer"/>
          <to uri="file:YourDirectoryHere!"/>
        </route>
  2. Start up a local instance of the Fuse ESB Enterprise runtime by entering the following at a command prompt:

    servicemix
  3. Make sure the requisite features are installed in the OSGi container. To install the camel-activemq feature, enter the following command at the console:

    karaf@root> features:install camel-activemq

    To ensure that the activemq-broker feature is not installed, enter the following command at the console:

    karaf@root> features:uninstall activemq-broker
  4. Use one of the following alternatives to obtain a broker instance for this demonstration:

    • Use the default broker—assuming you have not disabled the default broker, you can use it for this demonstration, because it is listening on the correct port, 61616.

    • Create a new broker instance using the console—if you prefer not to use the default broker, you can disable it (as described in Working with the Default Broker) and then create a new JMS broker instance by entering the following command at the console:

      karaf@root> activemq:create-broker --name test

      After executing this command, you should see the broker configuration file, test-broker.xml, in the InstallDir/deploy directory.

  5. Hot deploy the router configuration you created in step 1. Copy the camel-timer.xml file into the InstallDir/deploy directory.

  6. Within a few seconds, you should start to see files appearing in the target directory (which is C:\temp\sandpit\timer, by default). The file component automatically generates a unique filename for each message that it writes.

    It is also possible to monitor activity in the JMS broker by connecting to the Fuse ESB Enterprise runtime's JMX port. To monitor the broker using JMX, perform the following steps:

    1. To monitor the Fuse ESB Enterprise runtime, start a JConsole instance (a standard Java utility) by entering the following command:

      jconsole
    2. Initially, a JConsole: Connect to Agent dialog prompts you to connect to a JMX port. From the Local tab, select the org.apache.felix.karaf.main.Bootstrap entry and click Connect.

    3. In the main JConsole window, click on the MBeans tab and then drill down to org.apache.activemq|test|Queue in the MBean tree (assuming that test is the name of your broker).

    4. Under the Queue folder, you should see the camel.timer queue. Click on the camel.timer queue to view statistics on the message throughput of this queue.

  7. To shut down the router application, delete the camel-timer.xml file from the InstallDir/deploy directory.

Figure 18.1 shows a general overview of the NMR architecture, which spans both the OSGi container and the JBI container.


In Figure 18.1, the NMR is represented as a horizontal graphical element in order to emphasize its role linking together various application bundles. In practice, however, the NMR is deployed as a collection of bundles, just like any other application in the OSGi container.

In the OSGi container, normalized messages have a standard layout, as follows:

[Note]Note

When transmitting messages solely within the OSGi container, normalization of message content is not enforced. That is, the OSGi container does not impose any restrictions on the format of the message content. If messages are transmitted to an endpoint in the JBI container, however, message normalization must be observed.

To enable integration with the NMR, Apache Camel provides an NMR component, which lets you define NMR endpoints either at the beginning (for example, as in from("nmr:ExampleEndpoint")) or at the end (for example, to("nmr:ExampleEndpoint")) of a route. For full details of how to use the NMR component, see The Apache Camel NMR Component.

[Note]Note

The NMR component is designed specifically for integrating Apache Camel with the NMR within the OSGi container. If you deploy a Apache Camel application in the JBI container, however, NMR integration is provided by the JBI component. The NMR component (for use in an OSGi context) is conventionally identified by the nmr URI scheme, whereas the JBI component (for use in a JBI context) is conventionally identified by the jbi URI scheme.

To make NMR endpoints available to your Apache Camel application, you need to create an instance of the NMR component. Add the code shown in Example 18.1 to your bundle's Spring configuration file (located in META-INF/spring/*.xml) in order to instantiate the NMR component.


The bean element creates an instance of the NMR component with the bean ID, nmr, where this bean ID can then be used as the scheme prefix to create or reference NMR endpoints in your Apache Camel routes. The bean definition references two external Java packages—org.apache.servicemix.camel.nmr and org.apache.servicemix.nmr.api—which must therefore be imported by this bundle. Because the packages do not occur in Java source code, you must add them explicitly to the list of imported packages in the bundle instructions in the POM—see Configuring the bundle instructions for details.

Example 18.2 shows the routes for the camel-nmr demonstration, taken from the Spring XML configuration file, META-INF/spring/beans.xml.

Example 18.2. Spring XML Defining a Route with an NMR Endpoint

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xmlns:camel-osgi="http://camel.apache.org/schema/osgi"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/osgi  http://www.springframework.org/schema/osgi/spring-osgi.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       http://camel.apache.org/schema/osgi http://camel.apache.org/schema/osgi/camel-osgi.xsd">

  <import resource="classpath:org/apache/servicemix/camel/nmr/camel-nmr.xml" /> 1

  <camel-osgi:camelContext xmlns="http://camel.apache.org/schema/spring">
    <!-- Route periodically sent events into the NMR -->
    <route>
      <from uri="timer://myTimer?fixedRate=true&amp;period=2000"/>
      <to uri="nmr:ExampleRouter"/> 2
    </route>
    <!-- Route exchange from the NMR endpoint to a log endpoint -->
    <route>
      <from uri="nmr:ExampleRouter"/> 3
      <bean ref="myTransform" method="transform"/>
      <to uri="log:ExampleRouter"/>
    </route>
  </camel-osgi:camelContext>

  <bean id="myTransform" class="org.apache.servicemix.examples.camel.MyTransform">
    <property name="prefix" value="MyTransform"/>
  </bean>

</beans>

1

This Spring import element imports a snippet of XML that instantiates and initializes the NMR component. In fact, the content of this snippet is identical to the XML code shown in Example 18.1.

2

At the end of the first route, messages are sent to the NMR endpoint, nmr:ExampleRouter.

3

When you specify an NMR endpoint in the uri attribute of the <from> tag, a new NMR endpoint is created by the NMR component. In this example, the <from> tag implicitly creates the NMR endpoint, nmr:ExampleRouter, which is then capable of receiving the messages sent by the first route.

Not all of the packages required by the NMR component can be automatically detected by the Maven bundle plug-in. Some of the package dependencies arise from settings in the Spring configuration file (see Example 18.1), which are not automatically taken into account by the bundle plug-in. In particular, you must ensure that the following additional packages are imported by the bundle:

  • org.apache.servicemix.camel.nmr

  • org.apache.servicemix.nmr.api

For example, the following sample configuration of the Maven bundle plug-in shows how to add an Import-Package element that contains a list of the packages required for the NMR component:

<project ...>
    ...
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
                        <Import-Package>org.apache.servicemix.camel.nmr,org.apache.servicemix.nmr.api,*</Import-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

The Import-Package list also includes the wildcard, *, which instructs the bundle plug-in to scan the Java source code in order to discover further package dependencies.

If you use Maven to build your bundles or if you know that a particular bundle is available from a Maven repository, you can use the Mvn handler scheme to locate the bundle.

[Tip]Tip

To ensure that the Mvn URL handler can find local and remote Maven artifacts, you might find it necessary to customize the Mvn URL handler configuration. For details, see Configuring the Mvn URL handler.

The Mvn URL handler resolves a reference to a local Maven repository and maintains a list of remote Maven repositories. When resolving an Mvn URL, the handler searches first the local repository and then the remote repositories in order to locate the specified Maven artifiact. If there is a problem with resolving an Mvn URL, the first thing you should do is to check the handler settings to see which local repository and remote repositories it is using to resolve URLs.

To check the Mvn URL settings, enter the following commands at the console:

karaf@root> config:edit org.ops4j.pax.url.mvn
karaf@root> config:proplist

The config:edit command switches the focus of the config utility to the properties belonging to the org.ops4j.pax.url.mvn persistent ID. The config:proplist command outputs all of the property settings for the current persistent ID. With the focus on org.ops4j.pax.url.mvn, you should see a listing similar to the following:

   org.ops4j.pax.url.mvn.localRepository = file:E:/Data/.m2/repository
   service.pid = org.ops4j.pax.url.mvn
   org.ops4j.pax.url.mvn.defaultRepositories = file:E:/Programs/FUSE/apache-serv
icemix-4.2.0-fuse-SNAPSHOT/system@snapshots
   felix.fileinstall.filename = org.ops4j.pax.url.mvn.cfg
   org.ops4j.pax.url.mvn.repositories = http://repo1.maven.org/maven2, http://re
po.fusesource.com/maven2, http://repo.fusesource.com/maven2-snapshot@snapshots@n
oreleases, http://repository.apache.org/content/groups/snapshots-group@snapshots
@noreleases, http://repository.ops4j.org/maven2, http://svn.apache.org/repos/asf
/servicemix/m2-repo, http://repository.springsource.com/maven/bundles/release, h
ttp://repository.springsource.com/maven/bundles/external

Where the localRepository setting shows the local repository location currently used by the handler and the repositories setting shows the remote repository list currently used by the handler.

For more details about the wrap URL handler, see the following references:

In order to benefit from OSGi version management capabilities, it is important to restrict the range of acceptable versions for imported packages. You can use either of the following approaches:

[Tip]Tip

In practice, you are likely to find that the majority of imported packages can be automatically versioned by Maven. It is, typically, only occasionally necessary to specify a version manually.

Normally, it is not good practice to import the packages that you export (though there are exceptions to this rule). Here are some guidelines to follow:

Assuming you want to avoid importing the packages that you export, there are two alternative approaches you can take, as follows:

JUnit 4 is the latest version of the JUnit Java testing suite. What distinguishes JUnit 4 from earlier versions is that JUnit 4 defines a test by applying Java annotations (in contrast to earlier versions of JUnit, which used inherited classes and naming conventions).

The simplest JUnit tests require just two steps:

  1. Specify which methods are the test methods by annotating them with the @org.junit.Test annotation.

  2. At any point in the test method, define an assertion by calling assertTrue() with a boolean argument (you also need to include a static import of org.junit.Assert.assertTrue() in the file). The test succeeds, if the specified assertions all evaluate to true.

To integrate JUnit 4 with Pax-Exam, perform the following steps:

  1. Customize JUnit to run the test in the Pax-Exam test runner class—JUnit allows you to delegate control over a test run to a custom runner class (by defining a runner class that inherits from org.junit.runner.Runner). In order to integrate JUnit with Pax-Exam, add a @RunWith annotation to the test class as follows:

    import org.junit.runner.RunWith;
    import org.ops4j.pax.exam.junit.JUnit4TestRunner;
    ...
    @RunWith(JUnit4TestRunner.class) 
    public class MyTest { 
        ...
    }
  2. Add a Pax-Exam configuration method to the test class—in order to run a test in an OSGi framework, you need to initialize the OSGi container properly and install any prerequisite bundles. These essential steps are performed by returning the appropriate options from the Pax-Exam configuration method. This method is identified by the @Configuration annotation as follows:

    import org.ops4j.pax.exam.junit.Configuration;
    ...
    @Configuration
    public static Option[] configuration() throws Exception {
        ...
    }
  3. Use the Pax-Exam fluent API to configure the OSGi framework—there are a fairly large number of settings and options that you can return from the Pax-Exam configuration method. In order to define these options efficiently, Pax-Exam provides a fluent API, which is defined mainly by the following classes:

Example C.1 shows the Maven dependencies you need in order to run the Pax-Exam testing framework. You must specify dependencies on JUnit 4, Pax-Exam, and Apache Karaf tooling.


This example uses custom properties to specify the versions of the various Maven artifacts.

Example C.2 shows an example of how to write a test class for Apache Karaf in the Pax-Exam testing framework. The FeaturesText class configures the Apache Karaf environment, installs the obr and wrapper features, and then runs a test against the two features (where the obr and wrapper features implement particular sets of commands in the Apache Karaf command console).

Example C.2. FeaturesText Class

// Java
/*
 * Licensed to the Apache Software Foundation (ASF)
 * ...
 */
package org.apache.karaf.shell.itests;

import org.apache.karaf.testing.AbstractIntegrationTest;
import org.apache.karaf.testing.Helper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.service.command.CommandProcessor;
import org.osgi.service.command.CommandSession;

import static org.junit.Assert.assertNotNull;
import static org.ops4j.pax.exam.CoreOptions.felix;
import static org.ops4j.pax.exam.CoreOptions.maven;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartup;
import static org.ops4j.pax.exam.OptionUtils.combine;
import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.scanFeatures;

import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.workingDirectory;

@RunWith(JUnit4TestRunner.class) 1
public class FeaturesTest extends AbstractIntegrationTest { 2

    @Test 3
    public void testFeatures() throws Exception {
        // Make sure the command services are available
        assertNotNull(getOsgiService(BlueprintContainer.class, "osgi.blueprint.container.symbolicname=org.apache.karaf.shell.obr", 20000));
        assertNotNull(getOsgiService(BlueprintContainer.class, "osgi.blueprint.container.symbolicname=org.apache.karaf.shell.wrapper", 20000));
        // Run some commands to make sure they are installed properly
        CommandProcessor cp = getOsgiService(CommandProcessor.class); 4
        CommandSession cs = cp.createSession(System.in, System.out, System.err);
        cs.execute("obr:listUrl");
        cs.execute("wrapper:install --help");
        cs.close();
    }

    @Configuration 5
    public static Option[] configuration() throws Exception{
        return combine( 6
            // Default karaf environment
            Helper.getDefaultOptions( 7
                // this is how you set the default log level when using pax logging (logProfile)
                systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG")),

            // add two features
            scanFeatures( 8
                    maven().groupId("org.apache.karaf").artifactId("apache-felix-karaf").type("xml").classifier("features").versionAsInProject(),
                    "obr", "wrapper"
            ),

            workingDirectory("target/paxrunner/features/"), 9

            waitForFrameworkStartup(), 10
            
            // Test on the felix OSGi framework
            felix() 11
        );
    }

}

1

The @RunWith annotation instructs JUnit 4 to run the following test with the Pax-Exam test runner class, JUnit4TestRunner. This is the key step to integrate JUnit 4 with the Pax-Exam testing framework.

2

In order to integrate this JUnit test properly with Apache Karaf, you are required to derive this test class from org.apache.karaf.testing.AbstractIntegrationTest.

The AbstractIntegrationTest base class also provides some helper methods that access the bundle context: getOsgiService() methods, for obtaining a reference to an OSGi service, and the getInstalledBundle() method, for obtaining a reference to an org.osgi.framework.bundle object.

3

The @Test annotation is a standard JUnit 4 annotation that identifies the following method as a test method that is to be executed in the testing framework.

4

This line gives an example of how to use the getOsgiService() helper method to obtain an OSGi service from the OSGi container. In this example, the service is identified by specifying its Java type, org.osgi.service.command.CommandProcessor. The CommandProcessor service is the Apache Karaf service that has the capability to process console commands.

5

The @Configuration annotation is a Pax-Exam-specific annotation that marks the following the method as the configuration method that sets Pax-Exam testing options. The configuration method must be declared as public static and must have a return value of type, org.ops4j.pax.exam.Option[].

6

The OptionUtils.combine() method combines a given options array (of Option[] type) in the first argument with the options in the remaining arguments, returning an options array that contains all of the options.

7

The getDefaultOptions() method from the org.apache.karaf.testing.Helper class returns an options array containing all of the system property settings and option settings required to initialize Apache Karaf for the Pax-Exam testing framework.

If there are any Java system properties in the Apache Karaf environment that you would like to customize, you can pass the properties as optional arguments to the getDefaultOptions() method. In the example shown here, the system property for the Pax logging level is set to DEBUG.

8

The Pax-Exam framework supports the concept of Apache Karaf features (see Deploying Features). You can use the PaxRunnerOptions.scanFeatures() method to install specific features in the OSGi container before the test is run.

The location of the relevant features repository is specified by passing a Pax URL as the first argument to scanFeatures(). In this example, the URL is constructed by creating a Pax Mvn URL (see Mvn URL Handler) with the fluent API from the CoreOptions class. Subsequent arguments specify which features to install—in this example, the obr and wrapper features.

9

The workingDirectory() option specifies the directory where the Pax Runner provisioning module looks for OSGi bundles.

10

The waitForFrameworkStartup() specifies that the testing framework should wait for a default length of time (five minutes) for the OSGi framework to start up before timing out. To specify the timeout explicitly, you could use the waitForFrameworkStartupFor(long millis) method instead, where the timeout is specified in milliseconds.

11

The felix() option is used to specify that the test should be run in the Felix OSGi framework.

C

class loading, Class Loading in OSGi
Conditional Permission Admin service, OSGi framework services
Configuration Admin service, OSGi Compendium services
console, Fuse ESB

D

default broker
configuration, Broker configuration
data directory, Broker data
disabling, Disabling the default broker
default repositories, Default repositories

E

execution environment, OSGi architecture
Export-Package, Specifying exported packages

F

fabric
loading artifacts, Loading artifacts into the fabric's repository
locating artifacts, Procedure for locating artifacts
Fuse ESB, Fuse ESB
console, Fuse ESB

L

lifecycle layer, OSGi architecture
lifecycle states, Bundle lifecycle states

M

Maven
installing to a fabric, Loading artifacts into the fabric's repository
local repository, Local repository
remote repositories, Remote repositories
module layer, OSGi architecture

O

org.fusesource.mq.fabric.server-default.cfg, Broker configuration
org.ops4j.pax.url.mvn.localRepository.localRepository, Local repository
org.ops4j.pax.url.mvn.localRepository.settings, Local repository
org.ops4j.pax.url.mvn.repositories, Default repositories, Remote repositories
OSGi Compendium services, OSGi Compendium services
Configuration Admin service, OSGi Compendium services
OSGi framework, OSGi Framework
bundles, OSGi architecture
execution environment, OSGi architecture
lifecycle layer, OSGi architecture
module layer, OSGi architecture
security layer, OSGi architecture
service layer, OSGi architecture
OSGi framework services, OSGi framework services
Conditional Permission Admin service, OSGi framework services
Package Admin service, OSGi framework services
Permission Admin service, OSGi framework services
Start Level service, OSGi framework services
URL Handlers service, OSGi framework services
OSGi service registry, OSGi service registry
OSGi services, OSGi Services
service invocation model, Service invocation model
service registry, OSGi service registry

P

Package Admin service, OSGi framework services
Permission Admin service, OSGi framework services
Private-Package, Specifying private packages

R

remote repositories, Remote repositories
repositories
default, Default repositories
remote, Remote repositories

S

security layer, OSGi architecture
service layer, OSGi architecture
Start Level service, OSGi framework services

U

URL Handlers service, OSGi framework services