Beginner’s Guide
The OSGi specification is a module system and service platform that implements a complete and dynamic component model. Wasn’t that a complicated definition! So how would you really use it to practical modular applications? Let this book break down the seemingly overwhelming OSGi standards for you by explaining Apache Felix‘s powerful architecture in a simple and easy-to-understand manner using Apache Felix framework to get you up and running sooner than you expect.
also read:
- Java Tutorials
- Java EE Tutorials
- Design Patterns Tutorials
- Java File IO Tutorials
The OSGi standards have found a wide range of applications in the context of the Enterprise, Telecommunications, Telematics, Smart Home, E-Health, and Mobile, toname just a few. Apache Felix is one of the most famous implementations of the OSGi framework specification. This book introduces OSGi on the simple and extensible Felix framework and guides the reader from the development environment setup to the troubleshooting of potential issues, walking them through the development of an OSGi based application and explaining relevant soft ware design concepts.
This book starts with an introduction to the OSGi Service Platform, its parts and its bundle structure. It then walks the reader through the Felix framework’s setup and their development environment. It describes the Felix Framework and how to operate it using Gogo. This book will teach you everything possible about the practical implementation of OSGi using the Felix Framework as a launch pad.
The book then kicks off the Bookshelf project, a case study that will be used to progressively explain the important concepts around OSGi using the Felix framework.
The Bookshelf project feature trail will set the context to explain OSGi headers, the bundle activator, the bundle context and so on.
As the reader implements the bookshelf step by step, they learn about OBR repositories, dependency management, and bundle version management with Felix. Moving ahead, a few more advanced topics are covered, such as using iPOJO for dependency injection and service registration; then carries onto the implementation of a web-based graphical interface, first using a simple Servlet, and then building a JSP-based Web Application Bundle.
OSGi service specifications such as the Log Service, Htt p Service, and Web Container are explained. Finally, the book describes some of the common pitfalls during bundle development and hints on troubleshooting them in Felix
What This Book Covers
Chapter 1, Quick intro to OSGi and Felix gives an overview of OSGi and introduces Felix Chapter 2, Setting up the Environment walks the reader through the pre-requisites needed for developing as they read.
Chapter 3, Felix Gogo covers the Felix Gogo command-line shell and syntax.
Chapter 4, Let’s Get Started: The Bookshelf Project sets the scope of work for the case study and describes the chapter-by-chapter learning process to achieve it.
Chapter 5, The Book Inventory Bundle starts the case study inventory layer implementation and covers the basics of integrating with an OSGi framework.
Chapter 6, Using the OSGi Bundle Repository covers OBRs and shows how to use them to install the bundles developed in Chapter 5.
Chapter 7, The Bookshelf: First Stab continues the case study by laying the business logic middle tier on top of the inventory layer showing how to get access to and interact with services from other bundles on the framework.
Chapter 8, Adding a Command-Line Interface adds a first presentation layer to the case study showing how to extend the Gogo shell with custom commands.
Chapter 9, Improving the Bookshelf Service with iPOJO covers Felix iPOJO and shows how to use it for registering and injecting services. It also explains some of the major design patterns used in this context.
Chapter 10, Improving the Logging explains the importance of logging in an application, and shows how to send logs to an OSGi Log Service implementation.
Chapter 11, How about a Graphical Interface? continues the case study by implementing a simple servlet-based presentation in an OSGi framework, using the Htt p Service.
Chapter 12, The Web Management Console provides an overview of the Felix Web Management Console and takes the reader through the steps to install it.
Chapter 13, Improving the Graphics completes the case study by implementing a JSP Web Application Bundle and explaining Web Containers in the context of OSGi .
Chapter 14, Pitfalls and Troubleshooting includes a few tips on common issues faced when writing a bundle and describes a few means to troubleshoot them.
Using the OSGi Bundle Repository
So far, we have mentioned OBRs a few times without really diving into them.
We’re now at a point where we need to start using them, so it’s time to take
that dive.
In this chapter, we will first have a look at the OBR service in some level of
detail, and then we’ll see how we use it to install bundles from a remote
location onto our Felix framework. We’ll use the bundles we’ve created in
Chapter 5, The Book Inventory Bundle, to practice what we’ve learned.
By the end of this chapter, you will have:
- Learned about the OSGi Bundle Repository concepts and the OBR repository XML file format
- Inspected the local releases repository
- Installed the bundles from Chapter 5 onto Felix
OBR, the OSGi Bundle Repository
The OSGi Bundle Repository (OBR) is a draft specification from the OSGi alliance for a service that would allow getting access to a set of remote bundle repositories. Each remote repository, potentially a front for a federation of repositories, provides a list of bundles available for download, along with some additional information related to them.
The access to the OBR repository can be through a defined API to a remote service or as a direct connection to an XML repository file.
The bundles declared in an OBR repository can then be downloaded and installed to an OSGi framework like Felix. We will go through this install process a bit later.
The OSGi specification for OBRs is currently in the draft state, which means that
it may change before it is released.
The following diagram shows the elements related to the OBR, in the context of the OSGi framework:
The OBR bundle exposes a service that is registered with the framework. This interface can be used by other components on the framework to inspect repositories, download bundles, and install them.
The Gogo command bundle also registers commands that interact with the OBR service to achieve the same purpose. Later in this chapter, we will cover those commands. API-based interaction with the service is not covered, as it is beyond the scope of this book.
The OBR service currently implements remote XML repositories only. However, the Repository interface defined by the OBR service can be implemented for other potential types of repositories as well as for a direct API integration.
There are a few OSGi repositories out there, here are some examples:
- Apache Felix: http://felix.apache.org/obr/releases.xml
- Apache Sling: http://sling.apache.org/obr/sling.xml
- Paremus: http://sigil.codecauldron.org/spring-external.obr and
http://sigil.codecauldron.org/spring-release.obr
Those may be of use later, as a source for the dependencies of your project.
The repository XML Descriptor
We already have an OBR repository available to us, our releases repository. We have deployed the bookshelf bundles to it in the previous chapter as part of the Maven deploy phase (file:///C/projects/felixbook/releases/repository.xml).
Typically, you’ll rarely need to look into the repository XML file. However, it’s a good validation step when investigating issues with the deploy/install process.
Let’s inspect some of its contents:
<repository lastmodified='20100905070524.031'>
Not included above in the automatically created repository file is the optional repository name attribute.
The repository contains a list of resources that it makes available for download. Here, we’re inspecting the entry for the bundle com.packtpub.felix.bookshelf-inventory-api:
<resource id='com.packtpub.felix.bookshelf-inventory-api/1.4.0' symbolicname='com.packtpub.felix.bookshelf-inventory-api' presentationname='Bookshelf Inventory API' uri='file:/C:/projects/felixbook/releases/com/packtpub/felix/ com.packtpub.felix.bookshelf-inventory-api/1.4.0/com.packtpub.felix. bookshelf-inventory-api-1.4.0.jar' version='1.4.0'> <description> Defines the API for the Bookshelf inventory.</description> <size>7781</size> <category id='sample'/> <capability name='bundle'> <p n='symbolicname' v='com.packtpub.felix.bookshelf-inventory-api'/> <p n='presentationname' v='Bookshelf Inventory API'/> <p n='version' t='version' v='1.4.0'/> <p n='manifestversion' v='2'/> </capability> <capability name='package'> <p n='package' v='com.packtpub.felix.bookshelf.inventory.api'/> <p n='version' t='version' v='0.0.0'/> </capability> <require name='package' filter= '(&(package=com.packtpub.felix.bookshelf.inventory.api))' extend='false' multiple='false' optional='false'> Import package com.packtpub.felix.bookshelf.inventory.api </require> </resource>
Notice that the bundle location (att ribute uri), which points to where the bundle can be downloaded, relative to the base repository location. The presentationname is used when listing the bundles and the uriis used to get the bundle when a request to install it is issued.
Inside the main resource entry tag are further bundle characteristics, a description of its capabilities, its requirements, and so on.
Although the same information is included in the bundle manifest, it is also included in the repository XML for quick access during validation of the environment, before the actual bundle is downloaded.
For example, the package capability elements describe the packages that this bundle exports:
<capability name="package"> <p n="package" v="com.packtpub.felix.bookshelf.inventory.api"/> <p n="version" t="version" v="0.0.0"/> </capability>
The require elements describe the bundle requirements from the target platform:
<require extend="false" filter="(&(package=com.packtpub.felix.bookshelf.inventory. api)(version>=0.0.0))" multiple="false" name="package" optional="false"> Import package com.packtpub.felix.bookshelf.inventory.api </require> </resource> <!-- ... –-> </repository>
The preceding excerpts respectively correspond to the Export-Package and Import-Package manifest headers.
Each bundle may have more than one entry in the repository XML: an entry for every deployed version.
Updating the OBR repository
In Chapter 5, we had briefl y looked at how to deploy a bundle to a remote repository using Maven. The Felix Maven Bundle Plugin att aches to the deploy phase to automate the bundle deployment and the update of the repository.xml file.
Using the OBR scope commands
The Gogo Command bundle registers a set of commands for the interaction with the OBR service. Those commands allow registering repositories, listing their bundles, and requesting their download and installation.
Let’s look at those commands in detail.
obr:repos
The obr:repos command (repos for short, when there are no name confl icts) allows us to manage the repositories of the OBR service.
Its usage is as follows:
g! help repos repos - manage repositories scope: obr parameters: String ( add | list | refresh | remove ) String[] space-delimited list of repository URLs
The repos add operation is used to register repositories with the OBR service. For example, let’s register our releases repository:
g! repos add file:///C:/projects/felixbook/releases/repository.xml
Registered repositories are not kept between restarts of the framework. To have repositories automatically registered at startup, set the property obr.repository.url in the framework conf/config.properties file. Its value is a space-separated list of repository URLs.
For example, the default value for this property is the Felix releases repository:
obr.repository.url=http://felix.apache.org/obr/releases.xml
The repos remove operation unregisters a previously added repository. The repos list operation is used to list the registered repositories, for example:
g! repos list file:/C:/projects/felixbook/releases/repository.xml http://felix.apache.org/obr/releases.xml
Here we have the default repository and the one we’ve just added. The repos refresh operation will reload the repositories that are passed as a parameter.
obr:list
The obr:list command finds bundles in the registered repositories and displays them. The search may be constrained by a filter on bundle names.
Its usage is as follows:
g! help list list - list repository resources scope: obr flags: -v, --verbose display all versions parameters: String[] optional strings used for name matching
The -v (or –verbose) fl ag is used to display more information on each bundle, including all versions and the bundle-symbolic name. For example, the following lists the bundles in the repository containing the sub-string book and displays verbose information:
g! list -v book Bookshelf Inventory API [com.packtpub.felix.bookshelf-inventory-api] (1.4.0) Bookshelf Inventory Impl - Mock [com.packtpub.felix.bookshelf-inventory-impl-mock] (1.4.0)
The output was reformatt ed for clarity.
obr:info
The obr:info command r etrieves and displays the information available in the repository for one or more bundles. The targeted bundles are passed as a space-separated list, each entry specified by display name, symbolic name, or bundle ID.
The syntax is as follows:
g! help info info - retrieve resource description from repository scope: obr parameters: String[] ( <bundle-name< | <symbolic-name< | <bundle-id< )[@<version<] ...
For example, the following is the repository information of the “Apache Felix Gogo Shell Runtime” (bundle ID 3):
g! obr:info 3 ------------------------------- Apache Felix Gogo Shell Runtime ------------------------------- license: http://www.apache.org/licenses/LICENSE-2.0.txt symbolicname: org.apache.felix.gogo.runtime uri: http://repo1.maven.org/maven2/org/apache/felix/gogo/- org.apache.felix.gogo.runtime/0.2.0/- org.apache.felix.gogo.runtime-0.2.0.jar documentation: http://www.apache.org/ category: [org.apache.felix.gogo] description: Apache Felix Gogo Shell size: 58198 presentationname: Apache Felix Gogo Shell Runtime id: org.apache.felix.gogo.runtime/0.2.0 version: 0.2.0 Requires: (&(package=org.OSGi.framework)) (&(package=org.OSGi.service.command)(version>=0.2.0)) (&(package=org.OSGi.service.packageadmin)) (&(package=org.OSGi.service.threadio)(version>=0.2.0)) (&(package=org.OSGi.util.tracker)) Capabilities: {manifestversion=2, symbolicname=org.apache.felix.gogo.runtime, presentationname=Apache Felix Gogo Shell Runtime, version=0.2.0} {package=org.OSGi.service.command, version=0.2.0} {package=org.OSGi.service.threadio, version=0.2.0}
obr:deploy
The obr:deploy command is used to download bundles from the repository and install them onto the Felix instance, with the possibility of optionally starting them.
The command usage is as follows:
g! help deploy deploy - deploy resource from repository scope: obr flags: -s, --start start deployed bundles parameters: String[] ( | | )[@] ...
The -s (or –start) fl ag is used to request the start of the bundles that were just installed.
We will use this command in a short while to install and start our Book Inventory API and implementation bundles.
obr:source and obr:javadoc
The obr:source and obr:javadoc commands are used to download a bundle’s sources and JavaDocs archives (if present) to a local directory, and to optionally extract them. The targeted bundles are specified as a space-separated list of references, each reference being the bundle-symbolic name, presentation name, or ID, with an optional version specification.
The obr:source and obr:javadoc commands have similar usage. The following command is that of the javadoc:
g! help javadoc javadoc - retrieve resource JavaDoc from repository scope: obr flags: -x, --extract extract documentation parameters: File local target directory String[] ( | | )[@] ...
The -x (or –extract) fl ag is used to request that the archive be extracted once it is downloaded.
There is a name confl ict between the obr:source and gogo: source commands. The fully scoped name must be used when calling those commands.
Updating bundles in the repository
As you go through your development cycle, you’ll need to refresh the bundles on your framework with their latest versions for testing.
The o br:refresh command reloads the repository listing from its source and updates the list of available bundles. However, this does not mean that the bundles have been refreshed. For this, you’ll need to update the bundle.
The full cycle at each rebuild of a bundle (assuming you’re using the same version) would be as follows:
- Deploy the bundle and update the repository descriptor, using Maven.
- Refresh the URL; this is done in the Felix console, using the following
obr:refresh command:
-> repos refresh file:/C:/projects/felixbook/releases/repository. xml
- Update the bundle using the felix:update <id> command.
This command finds the latest version of the bundle and installs it. If the bundle was previously started, it will be restarted aft er the installation.
Updating a bundle may not work as well as expected if the
installation failed because classes were not found. In those cases,
it’s bett er to uninstall and then deploy it again.
You will find yourself going through this cycle oft en. Alternatively, you can use a direct file install using the f elix:install command and then update the bundle using the f elix:update command. This is useful for fast deploy-test cycles re-using the same version of the bundle.
Installing the Book Inventory bundles to Felix
In the previous chapter, we deployed the inventory layer bundles to the releases OBR repository. Now that we know more about how to operate the OBR service in Felix, we will pick up where we left off in the last chapter. We’re going to install them on our OSGi framework.
If you haven’t done so already:
- Start up your Felix framework instance (see Chapter 2, Setting Up the Environment)
- Add the releases repository URL to the OBR service (covered earlier in this chapter)
Time for action – install the book inventory bundles
We start by listing the target bundles, to make sure they’re there and to have their names, for easy copy-and-paste.
g! list book Bookshelf Inventory API (1.5.0) Bookshelf Inventory Impl - Mock (1.5.0)
Since we’ve declared the bookshelf inventory API as a dependency of the mock implementation, we only need to specifically deploy the implementation.
First, we set the initial bundle level to 2 (Tier 3 services), and move the framework level to that level right away:
g! bundlelevel -i2 g! frameworklevel 2
Then we use the obr:deploy command to deploy the bookshelf implementation:
g! deploy -s "Bookshelf Inventory Impl - Mock" Target resource(s): ------------------- Bookshelf Inventory Impl - Mock (1.5.0) Required resource(s): --------------------- Bookshelf Inventory API (1.5.0) Deploying... Starting Book Inventory Mock Impl done.
The bundle listing now shows the newly installed bundles:
g! lb START LEVEL 1 ID|State |Level|Name 0|Active | 0|System Bundle (3.0.1) 1|Active | 1|Apache Felix Bundle Repository (1.6.2) 2|Active | 1|Apache Felix Gogo Command (0.6.0) 3|Active | 1|Apache Felix Gogo Runtime (0.6.0) 4|Active | 1|Apache Felix Gogo Shell (0.6.0) 5|Active | 1|Bookshelf Inventory API (1.5.0) 6|Active | 1|Bookshelf Inventory Impl - Mock (1.5.0)
Bundles 5 and 6 are those we’ve just installed and started.
What just happened?
Alright, this is cool. Let’s go back through it step-by-step.
Someone (in this case, it was us) has deployed a bundle onto their OBR. Now this OBR could be local, as it is here, but could also be hosted online (for example, as is the one for the Felix releases at http://felix.apache.org/obr/releases.xml).
We have registered our releases OBR with the Bundle Repository service (while we were looking at the obr:repos add command earlier), which resulted in it now being aware of the “Bookshelf Inventory API” and the “Bookshelf Implementation – Mock” bundles.
Then we requested the Bundle Repository to start the “Bookshelf Inventory Impl – Mock”, calling it by name. The Bundle Repository retrieves the information relating to that bundle, namely, the bundle URI, from its cached listing.
However, the inventory mock implementation bundle declares a dependency on the inventory API. The Bundle Repository matches this dependency with the “Bookshelf Inventory API” bundle and installs it.
Then, as all the dependencies required for the “Bookshelf Inventory Impl – Mock” bundle are satisfied, it installs it.
Having specified the -s fl ag, the installed bundles are started.
When the “Bookshelf Inventory Impl – Mock” bundle is started, its bundle activator’s start() method is called. This is when our message “Starting Book Inventory Mock Impl” is printed on the standard output.
On dependency management
The example we’ve just looked at is a simple one, with a shallow level of dependencies; yet it already shows the value gained from the use of a proper dependency management tool. As bundles become richer in features, their dependency on other bundles, whether internal or third party, grows into a complex tree (sometimes a graph with potential cycles).
Keeping a close check on the dependencies of each project reduces the potential issues relating to the deployment of bundle upgrades. It will save you from lengthy searches for the missing dependencies—usually in the late hours of the night.
It is recommended to keep a checklist of those dependencies, the versions of each that have been tested and approved and the version that’s currently being used. Also include their assigned OBR repository URL for quick access when using obr:repos add.
Pop Quiz
- What is an OBR?
- It’s OSGi ‘s way of storing bundles
- It’s a service for querying repositories hosting OSGi bundles
- It’s a service that manages installed bundles
- What’s the main diff erence between the felix:install and obr:deploy
commands?- There’s no diff erence
- The main diff erence is that obr:deploy finds and installs dependencies
- The main diff erence is that obr:deploy uses the bundle presentation name
- How do you install and start a bundle using OBR?
- I use obr:deploy; it will automatically start the bundle when it’s installed
- I use obr:deploy to install the bundle, then felix:start to start it
- I use obr:deploy with the -s fl ag to install and then start the bundle
- How do you update an OBR repository?
- I submit a request to the OSGi alliance; they will update it
- I copy the bundle and then manually update the repository XML file
- I use the bundle plugin in Maven to update the repository on bundle deploy
Summary
In this chapter, you have learned about OSGi Bundle Repository. You’ve also looked at:
- The OBR service and the repository XML descriptor
- How to manage the registered OBR repositories using the obr scope commands
- How to find and deploy a bundle from an OBR repository to Felix and update it when
it is modified
Then you have:
- Installed the bundles from Chapter 5 to the Felix instance
Next, we’re going to implement the first version of the bookshelf service; it is a proof-of-concept, which we will enrich in subsequent chapters.