2.6. API/Provider Combination
Overview
This section explains how to set up a Maven project for an API/provider bundle.
The
hello-boston
bundle exemplifies an API/provider combination bundle. The API/provider bundle exports only its API packages, while the implementation packages are kept private. The API/provider bundle also instantiates and exports an OSGi service, which is accessed through the HelloBoston
interface.
Directory structure
The
hello-boston
bundle has the following directory structure:
hello-boston/
|
\--src/
|
\--main/
| |
| \--java/
| | |
| | \--org/fusesource/example/hello/boston/
| | | |
| | | \--HelloBoston.java
| | |
| | \--org/fusesource/example/hello/boston/impl/
| | |
| | \--HelloBostonImpl.java
| |
| \--resources/
| |
| \--OSGI-INF/blueprint/
| |
| \--boston-svc.xml
|
\--test/
The
org.fusesource.example.hello.boston
package is public and all of its classes and interfaces are exported from the bundle.
The
org.fusesource.example.hello.boston.impl
package is private. By default, the Maven bundle plug-in treats any packages containing the segments .impl
or .internal
, as private packages.
The
src/main/resources/OSGI-INF/blueprint
directory contains a single blueprint file, boston-svc.xml
. Any file matching the pattern, *.xml
, in this directory is assumed to be a blueprint configuration file.
Sample API
The
hello-boston
bundle contains an API, which consists of the interface, HelloBoston
. The HelloBoston
interface returns a localized greeting and a Clock
object that tells the local time. It is defined as follows:
// Java package org.fusesource.example.hello.boston; import org.fusesource.example.time.Clock; public interface HelloBoston { public String getGreeting(); public Clock getLocalTime(); }
Sample implementation
The
hello-boston
bundle also implements the API. In this example, a single HelloBostonImpl
class implements the HelloBoston
interface, as follows:
// Java package org.fusesource.example.hello.boston.impl; import org.fusesource.example.hello.boston.HelloBoston; import org.fusesource.example.time.Clock; import org.fusesource.example.time.TimeUtil; public class HelloBostonImpl implements HelloBoston { protected Clock localTime = null; public String getGreeting() { return new String("Hello!"); } public Clock getLocalTime() { if (localTime==null) { localTime = TimeUtil.createClock(TimeUtil.TimeZone.BOSTON); } return localTime; } }
Publish OSGi service
The natural way to bootstrap the
HelloBoston
implementation in OSGi is to publish the class, HelloBostonImpl
, as an OSGi service. Use the bean
element to create a HelloBostonImpl
instance and use the service
element to publish the bean, advertising it as a service of HelloBoston
type.
For example, the blueprint file,
OSGI-INF/blueprint/boston-svc.xml
, has the following contents:
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <bean id="hello-boston-impl" class="org.fusesource.example.hello.boston.impl.HelloBostonImpl"/> <service ref="hello-boston-impl" interface="org.fusesource.example.hello.boston.HelloBoston"/> </blueprint>
Maven dependencies
In the Maven POM file, the
hello-boston
bundle defines dependencies on the following Maven artifact:
time-util
Import and export rules
The following import and export rules apply to the
hello-boston
bundle:
- Exporting own packages—export the public API package,
org.fusesource.example.hello.boston
. Do not export the private package,org.fusesource.example.hello.boston.impl
. - Importing own packages—import the public API package,
org.fusesource.example.hello.boston
. - Importing dependent packages—any external package dependencies must be imported.
Maven bundle plug-in settings
You must export the API package,
org.fusesource.example.hello.boston
, by including it in the Export-Package
instruction, and add the provide:=true
clause to it. This signals that this bundle is acting as the provider of the hello.boston
package (and ensures that the API is imported with the correct version range—see Section 3.3, “Automatic Import Versioning”). In this case, the bundle plug-in instructions are as follows:
Example 2.2. Plug-In Settings for API/Provider 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.boston*;provide:=true;version=${project.version} </Export-Package> </instructions>
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 Built-By: JBLOGGS Created-By: Apache Maven Bundle Plugin Import-Package: org.fusesource.example.hello.boston;version="[1.0,1.1) ",org.fusesource.example.time;version="[1.0,2)",org.osgi.service.blue print;version="[1.0.0,2.0.0)" Bnd-LastModified: 1297357441566 Export-Package: org.fusesource.example.hello.boston;uses:="org.fusesou rce.example.time";version="1.0" Bundle-Version: 1.0.0 Bundle-Name: hello-boston Build-Jdk: 1.5.0_08 Bundle-ManifestVersion: 2 Export-Service: org.fusesource.example.hello.boston.HelloBoston Bundle-SymbolicName: org.fusesource.example.hello-boston Tool: Bnd-1.15.0
The
Import-Package
header imports both the public API package, org.fusesource.example.hello.boston
, and the external package dependencies—for example, org.fusesource.example.time
.
The
Export-Package
header exports the public API package, org.fusesource.example.hello.boston
, 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 HelloBoston
instance. This enables clients to find the HelloBostonImpl
instance by searching for a service of HelloBoston
type.