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 forhello-paris-impl
and must be built (usingmvn install
) before thehello-paris-impl
project. You do not deploy thehello-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 theprovide:=true
clause, which causes the API code to be included in thehello-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.