Red Hat Training

A Red Hat training course is available for Red Hat Fuse

2.7. API/Provider Build-Time Combination

Overview

This section explains how to set up a Maven project for an API/provider bundle, where the API packages and implementation packages are kept in separate Maven projects, but then combined into a single bundle at build-time.
You can demonstrate an API/provider build-time combination bundle by modifying the Maven configuration of the hello-paris-impl bundle. By exploiting the Bnd utility's provide:=true clause, you can modify the instructions for the Maven bundle plug-in, so that the org.fusesource.example.hello.paris API package gets included in the hello-paris-impl bundle at build time.

provide:=true clause

Whenever a bundle plays the role of provider with respect to a particular API package, you must indicate this explicitly by attaching the provide:=true clause to the API package, either in an import instruction or in an export instruction (otherwise, by default, the bundle plug-in would assume that the bundle is a consumer of the API package). In particular, for an API/provider build-time combination bundle, you must export the org.fusesource.example.hello.paris API package and attach the provide:=true clause, as follows:
<instructions>
  ...
  <Export-Package>
    ...
	${project.groupId}.hello.paris*;provide:=true;version=${project.version},
  </Export-Package>
  ...
</instructions>
Exporting a package with the provide:=true clause has a very important side effect: if the code for the exported package is not in the current Maven project, the Maven bundle plug-in adds the package code to the bundle at build time.

Included Maven projects

Code from the following Maven projects is included in the hello-paris-impl bundle:
hello-paris-impl
Contains the private package, org.fusesource.example.hello.paris.impl. Build this bundle to create the API/provider build-time combination bundle, hello-paris-impl.
hello-paris
Contains the public API package, org.fusesource.example.hello.paris. This project is a prerequisite for hello-paris-impl and must be built (using mvn install) before the hello-paris-impl project. You do not deploy the hello-paris bundle directly into the OSGi container, however.

Import and export rules

The following import and export rules apply to the hello-paris-impl bundle, when it is configured as an API/provider build-time combination:
  • Exporting own packages—no own packages to export, because the hello-paris-impl Maven project contains only private implementation packages.
  • Exporting dependent packages—export the public API package, org.fusesource.example.hello.paris, with the provide:=true clause, which causes the API code to be included in the hello-paris-impl bundle at build time.
  • Importing own packages—import the public API package, org.fusesource.example.hello.paris.
  • Importing dependent packages—any external package dependencies must be imported.

Maven bundle plug-in settings

To include the API from the hello-paris bundle in the hello-paris-impl bundle, add the org.fusesource.example.hello.paris package to the Export-Package instruction with the provide:=true clause attached, as shown in Example 2.3, “Plug-In Settings for Build-Time Combination”. Compare this with the regular API/provider case, Example 2.2, “Plug-In Settings for API/Provider Combination”, which takes the same approach of exporting the API package with the provide:=true clause. The semantics, however, are a bit different, because the current example pulls in the API package from a separate Maven project.

Example 2.3. Plug-In Settings for Build-Time Combination

<instructions>
  <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
  <Import-Package>*</Import-Package>
  <Export-Package>
    !${project.groupId}*.impl*,
    !${project.groupId}*.internal*,
    ${project.groupId}.hello.paris*;provide:=true;version=${project.version},
  </Export-Package>
</instructions>

Assigning versions at package granularity

In the preceding example, the included org.fusesource.example.hello.paris API package is given the same version as the hello-paris-impl Maven project, by adding the version=${project.version} clause to the export instruction. In practice, however, you might not always want to assign versions in this way. You might prefer to assign distinct versions to the API package (from the hello-paris Maven project) and the implementation package (from the hello-paris-impl Maven project).
The alternative approach you can take is to store version information at package granularity in a packageinfo file (see the section called “Export versions at package granularity” for details). The Maven bundle plug-in automatically scans your source code, looking for packageinfo files and extracting the version information from them. In this case, you must omit the version clause from the export instruction, as follows:
  <Export-Package>
    !${project.groupId}*.impl*,
    !${project.groupId}*.internal*,
    <!-- hello.paris version stored in packageinfo -->
 ${project.groupId}.hello.paris*;provide:=true,
  </Export-Package>

Generated MANIFEST.MF file

When you build the bundle using Maven, the Maven bundle plug-in automatically generates the following MANIFEST.MF file:
Manifest-Version: 1.0
Import-Package: org.fusesource.example.hello.paris;version="[1.0,1.1)"
 ,org.fusesource.example.time;version="[1.0,2)",org.osgi.service.bluep
 rint;version="[1.0.0,2.0.0)"
Export-Package: org.fusesource.example.hello.paris;uses:="org.fusesour
 ce.example.time";version="1.0"
Built-By: FBOLTON
Tool: Bnd-1.15.0
Bundle-Name: hello-paris-impl
Created-By: Apache Maven Bundle Plugin
Export-Service: org.fusesource.example.hello.paris.HelloParis
Build-Jdk: 1.6.0_24
Bundle-Version: 1.0.0
Bnd-LastModified: 1302098214984
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.fusesource.example.hello-paris-impl
The Import-Package header imports both the public API package, org.fusesource.example.hello.paris, and the external package dependencies—for example, org.fusesource.example.time.
The Export-Package header exports the public API package, org.fusesource.example.hello.paris, while the uses clause declares a transitive dependency on the org.fusesource.example.time package.
The Export-Service header advertises the OSGi service as a HelloParis instance.

Bundle deployment

Because the hello-paris-impl bundle includes all of the code from the hello-paris Maven project, it is unnecessary to deploy the hello-paris bundle in this case.