PK
HAoa, mimetypeapplication/epub+zipPK
HA META-INF/PK
HA OEBPS/PK
HA
OEBPS/images/PK
HA OEBPS/imagesdb/PK
HAh h META-INF/container.xml
The following best practices are recommended when building OSGi bundles using Maven:
Use your application's package prefix as the bundle symbolic name. For example, if
all of your Java source code is located in sub-packages of
org.fusesource.fooProject, use
org.fusesource.fooProject as the bundle symbolic name.
It makes sense to identify a Maven artifact with an OSGi bundle. To show this relationship as clearly as possible, you should use base the artifact ID on the bundle symbolic name. Two conventions are commonly used:
The artifact ID is identical to the bundle symbolic name—this enables you to define the bundle symbolic name in terms of the artifact ID, using the following Maven bundle instruction:
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>The bundle symbolic name is composed of the group ID and the artifact ID, joined by a dot—this enables you to define the bundle symbolic name in terms of the group ID and the artifact ID, using the following Maven bundle instruction:
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>![]() | Tip |
|---|---|
Properties of the form |
One of the key advantages of the OSGi framework is its ability to manage bundle versions and the possibility of deploying multiple versions of a bundle in the same container. In order to take advantage of this capability, however, it is essential that you associate a version with any packages that you export.
For example, you can configure the maven-bundle-plugin plug-in to
export packages with the current artifact version (given by the
project.version property) as follows:
<Export-Package>
${project.artifactId}*;version=${project.version}
</Export-Package>Notice how this example exploits the convention that packages use the artifact ID,
project.artifactId, as their package prefix. The combination of
package prefix and wildcard, ${project.artifactId}*, enables you to
reference all of the source code in your bundle.
If you define any private packages in your bundle (packages that you do not want
to export), it is recommended that you identify these packages using a strict naming
convention. For example, if your bundle includes implementation classes that you do
not want to export, you should place these classes in packages prefixed by
${project.artifactId}.impl or
${project.artifactId}.internal.
![]() | Note |
|---|---|
If you do not specify any |
To ensure that the private packages are not exported, you can
add an entry of the form ! to
the Maven bundle plug-in's export instructions. The effect of this entry is to
exclude any matching packages. For example, to exclude any packages prefixed by
PackagePattern${project.artifactId}.impl, you could add the following instruction
to the Maven bundle plug-in configuration:
<Export-Package>
!${project.artifactId}.impl.*,
${project.artifactId}*;version=${project.version}
</Export-Package>![]() | Note |
|---|---|
The order of entries in the |
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:
Manual version ranges—you can manually specify
the version range for an imported package using the version
qualifier, as shown in the following example:
<Import-Package> org.springframework.*;version="[2.5,4)", org.apache.commons.logging.*;version="[1.1,2)", * </Import-Package>
Version ranges are specified using the standard OSGi version range syntax,
where square brackets—that is, [ and
]—denote inclusive ranges and parentheses—that is,
( and )—denote exclusive ranges. Hence
the range, [2.5,4), means that the version, v, is
restricted to the range, 2.5 <= v < 4. Note the special
case of a range written as a simple number—for example,
version="2.5", which is equivalent to the range,
[2.5,.infinity)
Automatic version ranges—if packages are imported from a Maven dependency and if the dependency is packaged as an OSGi bundle, the Maven bundle plug-in automatically adds the version range to the import instructions.
The default behavior is as follows. If your POM depends on a bundle that is identified as version 1.2.4.8, the generated manifest will import version 1.2 of the bundle's exported packages (that is, the imported version number is truncated to the first two parts, major and minor).
It is also possible to customize how imported version ranges are generated
from the bundle dependency. When setting the version property,
you can use the ${@} macro (which returns the original export
version) and the ${version} macro (which modifies a version
number) to generate a version range. For example, consider the following
version settings:
*;version="${@}"If a particular package has export version
1.2.4.8, the generated import version resolves
to 1.2.4.8.
*;version="${version;==;${@}}"If a particular package has export version
1.2.4.8, the generated import version resolves
to 1.2.
*;version="[${version;==;${@}},${version;=+;${@}})"If a particular package has export version
1.2.4.8, the generated import version range
resolves to [1.2,1.3).
*;version="[${version;==;${@}},${version;+;${@}})"If a particular package has export version
1.2.4.8, the generated import version range
resolves to [1.2,2).
The middle part of the version macro—for example, == or
=+—formats the returned version number. The equals
sign, =, returns the corresponding version part unchanged; the
plus sign, +, returns the corresponding version part plus one;
and the minus sign, -, returns the corresponding version part
minus one. For more details, consult the Bnd documentation for the version macro and
the -versionpolicy option.
![]() | 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:
If the bundle is a pure library (providing interfaces and classes, but not instantiating any classes or OSGi services), do not import the packages that you export.
If the bundle is a pure API (providing interfaces and abstract classes, but no implementation classes), do not import the packages that you export.
If the bundle is a pure implementation (implementing and registering an OSGi service, but not providing any API), you do not need to export any packages at all.
![]() | Note |
|---|---|
The registered OSGi service must be accessible through an API interface or class, but it is presumed that this API is provided in a separate API bundle. The implementation bundle therefore needs to import the corresponding API packages. |
A special case arises, if an implementation and its corresponding API are combined into the same bundle. In this case, the API packages must be listed amongst the export packages and amongst the import packages. This configuration is interpreted in a special way by the OSGi framework: it actually means that the API packages will either be exported or imported at run time (but not both).
The reason for this special configuration is that, in a complex OSGi application, it is possible that an API package might be provided by more than one bundle. But you do not want multiple copies of an API to be exported into OSGi, because that can lead to technical problems like class cast exceptions. When a package is listed both in the exports and in the imports, the OSGi resolver proceeds as follows:
First of all, the resolver checks whether the package has already been exported from another bundle. If so, the resolver imports the package, but does not export it.
Otherwise, the resolver uses the local API package and exports this package, but it does not import the package.
Assuming you want to avoid importing the packages that you export, there are two alternative approaches you can take, as follows:
(Recommended) The most effective way of suppressing
the import of exported packages is to append the
-noimport:=true setting to package patterns in the
Export-Package instruction. For example:
<Export-Package>
${project.artifactId}*;version=${project.version};-noimport:=true
</Export-Package>The marked packages are now not imported,
irrespective of what is contained in the Import-Package
instruction.
An alternative way of avoiding the import is to add one or more package
exclusions to the Maven bundle plug-in's Import-Package element
(this was the only possibility in earlier versions of the Maven bundle
plug-in). For example, the following Import-Package element
instructs the Maven bundle plug-in to exclude all packages prefixed by the
artifact ID, ${project.artifactId}:
<Import-Package>
!${project.artifactId}*,
org.springframework.*;version="[2.5,4)",
org.apache.commons.logging.*;version="[1.1,2)",
*
</Import-Package>When an imported package is specified with optional resolution, this allows the bundle to be resolved without resolving the optional package. This affects the resolution order of the bundles which, in turn, can affect the runtime behavior. You should therefore be careful with optional imports, in case they have some unintended side effects.
A package is optional when it appears in the Import-Package manifest
header with the resolution:="optional" setting appended to it. For
example, the following example shows an Import-Package instruction for
the Maven bundle plug-in that specifies an optional import:
<Import-Package> org.springframework.*;version="[2.5,4)", org.apache.commons.logging.*;version="[1.1,2)";resolution:="optional", * </Import-Package>
Avoid using the Require-Bundle header, if possible. The trouble with
using the Require-Bundle header is that it forces
the OSGi resolver to use packages from the specified bundle. Importing at the
granularity of packages, on the other hand, allows the resolver to be more flexible,
because there are fewer constraints: if a package is already available and resolved
from another bundle, the resolver could use that package instead.
Example B.1 shows a sample POM that illustrates the best practices for building an OSGi bundle using Maven.
Example B.1. Sample POM File Illustrating Best Practices
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fusesource</groupId>
<artifactId>org.fusesource.fooProject</artifactId>
<packaging>bundle</packaging>
<version>1.0-SNAPSHOT</version>
<name>A fooProject OSGi Bundle</name>
<url>http://www.myorganization.org</url>
<dependencies>...</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>
!${project.artifactId}.impl.*,
${project.artifactId}*;version=${project.version};-noimport:=true
</Export-Package>
<Import-Package>
org.springframework.*;version="[2.5,4)",
org.apache.commons.logging.*;version="[1.1,2)",
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>The following best practices are recommended for OSGi related tools and utilities:
Even for a moderately sized bundle project, it is usually impractical to create and maintain a bundle Manifest by hand. The Maven bundle plug-in is the most effective tool for automating the generation of bundle Manifests in a Maven project. See Building OSGi Bundles.
Avoid using the OSGi Java API directly. Prefer a higher level technology, for example: Blueprint (from the OSGi Compendium Specification), Spring-DM, Declarative Services (DS), iPojo, and so on.
The Blueprint container is now the preferred framework for instantiating, registering, and referencing OSGi services, because this container has now been adopted as an OSGi standard. This ensures greater portability for your OSGi service definitions in the future.
Spring Dynamic Modules (Spring-DM) provided much of the original impetus for the definition of the Blueprint standard, but should now be regarded as obsolescent. Using the Blueprint container does not prevent you from using the Spring framework: the latest version of Spring is compatible with Blueprint.
When an application is composed of a large number of bundles, it becomes essential to group bundles together in order to deploy them efficiently. Apache Karaf features is a mechanism that is designed just for this purpose. It is easy to use and supported by a variety of different tools. See Deploying Features for details.
The OSGi Configuration Admin service is the preferred mechanism for providing configuration properties to your application. This configuration mechanism enjoys better tooling support than other approaches. For example, in Fuse ESB Enterprise the OSGi Configuration Admin service is supported in the following ways:
Properties integrated with Spring XML files.
Properties automatically read from configuration files,
etc/persistendId.cfg
Properties can be set in feature repositories.
In order for testing to be really effective, you should run at least some of your tests in an OSGi container. This requires you to start an OSGi container, configure its environment, install prerequisite bundles, and install the actual test. Performing these steps manually for every test would make testing prohibitively difficult and time-consuming. Pax-Exam solves this problem by providing a testing framework that is capable of automatically initializing an OSGi container before running tests in the container.
See Appendix C for more details.
The combination of Maven and the OSGi framework provides a sophisticated framework for building and deploying enterprise applications. In order to use this framework effectively, however, it is necessary to adopt certain conventions and best practices. The practices described in this appendix are intended to optimize the manageability and scalability of your OSGi applications.
This section gives a brief overview of how to prepare Maven for building Fuse ESB Enterprise projects and introduces the concept of Maven coordinates, which are used to locate Maven artifacts.
In order to build a project using Maven, you must have the following prerequisites:
Maven installation—Maven is a free, open source build tool from Apache. You can download the latest version from the Maven download page. The minimum supported version is 2.2.1.
Network connection—whilst performing a build, Maven dynamically searches external repositories and downloads the required artifacts on the fly. By default, Maven looks for repositories that are accessed over the Internet. You can change this behavior so that Maven will prefer searching repositories that are on a local network.
![]() | Note |
|---|---|
Maven can run in an offline mode. In offline mode Maven will only look for artifacts in its local repository. |
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.
Example 3.2. Adding the FuseSource Repositories to Maven
<settings>
<profiles>
<profile>
<id>my-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>fusesource</id>
<url>http://repo.fusesource.com/nexus/content/groups/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<repository>
<id>fusesource.snapshot</id>
<url>http://repo.fusesource.com/nexus/content/groups/public-snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>apache-public</id>
<url>https://repository.apache.org/content/groups/public/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
...
</repositories>
</profile>
</profiles>
...
</settings>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.
The basic building block in the Maven build system is an artifact. The output of an artifact, after performing a Maven build, is typically an archive, such as a JAR or a WAR.
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,
{. Sometimes Maven augments the basic
set of coordinates with the additional coordinates,
groupId,
artifactId,
version}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:versiongroupdId:artifactId:packaging:versiongroupdId:artifactId:packaging:classifier:version
Each coordinate can be explained as follows:
groupdIdDefines a scope for the name of the artifact. You would typically use
all or part of a package name as a group ID—for example,
org.fusesource.example.
artifactIdDefines the artifact name (relative to the group ID).
versionSpecifies the artifact's version. A version number can have up to four
parts: n.n.n.n, where the last part of the version number
can contain non-numeric characters (for example, the last part of
1.0-SNAPSHOT is the alphanumeric substring,
0-SNAPSHOT).
packagingDefines the packaged entity that is produced when you build the
project. For OSGi projects, the packaging is bundle. The
default value is jar.
classifierEnables you to distinguish between artifacts that were built from the same POM, but have different content.
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 |
|---|---|
It is not necessary to specify the |
One of the most important principles of the Maven build system is that there are
standard locations for all of the files in the Maven
project. There are several advantages to this principle. One advantage is that Maven
projects normally have an identical directory layout, making it easy to find files
in a project. Another advantage is
that the various tools integrated with Maven need almost no
initial configuration. For example, the Java compiler knows that it should compile
all of the source files under src/main/java and put the results into
target/classes.
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.
Example 3.1. Standard Maven Directory Layout
ProjectDir/
pom.xml
src/
main/
java/
...
resources/
META-INF/
spring/
*.xml
OSGI-INF/
blueprint/
*.xml
test/
java/
resources/
target/
...![]() | Note |
|---|---|
It is possible to override the standard directory layout, but this is not a recommended practice in Maven. |
The pom.xml file is the Project Object Model (POM) for the current
project, which contains a complete description of how to build the current project.
A pom.xml file can be completely self-contained, but frequently
(particular for more complex Maven projects) it can import settings from a
parent POM file.
After building the project, a copy of the pom.xml file is
automatically embedded at the following location in the generated JAR file:
META-INF/maven/groupId/artifactId/pom.xml
The src/ directory contains all of the code and resource files that
you will work on while developing the project.
The target/ directory contains the result of the build (typically a
JAR file), as well as all all of the intermediate files generated during the build.
For example, after performing a build, the target/classes/ directory
will contain a copy of the resource files and the compiled Java classes.
The src/main/ directory contains all of the code and resources needed
for building the artifact.
The src/test/ directory contains all of the code and resources for
running unit tests against the compiled artifact.
Each java/ sub-directory contains Java source code
(*.java files) with the standard Java directory layout (that is,
where the directory pathnames mirror the Java package names, with / in
place of the . character). The src/main/java/ directory
contains the bundle source code and the src/test/java/ directory
contains the unit test source code.
If you have any configuration files, data files, or Java properties to include in
the bundle, these should be placed under the src/main/resources/
directory. The files and directories under src/main/resources/ will be
copied into the root of the JAR file that is generated by the Maven build
process.
The files under src/test/resources/ are used only during the testing
phase and will not be copied into the generated JAR
file.
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.
OSGi R4.2 defines a blueprint container, which is effectively a standardized
version of Spring DM. Fuse ESB Enterprise has built-in support for the blueprint container, which
you can enable simply by including blueprint configuration files,
OSGI-INF/blueprint/*.xml, in your project. For more details about
the blueprint container, see OSGi Services.
To help you get started quickly, you can invoke a Maven archetype to generate the initial outline of a Maven project (a Maven archetype is analogous to a project wizard). The following Maven archetypes can generate projects for building OSGi bundles:
The Apache CXF code-first archetype creates a project for building a service from
Java. To generate a Maven project with the coordinates,
GroupId:ArtifactId:Version,
enter the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-cxf-code-first-osgi-bundle -DarchetypeVersion=2012.01.0.fuse-70-097 -DgroupId=GroupId-DartifactId=ArtifactId-Dversion=Version
![]() | Note |
|---|---|
The arguments to the |
The Apache CXF WSDL-first archetype creates a project for building a service from
WSDL. To generate a Maven project with the coordinates,
GroupId:ArtifactId:Version,
enter the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-cxf-wsdl-first-osgi-bundle -DarchetypeVersion=2012.01.0.fuse-70-097 -DgroupId=GroupId-DartifactId=ArtifactId-Dversion=Version
The Apache Camel OSGi archetype creates a project for building a route that can be
deployed into the OSGi container. To generate a Maven project with the coordinates,
GroupId:ArtifactId:Version,
enter the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-camel-osgi-bundle -DarchetypeVersion=2012.01.0.fuse-70-097 -DgroupId=GroupId-DartifactId=ArtifactId-Dversion=Version
By default, the preceding archetypes create a project in a new directory, whose
names is the same as the specified artifact ID,
ArtifactId. To build the bundle defined by the new
project, open a command prompt, go to the project directory (that is, the directory
containing the pom.xml file), and enter the following Maven
command:
mvn install
The effect of this command is to compile all of the Java source files, to generate
a bundle JAR under the ArtifactId/target
directory, and then to install the generated JAR in the local Maven
repository.
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.
If you already have a Maven project and you want to modify it so that it generates an OSGi bundle, perform the following steps:
Configure Maven to generate an OSGi bundle by changing the package type to
bundle in your project's pom.xml file. Change the
contents of the packaging element to bundle, as shown in
the following example:
<project ... >
...
<packaging>bundle</packaging>
...
</project>The effect of this setting is to select the Maven bundle plug-in,
maven-bundle-plugin, to perform packaging for this project. This
setting on its own, however, has no effect until you explicitly add the bundle
plug-in to your POM.
To add the Maven bundle plug-in, copy and paste the following sample
plugin element into the project/build/plugins section
of your project's pom.xml file:
<project ... >
...
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>*</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
...
</project>Where the bundle plug-in is configured by the settings in the
instructions element.
For some specific recommendations on configuring the bundle plug-in for Apache CXF and Apache Camel, see Packaging a Web Service in a Bundle and Spring example.
For an in-depth discussion of bundle plug-in configuration, in the context of the OSGi framework and versioning policy, see Managing OSGi Dependencies.
It is almost always necessary to specify the JDK version in your POM file. If your
code uses any modern features of the Java language—such as generics, static
imports, and so on—and you have not customized the JDK version in the POM,
Maven will fail to compile your source code. It is not
sufficient to set the JAVA_HOME and the PATH environment
variables to the correct values for your JDK, you must also modify the POM
file.
To configure your POM file, so that it accepts the Java language features
introduced in JDK 1.6, add the following maven-compiler-plugin plug-in
settings to your POM (if they are not already present):
<project ... >
...
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
...
</project>This chapter describes how to build an OSGi bundle using Maven. For building bundles, the Maven bundle plug-in plays a key role, because it enables you to automate the generation of OSGi bundle headers (which would otherwise be a tedious task). Maven archetypes, which generate a complete sample project, can also provide a starting point for your bundle projects.
Note: Consider using FABs instead of bundles as your unit of deployment, because FABs are easier to configure, deploy, and maintain.
To help you get started quickly, you can invoke a Maven archetype to generate the
initial outline of a Maven project (a Maven archetype is analogous to a project
wizard). Because FABs do not require any special configuration (apart from the
presence of a pom.xml file, which is always present in a
Maven-generated JAR), you can use almost any Maven archetype, as long as the
generated Maven project has the jar packaging type.
The following Maven archetypes are useful for generating Apache Camel projects:
camel-archetype-javaDemonstrates a route defined using the Java DSL.
camel-archetype-blueprintDemonstrates a route defined using the XML DSL in an OSGi blueprint file.
camel-archetype-activemqDemonstrates how to use a message broker in a route.
camel-archetype-componentDemonstrates how to define a custom Apache Camel component.
For example, consider an archetype for building an Apache Camel project. The
camel-archetype-blueprint archetype creates a project that
demonstrates a simple Apache Camel route written in the XML DSL using the Blueprint
injection framework. To generate a Maven project with the coordinates,
GroupId:ArtifactId:Version,
enter the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.camel.archetypes -DarchetypeArtifactId=camel-archetype-blueprint -DarchetypeVersion=2.9.0.fuse-70-097 -DgroupId=GroupId-DartifactId=ArtifactId-Dversion=Version
![]() | Note |
|---|---|
The arguments to the |
The archetype creates a project in a new directory whose name is that of the
specified artifact ID, ArtifactId. To build the FAB
defined by the new project, open a command prompt, go to the project directory (that
is, the directory containing the pom.xml file), and enter the following
Maven command:
mvn install
The effect of this command is to compile all of the Java source files, to generate
a FAB JAR under the ArtifactId/target
directory, and then to install the generated JAR in the local Maven
repository.
By default, a FAB adds each Maven dependency to its private class space at run
time (except for dependencies having Maven group ID org.apache.camel,
org.apache.activemq, or org.apache.cxf, which are
shared by default). This is a safe approach to deploying dependencies, because it
reduces the risk of version inconsistencies. But it is also an expensive approach,
in terms of resources, because it forces the JVM to maintain a dedicated copy of
each dependency in memory, just for this FAB.
You can make a FAB more economical by opting to share some of its dependencies with other applications in the container. There are two approaches you can use:
To share a dependency (and its transitive dependencies), declare a dependency with
the provided scope in your project's pom.xml file. For
example:
<dependency>
<groupId>org.acme.foo</groupId>
<artifactId>foo-core</artifactId>
<version>${foo-version}</version>
<scope>provided</scope>
</dependency>This is analogous to the approach you would use when building a WAR with Maven, in order to avoid including libraries like the servlet API or the JSP API.
You can also configure class sharing by setting the
FAB-Provided-Dependency: manifest header. For example, to share all
artifacts with the org.acme.foo Maven group ID:
FAB-Provided-Dependency: org.acme.foo:* org.apache.camel:* org.apache.cxf:* org.apache.activemq:* For full details of how to use this approach, see Sharing dependencies and How to set JAR manifest headers.
Typically, it is not necessary to specify any additional configuration for a FAB. But you might be interested in setting some of the optional FAB manifest headers, in order to optimize the performance of your FAB at run time. In particular, it is often a good idea to share some of the bigger dependencies, so that the FAB does not consume too much system memory in the JVM at run time.
Many of the FAB manifest headers take a value, which is a space-separated list of patterns that match Maven artifacts. Each artifact pattern has the following syntax:
groupId[:artifactId]
If the artifact ID, artifactId, is omitted, the pattern
matches all of the artifacts in the specified group,
groupId. You can also use the wildcard character,
*, to match an arbitrary sequence of characters in either the group
ID or the artifact ID.
For example, to match specific artifacts, you could specify a list like the following:
org.apache.camel:camel-core org.apache.cxf:cxf-core
To match all of the Apache Camel, Apache ActiveMQ, and Apache CXF artifacts, you could specify a list like the following:
org.apache.camel org.apache.activemq org.apache.cxf
To match all Apache artifacts and all Spring framework artifacts, you could specify a list like the following:
org.apache.* org.springframework.*
To configure a FAB, you can optionally specify any of the following FAB manifest headers:
FAB-Version-Range-DigitsFAB-Provided-DependencySee Sharing dependencies.
FAB-Include-Optional-DependencyFAB-Dependency-Require-BundleFAB-Exclude-DependencyImport-PackageFAB-Skip-Matching-Feature-DetectionFAB-Require-Feature-URL, FAB-Require-FeatureSee Requiring features.
FAB-Install-Provided-Bundle-DependenciesMaven dependencies typically specify the exact version of each required artifact. At deployment time, however, a little bit of flexibility is usually required. For example, you would normally prefer the FAB to be capable of accepting a patch update to one of its dependencies. For this reason, when the FAB is converted to a bundle at deploy time, each dependency version is normally converted into a range.
For example, given the following Maven dependency:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-core</artifactId> <version>2.8.1-fuse-00-02</version> <scope>provided</scope> </dependency>
When the FAB is converted to a bundle, the preceding exact version is converted to
a range in the generated OSGi Import-Package header, as follows:
Import-Package: org.apache.camel;version="[2.8.1-fuse-00-02,2.9)"
This reflects the default range policy, where later patch versions
(2.8.2, 2.8.3, 2.8.4, and so on) are
accepted, but minor and major upgrades are rejected.
It is possible to modify the range policy—either to be more strict or to be
more lax—by setting the FAB-Version-Range-Digits: manifest header
to one of the following policy values:
| Value | Sample | Description |
|---|---|---|
0 | [2.5.6.qual,2.5.6.qual] | Exact only. |
1 | [2.5.6.qual,2.5.7) | Allow arbitrary qualifers (order not guaranteed). |
2 | [2.5.6.qual,2.6) | Allow patch releases (default). |
3 | [2.5.6.qual,3) | Allow patch and minor releases. |
4 | [2.5.6.qual,) | Any version from 2.5.6
onwards. |
This manifest header gives you an alternative way to configure class sharing.
Instead of adding <scope>provided</scope> to dependencies in the
pom.xml file, you can list the shared artifacts in this manifest
header. The shared artifacts are specified as a space-separated list of artifact
patterns, for example:
FAB-Provided-Dependency:groupId1:artifactId1groupId2:artifactId2...
You can also use a wildcard, *, for the
groupId or the artifactId.
For example, to share all Apache Camel and Spring dependencies (transitively) in your
FAB, add the following header to your manifest:
FAB-Provided-Dependency: org.apache.camel:* org.springframework:*
If you do not explicitly configure the FAB-Provided-Dependency
manifest header, the FAB runtime implicitly adds the following default
header:
FAB-Provided-Dependency: org.apache.camel:* org.apache.cxf:* org.apache.activemq:*
![]() | Important |
|---|---|
If you specify the |
Optional dependencies In a pom.xml file are marked by the presence of
<optional>true</optional> in the dependency.
By default, optional dependencies are excluded from a FAB. To force their
inclusion, list them in the FAB-Include-Optional-Dependency: manifest
header.
The header value is specified as a space-separated list of artifact patterns, with
support for the wildcard, * . For example, to force the inclusion of
all optional dependencies, add the following manifest
header:
FAB-Include-Optional-Dependency: *:*
Specifies a list of artifacts which should not use the regular OSGi mechanism of
importing packages, but instead should use the OSGi Require-Bundle
directive.
By default, packages are imported from shared dependencies using the OSGi
Import-Package directive for all artifacts not selected by the
FAB-Dependency-Require-Bundle header.
The header value is specified as a space-separated list of artifacts, with support
for the wildcard, * —for example:
FAB-Dependency-Require-Bundle:groupId1:artifactId1groupId2:artifactId2...
To exclude specific dependencies, you can list them in the
FAB-Exclude-Dependency: manifest header, as a space-separated list
of artifact patterns, for example:
FAB-Exclude-Dependency: log4j logkit
Specifying Java packages to import from the classpath, using the
Import-Package manifest header, is the standard OSGi mechanism for
specifying dependencies. Normally, you do not have to worry
about imported packages when using FABs, because the FAB runtime automatically
generates the Import-Package manifest header with the requisite
entries.
In exceptional cases, however, you might find that you need to import specific
Java packages that FAB is unable to figure out by itself. For these cases, it is
possible to add an Import-Package manifest header to your FAB package.
At run time, FAB merges your customized import package list with the automatically
generated list of import packages.
The Import-Package header is specified using the standard OSGi
format. For example, to import the package, com.acme.special, where the
version is allowed to lie in the range [1.0, 1.1), you could add the
following header:
Import-Package: com.acme.special;version="[1.0,1.1)"
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.9.0.fuse-70-097</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 |
|---|---|
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,
|
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
You can configure a FAB explicitly to require one or more features, so that the features are automatically installed when you deploy the FAB into the container. To identify a feature, you must specify both the location of the features repository (normally provided in a Maven repository) and the name of the feature.
For example, to require the cxf-sts feature, add the following
entries to the Manifest (noting that the Maven URL is continued on a second line,
because it does not fit within the 72 byte line limit):
FAB-Require-Feature-URL: mvn:org.apache.cxf.karaf/apache-cxf/ 2.5.0.fuse-70-097/xml/features FAB-Require-Feature: cxf-sts
The FAB-Require-Feature-URL header is specified as a space-separated
list of URLs that give the locations of the features repositories.
The FAB-Require-Feature header is specified as a space-separated list
of features, in the format, , or
in the format,
FeatureName.
For example:FeatureName/Version
FAB-Require-Feature: cxf-sts/2.5.0.fuse-70-097 cxf-wsn/2.5.0.fuse-70-097
There would not be much point in using features (which are manually adjusted to install exactly the right dependencies, for special cases that an automated tool could not copy with), if the FAB runtime simply forged ahead and installed all of the dependencies it thinks it needs, ignoring the dependencies that were already installed by the feature. For this reason, the FAB runtime adopts a respectful attitude towards previously installed bundles: by default, FAB does not try to install dependencies for a provided bundle, if that bundle is already installed.
The assumption is that a pre-installed bundle already has all of its transitive dependencies installed. For example, this is normally true, if the bundle was installed as part of a feature.
FAB respects pre-installed features and bundles by default. If you want to override this behavior, forcing the FAB runtime to scan the POM files in provided bundles and to install all of the transitive dependencies it finds, set the following Manifest header flag:
FAB-Install-Provided-Bundle-Dependencies: true
The Maven JAR plug-in supports the following alternative approaches to setting manifest headers in your Maven project:
You can specify manifest headers in pom.xml, by configuring the Maven
JAR plug-in. In the JAR plug-in's configuration/archive/manifestEntries
element, specify manifest header settings using the following syntax:
<ManifestHeaderName>HeaderValue</ManifestHeaderName>
For example, to set the FAB-Version-Range-Digits manifiest header and
the FAB-Provided-Dependency manifest header in your
pom.xml file, configure the JAR plug-in as shown in Example 5.1.
Example 5.1. Configuring FAB Manifest Headers in the POM
<project ...>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<index>true</index>
<manifestEntries>
<FAB-Version-Range-Digits>0</FAB-Version-Range-Digits>
<FAB-Provided-Dependency>
org.apache.camel:*
org.apache.cxf:*
org.apache.activemq:*
</FAB-Provided-Dependency>
</manifestEntries>
</archive>
</configuration>
</plugin>
...
</plugins>
</build>
</project>Alternatively, you can create a MANIFEST.MF file directly and
instruct the Maven JAR plug-in to include the provided manifest in the generated JAR
(the JAR plug-in does not include the manifest by default).
Configure the JAR plug-in to include the manifest file as follows:
<project ...>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- lets use the default META-INF/MANIFEST.MF if its there -->
<useDefaultManifestFile>true</useDefaultManifestFile>
</configuration>
</plugin>
...
</plugins>
</build>
</project>In your Maven project directory tree, create a MANIFEST.MF file at
the following location:
ProjectDir/src/main/resources/META-INF/MANIFEST.MFThe following example shows a correctly formatted
META-INF/MANIFEST.MF file:
FAB-Version-Range-Digits: 0 FAB-Provided-Dependency: org.apache.camel:* org.apache.cxf:* org.ac tivemq:*
Note the following peculiarities of the manifest file syntax:
Each header is terminated by a newline.
Line length is limited to 72 bytes (not characters), including the newline.
Line continuation is indicated by putting a space character at the start of a line.
The manifest file must end with a newline character.
![]() | Tip |
|---|---|
Given the awkward constraints on the manifest file syntax, it is recommended that you edit the manifest using a dedicated editor, such as the Eclipse Manifest Editor Plug-In. |
If you already have a Maven project and you want to customize it to generate a FAB, perform the following steps:
A FAB is packaged as a regular JAR file, which is the default package type in
Maven. Ensure that the packaging element in your project's
pom.xml file contains the value, jar, as shown in the
following example:
<project ... >
...
<packaging>jar</packaging>
...
</project>It is almost always necessary to specify the JDK version in your POM file. If your
code uses any modern features of the Java language—such as generics, static
imports, and so on—and you have not customized the JDK version in the POM,
Maven will fail to compile your source code. It is not
sufficient to set the JAVA_HOME and the PATH environment
variables to the correct values for your JDK, you must also modify the POM
file.
To configure your POM file, so that it accepts the Java language features
introduced in JDK 1.6, add the following maven-compiler-plugin plug-in
settings to your POM (if they are not already present):
<project ... >
...
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
...
</project>Any dependencies on standard artifacts already provided by the container should be
declared as provided, to prevent the FAB runtime from unnecessarily
installing those dependencies again. This typically includes artifacts whose names
match the patterns, camel-*, cxf-*,
activemq-*, and fabric-*.
For example, if you have an existing dependency on the camel-http
artifact, you should modify the dependency by adding the scope element
as follows:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>2.9.0.fuse-70-097</version>
<scope>provided</scope>
</dependency>![]() | Note |
|---|---|
Since Fuse ESB Enterprise 7.0.1, all dependencies with Maven group ID
|
If you have a large number of dependencies to manage, it might be easier to share the standard container artifacts by adding a FAB manifest header. For details, see Example 5.1.
Any artifacts needed only for testing must be marked with the test scope, as in the following example:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j-version}</version>
<scope>test</scope>
</dependency>Of course, this is the standard convention in POM files. But it is particularly important to observe this convention with FAB projects. For any test artifacts that are not marked as such, the FAB runtime will attempt to download and install the test artifact into the container at run time.
![]() | Important |
|---|---|
Because the test-only artifacts are not intended to be installed in the
container, it is quite likely that a FAB will fail to deploy properly if test
artifacts are not marked with the |
If you are building a Web service application based on Apache CXF, you should add
a dependency on the cxf-bundle artifact—for example, by adding
the following dependency element as a child of the
dependencies element in your POM file:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-bundle</artifactId>
<version>2.5.0.fuse-70-097</version>
<scope>provided</scope>
</dependency>Note the following points about this dependency:
The cxf-bundle artifact references an aggregate bundle that
includes all of the standard Apache CXF
bundles.
You can remove all of the other org.apache.cxf artifacts from
your POM file, because they are already included in the
cxf-bundle artifact.
You should specify the dependency to be of provided scope, so
that the FAB can share the cxf-bundle bundle that is
pre-installed in the container (at least, in the full ESB container).
Using the cxf-bundle is economical, because it is normally
already installed in the container and can be shared between multiple
applications.
If your project uses dependency injection or XML configuration, you should prefer the Blueprint framework over the Spring framework.
Because Blueprint is more tightly integrated with OSGi, it is usually able to find
whatever dependencies it needs dynamically at deploy time. By contrast, dependencies
introduced by a Spring XML file are more likely to lead to
ClassNotFound exceptions at deploy time (FAB is not capable of
parsing a Spring XML file to discover the dependencies it introduces).
Although the FAB runtime obtains most of its deployment metadata by scanning the
pom.xml file embedded in the JAR, you can also specify FAB-specific
configuration settings by adding headers to the JAR's manifest. For example:
FAB-Version-Range-Digits: 2 FAB-Provided-Dependency: org.acme.foo:* org.apache.camel:* org.apache.cxf:* org.apache.activemq:*
For detailed explanations of all the FAB manifest headers, see Configuring a FAB.
A FAB is essentially a JAR file built using Maven, where the Maven
pom.xml file declares the complete set of dependencies for the JAR.
It is recommended that you adopt FABs as your standard unit of deployment for the
Fuse ESB Enterprise container, because FABs are easy to use and less likely to fail at deploy time
(for example, due to missing dependencies). For more background information, see
Deploying a FAB.
A simple way to bootstrap Apache CXF in a WAR is to configure web.xml to
use the standard CXF servlet,
org.apache.cxf.transport.servlet.CXFServlet.
For example, the following web.xml file shows how to configure the
CXF servlet, where all Web service addresses accessed through this servlet would be
prefixed by /services/ (as specified by the value of
servlet-mapping/url-pattern):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>cxf</display-name>
<description>cxf</description>
<servlet>
<servlet-name>cxf</servlet-name>
<display-name>cxf</display-name>
<description>Apache CXF Endpoint</description>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>In addition to configuring the web.xml file, it is also necessary to
configure your Web services by defining a cxf-servlet.xml file, which
must be copied into the root of the generated WAR.
Alternatively, if you do not want to put cxf-servlet.xml in the
default location, you can customize its name and location, by setting the
contextConfigLocation context parameter in the web.xml
file. For example, to specify that Apache CXF configuration is located in
WEB-INF/cxf-servlet.xml, set the following context parameter in
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/cxf-servlet.xml</param-value>
</context-param>
...
</web-app>If you already have a Maven project and you want to modify it so that it generates a WAR, perform the following steps:
Configure Maven to generate a WAR by changing the package type to war
in your project's pom.xml file. Change the contents of the
packaging element to war, as shown in the following
example:
<project ... >
...
<packaging>war</packaging>
...
</project>The effect of this setting is to select the Maven WAR plug-in,
maven-war-plugin, to perform packaging for this project.
It is almost always necessary to specify the JDK version in your POM file. If your
code uses any modern features of the Java language—such as generics, static
imports, and so on—and you have not customized the JDK version in the POM,
Maven will fail to compile your source code. It is not
sufficient to set the JAVA_HOME and the PATH environment
variables to the correct values for your JDK, you must also modify the POM
file.
To configure your POM file, so that it accepts the Java language features
introduced in JDK 1.6, add the following maven-compiler-plugin plug-in
settings to your POM (if they are not already present):
<project ... >
...
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
...
</project>Resource files for the Web application are stored under the /WEB-INF
directory in the standard WAR directory layout. In order to ensure that these
resources are copied into the root of the generated WAR package, store the
WEB-INF directory under
in the Maven
directory tree, as follows:ProjectDir/src/main/webapp
ProjectDir/
pom.xml
src/
main/
webapp/
WEB-INF/
web.xml
classes/
lib/In particular, note that the web.xml file is stored at
.ProjectDir/src/main/webapp/WEB-INF/web.xml
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:
webXmlSpecifies where to find the web.xml file in the current
Maven project, relative to the location of pom.xml. The
default is src/main/webapp/WEB-INF/web.xml.
webResourcesSpecifies additional resource files that are to be included in the generated WAR package. It can contain the following sub-elements:
webResources/resource—each resource
elements specifies a set of resource files to include in the
WAR.
webResources/resource/directory—specifies
the base directory from which to copy resource files, where this
directory is specified relative to the location of
pom.xml.
webResources/resource/targetPath—specifies
where to put the resource files in the generated WAR
package.
webResources/resource/includes—uses an
Ant-style wildcard pattern to specify explicitly which resources
should be included in the WAR.
webResources/resource/excludes—uses an
Ant-style wildcard pattern to specify explicitly which resources
should be excluded from the WAR (exclusions
have priority over inclusions).
For complete details of how to configure the Maven WAR plug-in, see http://maven.apache.org/plugins/maven-war-plugin/index.html.
![]() | Note |
|---|---|
Do not use version 2.1 of the |
To build the WAR defined by the Maven project, open a command prompt, go to the
project directory (that is, the directory containing the pom.xml file),
and enter the following Maven command:
mvn install
The effect of this command is to compile all of the Java source files, to generate
a WAR under the directory,
and then to install the generated WAR in the local Maven repository.ProjectDir/target
You can bootstrap a Spring context in a WAR using Spring's ContextLoaderListener class.
For example, the following web.xml file shows how to boot up a Spring
application context that is initialized by the XML file,
/WEB-INF/applicationContext.xml (which is the location of the
context file in the generated WAR package):
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Camel Routes</display-name>
<!-- location of spring xml files -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!-- the listener that kick-starts Spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>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).
The following example shows how you can integrate a JMS broker into a router
application. The example generates messages using a timer; sends the messages
through the camel.timer queue in the JMS broker; and then writes the
messages to a specific directory in the file system.
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 |
|---|---|
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,
|
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. Sample Route with JMS Endpoints
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/osgi-compendium
http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd">
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="timer://MyTimer?fixedRate=true&period=4000"/>
<setBody><constant>Hello World!</constant></setBody>
<to uri="activemq:camel.timer"/>
</route>
<route>
<from uri="activemq:camel.timer"/>
<to uri="file:C:/temp/sandpit/timer"/>
</route>
</camelContext>
</beans>In general, it is necessary to create a custom instance of the Apache Camel
activemq component, because you need to specify the connection details
for connecting to the broker. The preceding example uses Spring syntax to
instantiate the activemq bean which connects to the broker URL,
tcp://localhost:61616. The broker URL must correspond to one of the
transport connectors defined in the broker configuration file,
deploy/test-broker.xml.
Example 17.3 defines two routes, as follows:
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 |
|---|---|
The |
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:
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>Start up a local instance of the Fuse ESB Enterprise runtime by entering the following at a command prompt:
servicemix
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
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
directory.InstallDir/deploy
Hot deploy the router configuration you created in step 1. Copy the
camel-timer.xml file into the
directory.InstallDir/deploy
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:
To monitor the Fuse ESB Enterprise runtime, start a JConsole instance (a standard Java utility) by entering the following command:
jconsole
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.
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).
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.
To shut down the router application, delete the
camel-timer.xml file from the
directory.InstallDir/deploy
Fuse ESB monitors JAR files in the
directory and hot
deploys everything in this directory. Each time a JAR file is copied to this
directory, it is installed in the runtime and also started. You can subsequently
update or delete the JARs, and the changes are handled automatically.InstallDir/deploy
For example, if you have just built the bundle,
ProjectDir/target/foo-1.0-SNAPSHOT.jar,
you can deploy this bundle by copying it to the
InstallDir/deploy directory as follows
(assuming you are working on a UNIX platform):
% cpProjectDir/target/foo-1.0-SNAPSHOT.jarInstallDir/deploy
Applications in an OSGi environment are subject to the lifecycle of its bundles. Bundles have six lifecycle states:
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.
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 |
|---|---|
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.
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.
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.
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.
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.
When you install a bundle using the osgi:install command (without the
-s flag), the kernel installs the specified bundle and attempts to
put it into the resolved state. If the resolution of the bundle fails for some
reason (for example, if one of its dependencies is unsatisfied), the kernel leaves
the bundle in the installed state.
At a later time (for example, after you have installed missing dependencies) you
can attempt to move the bundle into the resolved state by invoking the
osgi:resolve command, as follows:
osgi:resolve 181
Where the argument (181, in this example) is the ID of the bundle you
want to resolve.
You can start one or more bundles (from either the installed or the resolved
state) using the osgi:start command. For example, to start the bundles
with IDs, 181, 185, and 186, enter the following console command:
osgi:start 181 185 186
You can stop one or more bundles using the osgi:stop command. For
example, to stop the bundles with IDs, 181, 185, and 186, enter the following
console command:
osgi:stop 181 185 186
You can restart one or more bundles (that is, moving from the started state to the
resolved state, and then back again to the started state) using the
osgi:restart command. For example, to restart the bundles with IDs,
181, 185, and 186, enter the following console command:
osgi:restart 181 185 186
A start level is associated with every bundle. The start
level is a positive integer value that controls the order in which bundles are
activated/started. Bundles with a low start level are started before bundles with a
high start level. Hence, bundles with the start level, 1, are started
first and bundles belonging to the kernel tend to have lower start levels, because
they provide the prerequisites for running most other bundles.
Typically, the start level of user bundles is 60 or higher.
Use the osgi:bundle-level command to set the start level of a
particular bundle. For example, to configure the bundle with ID, 181,
to have a start level of 70, enter the following console
command:
osgi:bundle-level 181 70
The OSGi container itself has a start level associated with it and this system start level determines which bundles can be active and which cannot: only those bundles whose start level is less than or equal to the system start level can be active.
To discover the current system start level, enter osgi:start-level in
the console, as follows:
karaf@root> osgi:start-level Level 100
If you want to change the system start level, provide the new start level as an
argument to the osgi:start-level command, as follows:
osgi:start-level 200
You can manually deploy and undeploy bundles by issuing commands at the Fuse ESB Enterprise console.
Use the osgi:install command to install one or more bundles in the
OSGi container. This command has the following syntax:
osgi:install [-s] [--start] [--help] UrlListWhere UrlList is a whitespace-separated list of URLs
that specify the location of each bundle to deploy. The following command arguments
are supported:
-sStart the bundle after installing.
--startSame as -s.
--helpShow and explain the command syntax.
For example, to install and start the bundle,
ProjectDir/target/foo-1.0-SNAPSHOT.jar,
enter the following command at the Karaf console prompt:
osgi:install -s file:ProjectDir/target/foo-1.0-SNAPSHOT.jar![]() | Note |
|---|---|
On Windows platforms, you must be careful to use the correct syntax for the
|
To uninstall a bundle, you must first obtain its bundle ID using the
osgi:list command. You can then uninstall the bundle using the
osgi:uninstall command (which takes the bundle ID as its
argument).
For example, if you have already installed the bundle named A Camel OSGi
Service Unit, entering osgi:list at the console prompt might
produce output like the following:
... [ 175] [Active ] [ ] [Started] [ 60] ServiceMix :: FTP (2009.02.0.psc-01-00RC1) [ 181] [Resolved ] [ ] [ ] [ 60] A Camel OSGi Service Unit (1.0.0.SNAPSHOT)
You can now uninstall the bundle with the ID, 181, by entering the
following console command:
osgi:uninstall 181
When specifying the location URL to the osgi:install command, you can
use any of the URL schemes supported by Fuse ESB Enterprise, which includes the following scheme
types:
Apache Karaf provides two different approaches for deploying a single OSGi bundle: hot deployment or manual deployment. If you need to deploy a collection of related bundles, on the other hand, it is recommended that you deploy them together as a feature, rather than singly (see Deploying Features).
The OSGi framework allows third-party frameworks to be piggybacked on top of it.
In particular, Fuse ESB Enterprise enables the Spring framework and the blueprint framework, by
default. In the case of the Spring framework, OSGi
automatically activates any Spring XML files under the META-INF/spring/
directory in a JAR, and Spring XML files can also be hot-deployed to the
directory. In
the case of the blueprint framework, OSGi automatically
activates any blueprint XML files under the ESBInstallDir/deployOSGI-INF/blueprint/
directory in a JAR, and blueprint XML files can also be hot-deployed to the
directory.ESBInstallDir/deploy
There are two kinds of file that you can use to configure your project:
Spring configuration—in the standard Maven
directory layout, Spring XML configuration files are located under
.ProjectDir/src/main/resources/META-INF/spring
Blueprint configuration—in the standard Maven
directory layout, blueprint XML configuration files are located under
.ProjectDir/src/main/resources/OSGI-INF/blueprint
If you decide to use the blueprint configuration, you can embed
camelContext elements in the blueprint file, as described in Blueprint configuration file.
If you decide to configure your Apache Camel application using blueprint, you must
ensure that the camel-blueprint feature is installed. If necessary,
install it by entering the following console command:
karaf@root> features:install camel-blueprint
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&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">
...Before deploying routes in a blueprint configuration file, check that the camel-blueprint feature is already installed.
You can deploy a camelContext using a blueprint configuration file,
where the root element is blueprint and the camelContext
element is a child of the blueprint element. In this case, the
camelContext namespace must be
http://camel.apache.org/schema/blueprint.
For example, the following blueprint 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"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route> <from uri="timer://myTimer?fixedRate=true&period=2000"/> <to uri="log:ExampleRouter"/> </route> </camelContext> </blueprint>
![]() | Note |
|---|---|
Blueprint is a dependency injection framework, defined by the OSGi standard, which is similar to Spring in many respects. For more details about blueprint, see The Blueprint Container. |
You can hot deploy the following types of configuration file:
Spring XML file, deployable with the suffix, .xml.
Blueprint XML file, deployable with the suffix, .xml.
If you have an existing Spring XML or blueprint XML configuration file, you can deploy the configuration file directly by copying it into the following hot deploy directory:
InstallDir/deployAfter deploying, the configuration file is activated immediately.
If you want to deploy Apache Camel routes in a blueprint configuration file, the
camel-blueprint feature must be installed (which it is by default).
If the camel-blueprint feature has been disabled, however, you can
re-install it by entering the following console command:
karaf@root> features:install camel-blueprint
When a Spring XML file or a Blueprint XML file is hot deployed, the XML file is
automatically wrapped in an OSGi bundle and deployed as a bundle in the OSGi
container. By default, the generated bundle has the version,
0.0.0.
If you prefer to customize the bundle version, use the manifest
element in the XML file. The manifest element enables you to
override any of the headers in the generated bundle's
META-INF/MANIFEST.MF file. In particular, you can use it to specify
the bundle version.
To specify the bundle version in a hot-deployed Spring XML file, define a
manifest element as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<manifest xmlns="http://karaf.apache.org/xmlns/deployer/spring/v1.0.0">
Bundle-Version = 1.2.3.4
</manifest>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="timer://myTimer?fixedRate=true&period=2000"/>
<to uri="log:ExampleRouter"/>
</route>
</camelContext>
</beans>The manifest element for Spring XML files belongs to the following
schema namespace:
http://karaf.apache.org/xmlns/deployer/spring/v1.0.0
The contents of the manifest element are specified using the syntax
of a Java properties file.
To specify the bundle version in a hot-deployed Blueprint XML file, define a
manifest element as follows:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<manifest xmlns="http://karaf.apache.org/xmlns/deployer/blueprint/v1.0.0">
Bundle-Version = 1.2.3.4
</manifest>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route>
<from uri="timer://myTimer?fixedRate=true&period=2000"/>
<to uri="log:ExampleRouter"/>
</route>
</camelContext>
</blueprint>The manifest element for Blueprint XML files belongs to the following
schema namespace:
http://karaf.apache.org/xmlns/deployer/blueprint/v1.0.0
The contents of the manifest element are specified using the syntax
of a Java properties file.