2.8. Consumer Bundle
Overview
This section explains how to set up a Maven project for a consumer bundle.
The
hello-consumer
bundle exemplifies a consumer bundle, which imports OSGi services and accesses the services through the relevant API packages. This is the bundle that drives the sample application and, therefore, it relies on a blueprint lifecycle callback (through the blueprint bean
element's init-method
attribute) to initiate processing.
Note
Being a consumer is just a role, not an absolute category, so you will commonly come across bundles that behave both as a consumer and a provider. In the current example, however,
hello-consumer
behaves as a pure consumer.
Directory structure
The
hello-consumer
bundle has the following directory structure:
hello-consumer/ | \--src/ | \--main/ | | | \--java/ | | | | | \--org/fusesource/example/hello/consumer/ | | | | | \--ConsumeHello.java | | | \--resources/ | | | \--OSGI-INF/blueprint/ | | | \--client.xml | \--test/
The
org.fusesource.example.hello.consumer
package is public and all of its classes and interfaces are exported from the bundle. It would not matter, however, if you made this package private instead, because it is not needed by any other bundles.
The
src/main/resources/OSGI-INF/blueprint
directory contains a single blueprint file, client.xml
. Any file matching the pattern, *.xml
, in this directory is assumed to be a blueprint configuration file.
Sample consumer code
The
hello-consumer
bundle effectively drives the sample application, obtaining references to the HelloBoston
and HelloParis
OSGi services, and then invoking methods on these services to obtain localised greetings and times.
The
hello-consumer
bundle contains the class, ConsumeHello
, which is a client of the OSGi services, HelloBoston
and HelloParis
. To gain access to the OSGi services, ConsumeHello
defines the setter methods, getHelloBoston()
and getHelloParis()
, and relies on the blueprint framework to inject the references. The entry point is the init()
method, which gets invoked after the ConsumeHello
bean is created and injected with the service references. The ConsumeHello
class is defined as follows:
// Java package org.fusesource.example.hello.consumer; import org.fusesource.example.hello.boston.HelloBoston; import org.fusesource.example.hello.paris.HelloParis; public class ConsumeHello { protected HelloBoston helloBoston = null; protected HelloParis helloParis = null; /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub } public void init() { if (helloBoston==null || helloParis==null) { System.out.println("Initialization failed. Injected objects are null."); return; } String enGreeting = helloBoston.getGreeting(); String bostonTime = helloBoston.getLocalTime().getLocalTime(); System.out.println("Boston says:" + enGreeting + " at " + bostonTime); String frGreeting = helloParis.getGreeting(); String parisTime = helloParis.getLocalTime().getLocalTime(); System.out.println("Paris says:" + frGreeting + " at " + parisTime); } public HelloBoston getHelloBoston() { return helloBoston; } public void setHelloBoston(HelloBoston helloBoston) { this.helloBoston = helloBoston; } public HelloParis getHelloParis() { return helloParis; } public void setHelloParis(HelloParis helloParis) { this.helloParis = helloParis; } }
Access OSGi service
The
ConsumeHello
class needs to obtain a reference to the HelloBoston
service and a reference to the HelloParis
service. Use the reference
element to create proxies for the HelloBoston
service and for the HelloParis
service. Use the bean
element to create a ConsumeHello
instance and inject the helloBoston
and helloParis
proxies.
The
ConsumeHello
bean also requires an entry point to initiate processing. By setting the bean
element's init-method
attribute to init
, you ensure that the blueprint framework calls the ConsumeHello.init()
method after all of the bean's properties have been injected.
For example, the blueprint file,
OSGI-INF/blueprint/client.xml
, has the following contents:
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <reference id="helloBoston" interface="org.fusesource.example.hello.boston.HelloBoston"/> <reference id="helloParis" interface="org.fusesource.example.hello.paris.HelloParis"/> <bean id="client" class="org.fusesource.example.hello.consumer.ConsumeHello" init-method="init"> <property name="helloBoston" ref="helloBoston"/> <property name="helloParis" ref="helloParis"/> </bean> </blueprint>
Maven dependencies
In the Maven POM file, the
hello-consumer
bundle defines dependencies on the following Maven artifacts:
time-util
hello-paris
hello-boston
Import and export rules
The following import and export rules apply to the
hello-consumer
bundle:
- Exporting own packages—a client typically does not need to export its own packages, because a client does not usually expose an API.
- Importing own packages—a client does not import its own packages.
- Importing dependent packages—any external package dependencies must be imported.
Maven bundle plug-in settings
The Maven bundle plug-in is configured to export the package,
org.fusesource.example.hello.consumer
, although the export is unnecessary in this particular example. The Export-Package
instruction also contains entries to block the export of any packages containing .impl
or .internal
. In this case, the bundle plug-in instructions are as follows:
<instructions> <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName> <Import-Package>*</Import-Package> <Export-Package> !${project.groupId}*.impl*, !${project.groupId}*.internal*, ${project.groupId}.hello.consumer*;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,2)", org.fusesource.example.hello.paris;version="[1.0,2)",org.fusesource.e xample.time;version="[1.0,2)",org.osgi.service.blueprint;version="[1. 0.0,2.0.0)"Bnd-LastModified: 1296826333723 Export-Package: org.fusesource.example.hello.consumer;uses:="org.fuses ource.example.time,org.fusesource.example.hello.paris,org.fusesource. example.hello.boston";version="1.0" Bundle-Version: 1.0.0 Bundle-Name: hello-consumer Build-Jdk: 1.5.0_08 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.fusesource.example.hello-consumer Tool: Bnd-1.15.0 Import-Service: org.fusesource.example.hello.boston.HelloBoston,org.fu sesource.example.hello.paris.HelloParis
The
Import-Package
header imports the external package dependencies—for example, org.fusesource.example.hello.boston
.
The
Export-Package
header exports the package, org.fusesource.example.hello.consumer
. In this case, however, the export is not really needed and the package could have been declared private instead (for example, using the Private-Package
instruction).
The
Import-Service
header declares the OSGi services accessed by this bundle. The services are accessed respectively through the HelloBoston
interface and through the HelloParis
interface.