Appendix A. Using the Maven OSGi Tooling
Abstract
Manually creating a bundle, or a collection of bundles, for a large project can be cumbersome. The Maven bundle plug-in makes the job easier by automating the process and providing a number of shortcuts for specifying the contents of the bundle manifest.
A.1. The Maven Bundle Plug-In
The Red Hat Fuse OSGi tooling uses the Maven bundle plug-in from Apache Felix. The bundle plug-in is based on the bnd tool from Peter Kriens. It automates the construction of OSGi bundle manifests by introspecting the contents of the classes being packaged in the bundle. Using the knowledge of the classes contained in the bundle, the plug-in can calculate the proper values to populate the Import-Packages
and the Export-Package
properties in the bundle manifest. The plug-in also has default values that are used for other required properties in the bundle manifest.
To use the bundle plug-in, do the following:
- Section A.2, “Setting up a Red Hat Fuse OSGi project” the bundle plug-in to your project’s POM file.
- Section A.3, “Configuring the Bundle Plug-In” the plug-in to correctly populate your bundle’s manifest.
A.2. Setting up a Red Hat Fuse OSGi project
Overview
A Maven project for building an OSGi bundle can be a simple single level project. It does not require any sub-projects. However, it does require that you do the following:
There are several Maven archetypes you can use to set up your project with the appropriate settings.
Directory structure
A project that constructs an OSGi bundle can be a single level project. It only requires that you have a top-level POM file and a src
folder. As in all Maven projects, you place all Java source code in the src/java
folder, and you place any non-Java resources in the src/resources
folder.
Non-Java resources include Spring configuration files, JBI endpoint configuration files, and WSDL contracts.
Red Hat Fuse OSGi projects that use Apache CXF, Apache Camel, or another Spring configured bean also include a beans.xml
file located in the src/resources/META-INF/spring
folder.
Adding a bundle plug-in
Before you can use the bundle plug-in you must add a dependency on Apache Felix. After you add the dependency, you can add the bundle plug-in to the plug-in portion of the POM.
Example A.1, “Adding an OSGi bundle plug-in to a POM” shows the POM entries required to add the bundle plug-in to your project.
Example A.1. Adding an OSGi bundle plug-in to a POM
... <dependencies> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.osgi.core</artifactId> <version>1.0.0</version> </dependency> ... </dependencies> ... <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.camel.osgi</Import-Package> <Private-Package>org.apache.servicemix.examples.camel</Private-Package> </instructions> </configuration> </plugin> </plugins> </build> ...
The entries in Example A.1, “Adding an OSGi bundle plug-in to a POM” do the following:
Adds the dependency on Apache Felix
Adds the bundle plug-in to your project
Configures the plug-in to use the project’s artifact ID as the bundle’s symbolic name
Configures the plug-in to include all Java packages imported by the bundled classes; also imports the org.apache.camel.osgi package
Configures the plug-in to bundle the listed class, but not to include them in the list of exported packages
Edit the configuration to meet the requirements of your project.
For more information on configuring the bundle plug-in, see Section A.3, “Configuring the Bundle Plug-In”.
Activating a bundle plug-in
To have Maven use the bundle plug-in, instruct it to package the results of the project as a bundle. Do this by setting the POM file’s packaging
element to bundle
.
Useful Maven archetypes
There are several Maven archetypes available to generate a project that is preconfigured to use the bundle plug-in:
Spring OSGi archetype
The Spring OSGi archetype creates a generic project for building an OSGi project using Spring DM, as shown:
org.springframework.osgi/spring-bundle-osgi-archetype/1.1.2
You invoke the archetype using the following command:
mvn archetype:generate -DarchetypeGroupId=org.springframework.osgi -DarchetypeArtifactId=spring-osgi-bundle-archetype -DarchetypeVersion=1.1.2 -DgroupId=groupId -DartifactId=artifactId -Dversion=version
Apache CXF code-first archetype
The Apache CXF code-first archetype creates a project for building a service from Java, as shown:
org.apache.servicemix.tooling/servicemix-osgi-cxf-code-first-archetype/2010.02.0-fuse-02-00
You invoke the archetype using the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-osgi-cxf-code-first-archetype -DarchetypeVersion=2010.02.0-fuse-02-00 -DgroupId=groupId -DartifactId=artifactId -Dversion=version
Apache CXF wsdl-first archetype
The Apache CXF wsdl-first archetype creates a project for creating a service from WSDL, as shown:
org.apache.servicemix.tooling/servicemix-osgi-cxf-wsdl-first-archetype/2010.02.0-fuse-02-00
You invoke the archetype using the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-osgi-cxf-wsdl-first-archetype -DarchetypeVersion=2010.02.0-fuse-02-00 -DgroupId=groupId -DartifactId=artifactId -Dversion=version
Apache Camel archetype
The Apache Camel archetype creates a project for building a route that is deployed into Red Hat Fuse, as shown:
org.apache.servicemix.tooling/servicemix-osgi-camel-archetype/2010.02.0-fuse-02-00
You invoke the archetype using the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-osgi-camel-archetype -DarchetypeVersion=2010.02.0-fuse-02-00 -DgroupId=groupId -DartifactId=artifactId -Dversion=version
A.3. Configuring the Bundle Plug-In
Overview
A bundle plug-in requires very little information to function. All of the required properties use default settings to generate a valid OSGi bundle.
While you can create a valid bundle using just the default values, you will probably want to modify some of the values. You can specify most of the properties inside the plug-in’s instructions
element.
Configuration properties
Some of the commonly used configuration properties are:
Setting a bundle’s symbolic name
By default, the bundle plug-in sets the value for the Bundle-SymbolicName
property to groupId + "." +
artifactId, with the following exceptions:
If groupId has only one section (no dots), the first package name with classes is returned.
For example, if the group Id is
commons-logging:commons-logging
, the bundle’s symbolic name isorg.apache.commons.logging
.If artifactId is equal to the last section of groupId, then groupId is used.
For example, if the POM specifies the group ID and artifact ID as
org.apache.maven:maven
, the bundle’s symbolic name isorg.apache.maven
.If artifactId starts with the last section of groupId, that portion is removed.
For example, if the POM specifies the group ID and artifact ID as
org.apache.maven:maven-core
, the bundle’s symbolic name isorg.apache.maven.core
.
To specify your own value for the bundle’s symbolic name, add a Bundle-SymbolicName
child in the plug-in’s instructions
element, as shown in Example A.2, “Setting a bundle’s symbolic name”.
Example A.2. Setting a bundle’s symbolic name
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
...
</instructions>
</configuration>
</plugin>
Setting a bundle’s name
By default, a bundle’s name is set to ${project.name}
.
To specify your own value for the bundle’s name, add a Bundle-Name
child to the plug-in’s instructions
element, as shown in Example A.3, “Setting a bundle’s name”.
Example A.3. Setting a bundle’s name
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-Name>JoeFred</Bundle-Name>
...
</instructions>
</configuration>
</plugin>
Setting a bundle’s version
By default, a bundle’s version is set to ${project.version}
. Any dashes (-
) are replaced with dots (.
) and the number is padded up to four digits. For example, 4.2-SNAPSHOT
becomes 4.2.0.SNAPSHOT
.
To specify your own value for the bundle’s version, add a Bundle-Version
child to the plug-in’s instructions
element, as shown in Example A.4, “Setting a bundle’s version”.
Example A.4. Setting a bundle’s version
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-Version>1.0.3.1</Bundle-Version>
...
</instructions>
</configuration>
</plugin>
Specifying exported packages
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 default package, .
, and any packages containing .impl
or .internal
.
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.
Specifying private packages
If you want to specify a list of packages to include in a bundle without exporting them, you can add a Private-Package
instruction to the bundle plug-in configuration. By default, if you do not specify a Private-Package
instruction, all packages in your local Java source are included in the bundle.
If a package matches an entry in both the Private-Package
element and the Export-Package
element, the Export-Package
element takes precedence. The package is added to the bundle and exported.
The Private-Package
element works similarly to the Export-Package
element in that you specify a list of packages to be included in the bundle. The bundle plug-in uses the list to find all classes on the project’s classpath that are to be included in the bundle. These packages are packaged in the bundle, but not exported (unless they are also selected by the Export-Package
instruction).
Example A.5, “Including a private package in a bundle” shows the configuration for including a private package in a bundle
Example A.5. Including a private package in a bundle
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Private-Package>org.apache.cxf.wsdlFirst.impl</Private-Package>
...
</instructions>
</configuration>
</plugin>
Specifying imported packages
By default, the bundle plug-in populates the OSGi manifest’s Import-Package
property with a list of all the packages referred to by the contents of the bundle.
While the default behavior is typically sufficient for most projects, you might find instances where you want to import packages that are not automatically added to the list. The default behavior can also result in unwanted packages being imported.
To specify a list of packages to be imported by the bundle, add an Import-Package
child to the plug-in’s instructions
element. The syntax for the package list is the same as for the Export-Package
element and the Private-Package
element.
When you use the Import-Package
element, the plug-in does not automatically scan the bundle’s contents to determine if there are any required imports. To ensure that the contents of the bundle are scanned, you must place an *
as the last entry in the package list.
Example A.6, “Specifying the packages imported by a bundle” shows the configuration for specifying the packages imported by a bundle
Example A.6. Specifying the packages imported by a bundle
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Import-Package>javax.jws, javax.wsdl, org.apache.cxf.bus, org.apache.cxf.bus.spring, org.apache.cxf.bus.resource, org.apache.cxf.configuration.spring, org.apache.cxf.resource, org.springframework.beans.factory.config, * </Import-Package>
...
</instructions>
</configuration>
</plugin>
More information
For more information on configuring a bundle plug-in, see: