Combining the Power of Eclipse and Bnd
Developing OSGi with BndTools
With the rapid rise of modular software development, OSGi is becoming the de-facto standard for modular Java applications. With a background of being designed for small embedded systems, it's now also a great contender for ever larger and more dynamic systems. With this growth there is also a need for better and easier tools needed to develop, build and release applications based on OSGi. Some well known build tools are Eclipse PDE, Maven and Ant, and while they are well suited for smaller and simple applications, using them for complex applications shows some inherent problems. In this article these problems are explained and a solution provided by BndTools is introduced.
Building an OSGi based project is mostly done using either custom made build files (Ant in combination with Bnd), Maven and the OSGi bundle plugin, or using the Eclipse Plugin Development environment. All these tools support some kind of automation/abstraction for editing/generating manifest files, so creating a new bundle is simple and straightforward.
Maven and Eclipse rely on the concept that one project is one bundle, so each project has its own manifest file, source code and additional resources which are included when building the bundle. An actual application consists of several bundles, for example, within Eclipse a new application can be created by including/excluding bundles. Even though Maven and Eclipse make it rather easy to update the bundle manifest, they are centered around a "manifest first" model. When adding a new bundle, the manifest has to be created before actual coding starts. For Eclipse this is through the Manifest editor, and with Maven this is via the pom file.
While this provides a model which is easy to learn and use, a problem arises when trying to use this model for larger, more complex applications, but as well for legacy applications being converted to OSGi. To explain this problem, the 4+1 view will be used.
The 4+1 views method is a popular method for describing architectures. Architectural views are used to describe the system from the viewpoint of different stakeholders. It is based on 4 views, on top of which use case scenarios are used to describe interaction within the system.
The 4 views are:
• Logical View
The logical view provides a high level overview of the system. This overview is often a structural decomposition which describes the components of the system. The process view is used to describe dynamic aspects of the system, how processes interact, what asynchronous aspects are important etc.
Two last two views within the 4+1 model are the development view and the physical view. The development view can be described as the view the developer has on the project, for example, from an IDE. This includes packages, code, resources etc. The physical view, often called deployment view, is a view on components of the system and the deployment of these components to nodes. Both views are closely related, and the physical view displays the deployment of (a subset of) artifacts resulting from the development view. For example, using the separation of development and deployment view makes it possible to include classes (from one source) into multiple bundles. And even though both views are related, they provide a different view, which can't and shouldn't be combined when developing large applications. Because doing so, results in a forced separation of components, without any flexibility regarding reuse of classes and deployment of bundles. And this is exactly what Maven and the Eclipse PDT do, each bundle requires its own project. This makes it difficult to understand, manage, extend and maintain projects. The developer always needs to keep in mind how source is grouped and what components are available. Also migrating existing applications to a component based solution becomes very difficult, existing code has to be split into several projects.
What is needed is the ability to have both a development and a physical view on projects: the development view for development, and the physical view for division and deployment of components. A tool, which amongst others, tries to solve this, is BndTools. The next part of this article will introduce BndTools and how it solves this problem. Other features of BndTools are explained in detail on the BndTools website.
BndTools is a relatively new tool for building and testing OSGi based projects in Eclipse. It builds on Bnd, which is a powerful command line tool.
Bnd is described on its own website as: "the Swiss army knife of OSGi, it is used for creating and working with OSGi bundles. Its primary goal is take the pain out of developing bundles." From http://www.aqute.biz/Bnd/Bnd
Bnd solves the need to completely write and maintain the manifest file of a bundle. This manifest file is closely related to the classes in the bundle, and updating it can be very error prone. Bnd uses the actual class files to create the manifest file, this includes dependencies to packages, but for example also including packages using wild cards etc. Bnd relies on .bnd files created by the developer to customize the bundle. The file is used to define the bundle symbolic name, the exported and private package, bundle classpath etc. Maintaining these files by hand can be a cumbersome process, typos are easily made resulting in failing bundles. This is where BndTools comes back in the picture. BndTools provides a new project type in Eclipse called an OSGi project. An OSGi project is defined by a 'bnd.bnd' file in which, for example, the build path for the project is defined. This build path can consist of other bundles, but also a classpath containing plain old jar files. A project can consist of one or more bundles, and each bundle is defined by a '.bnd' file in which the metadata for the bundle is placed. Since BndTools is tightly integrated with Eclipse, Eclipse compiles and builds bundles on code changes. Besides bundles, BndTools also supports run configurations. The configurations are used to launch an OSGi framework with a selected set of bundles.
This set of bundles currently automatically includes all bundles from its own project, additional bundles can be selected from a local bundle repository. This bundle repository will be detailed later on. Using the dynamics of OSGi, in combination with the on the fly generation of bundles, BndTools makes it possible to update bundles in the running configuration.
Before detailing more about how BndTools works, let's see how this maps on the 4+1 views method. The two views relevant for the developer in this case are still the development and deployment view. From the development viewpoint, a uniform view on all the sources and resources in a project is needed. This view should not assume anything regarding the deployment of the artifacts created out of the source. Since BndTools does not impose a "project is a bundle" structure, this is exactly what is needed.
Secondly, the deployment view is also needed to be able to understand how bundles can and can't interact with each other. For example, packages which are used by a bundle, but are never exported. BndTools (actually Bnd does all the work) provides support for this by analysing the imported packages in the source with the exported packages of bundles. When looking at the 4+1 model, BndTools provides the developer with a complete development view, but still provides enough support to add and point to restrictions which the deployment imposes on the application. Its method is also especially interesting for existing projects; there is no need to divide the source into bundles.
The existing project can be kept, only a number of '.bnd' files are needed to create the bundles. Besides, the better mapping on the 4+1 views, this model also keeps the source within one project. This makes refactoring work over all bundles instead of within one, as is the case with Eclipse OSGi development. Finally, BndTools also has support for a so called repository.
The repository is used to store dependencies needed by the projects. This repository is visible as an Eclipse project in your workspace called 'cnf' and can contain both third party dependencies in different versions and stable artifacts that have been released from your own projects (so other projects can depend on them). Using this repository keeps the project clean, no additional bundles need to be placed inside the project. Also using one repository ensures multiple related projects within the workspace use the same available dependencies.
The following simple example will be used to create an application with one "Hello World" bundle. It is assumed Eclipse with BndTools is up and running. The steps followed will be:
• Create a new workspace
• Add a Bnd OSGi project
• Setup the run configuration
• Add a new bundle
Create a new workspace and select the OSGi perspective. A dialog will be shown asking to create a configuration project. This configuration project contains the bundle repository. After creating the configuration, the workspace will contain one project called “cnf”. With the OSGi perspective also comes the Repositories view. This view lists all bundles installed in the repository. A BndTools projects comes preconfigured with a list of useful bundles, including Felix, Equinox and many other compendium services. The bundles shown in this view are all located in the “cnf” project.
<BndTools - Repositories View>
Next, create a new Bnd OSGi Project. The wizard currently has two templates. For a declarative services project, and for an empty project. For this example the Empty project template is used. After creating the project the “bnd.bnd” file is opened. Initially BndTools creates a project for a single bundle. To change this, the “Enable sub-bundles” option on the “Build” tab has to be checked. After this change, it is no longer possible to configure the “bnd.bnd" file as a bundle. Bundles can be added by creating a new bundle descriptor. Before creating the bundle, the project needs an OSGi framework and possibly some other bundles. These libraries can be added to the run configuration of the “bnd. bnd” file. The run configuration can be found on the “run” tab. The desired OSGi framework can be selected, and bundles from the repository can be added. For this example, Apache Felix is used as framework and the Apache Felix Shell bundles are added. After updating the run configuration, the project can already be run. This is done on the context menu of the “bnd.bnd" file. Select “Run As” -> “OSGi Run”. This will result in starting the framework with the selected bundles. Since the shell is installed, it is possible to inspect the running bundles. Listing these bundles, using the “ps” command, will show the system bundle as well as the shell bundles. For the next steps, the framework can be kept running.
<BndTools – Running Framework>
Now a bundle needs to be added. This is done, as mentioned before, by creating a new Bundle Descriptor. A bundle descriptor shows private and exported packages. Based on these packages, the imports are calculated.
<BndTools – Bundle Editor>
Before private and exported packages can be added, some classes have to be created. For this example a simple Hello World activator will be used. Creating classes is done using the standard Eclipse method, no special actions are needed for BndTools. After creating the Activator, it must be added to the private packages of the bundle, and finally it must be set as Activator under the "Basic Information" section. This will result in an update of the calculated imports, the dependency to the framework is now listed. If the framework wasn't shutdown before adding the bundle, the power of BndTools can be seen. The newly created bundle has been installed in the running framework, and every saved change has resulted in a bundle update. The bundle has been started and the "Hello"greeting has been printed. Listing the installed bundles now also shows the created bundle.
<BndTools – Updated Framework>
While this is a very trivial and simple example, it does show the power of BndTools. The 4+1 model is followed and the developer has a complete view on all the project sources without being bothered with deployment issues, but still the deployment can easily be changed and used via the Bundle Descriptors and run configurations. Larger projects with multiple bundles can greatly benefit from this model and using the features to update bundles in a running framework can result in a serious reduction of time needed for compiling, starting and testing bundles. To summarize, BndTools makes it possible to develop, test and run OSGi bundles and applications in a dynamic way. This method of development fits the inherent dynamic aspects of OSGi, but does not burden the developer too much with deployment questions while writing the code. While BndTools is already very useful, it is still being improved. Since it is an open source project, anyone can look at the source and contribute via patches (using github).