Appendix A. Building bundles

Throughout this book, you’ve been building OSGi bundles with the bnd tool, using Ant to manage the builds. If you’re a fan of Maven, you may be feeling a bit left out at this point, but don’t worry. You can build bundles with Maven using the same bnd instructions, thanks to the maven-bundle-plugin. To build a bundle, all you really need is the ability to customize the JAR manifest; you don’t need to change to an OSGi-specific build system. On the other hand, the more a build system understands about what it’s building, the more it can assist you—so which build systems work particularly well with OSGi?

We start by revisiting bnd and Ant, but this time explaining the various bnd instructions used in the book along with some advanced ones with which you may not be familiar. After that, we’ll show you how to migrate a Maven project to use bnd and introduce some features specific to the maven-bundle-plugin. Finally, we’ll round things off with a brief overview of more OSGi-specific build systems, including Eclipse Plug-in Development Environment (PDE) and Maven Tycho. But first, let’s return to where we left off: building bundles with Ant.

A.1. Building with Ant

Apache Ant (http://ant.apache.org) is a build system for Java that uses XML to describe a tree of targets, where each target describes a sequence of tasks. Ant is extended by writing new tasks in Java, such as the bnd tool’s bnd task that can generate one or more bundles from a given class path. But what exactly is bnd?

A.1.1. Introducing the bnd tool

The bnd tool (www.aqute.biz/Code/Bnd) was written by Peter Kriens to take the pain out of developing bundles. Usually, when you create a JAR, you take a directory and archive its contents. This is fine for plain JARs, but it isn’t always ideal for OSGi bundles—there’s no easy way to tell if the OSGi manifest matches the contents or to quickly slice a large project class path into a consistent set of bundles.

Bnd is different because it takes a pull approach to assembling bundles: it doesn’t just archive everything it’s given. Developers write instructions using OSGi-style headers, which can either be written as properties in the build or stored in separate property files. The bnd tool uses these instructions to pick the classes and resources that should go into each bundle. Because the tool knows each class and resource pulled into a bundle, it can make sure they form a consistent set and generate a valid OSGi manifest that represents the contents. It can also glean information from other bundles on the class path, such as version information, and use that to automatically version imports.

Bnd instructions can be categorized into four types:

  • OSGi-style headers, which start with a capital letter
  • Low-level directives, which start with a dash
  • Variables, which start with a lowercase letter
  • Built-in macros, which start with $

Let’s begin by looking at what headers are available.

A.1.2. Headers

Bnd headers follow the same pattern of comma-separated clauses defined in the OSGi specification, so you don’t have to learn yet another syntax to write instructions. The bnd tool accepts standard OSGi headers such as Export-Package and Import-Package, as well as its own headers like Private-Package and Include-Resource that let you define additional bundle contents that are neither imported nor exported. To make life easier, you can use wildcard patterns and negation in package headers; you don’t have to be explicit and list every single package in detail. Bnd expands wildcards and normalizes versions, so the final bundle always has valid OSGi headers.

The following are some of the bnd headers you’ve used so far in this book.

Export-Package

This header is a comma-separated list of packages that should be contained and exported from this bundle. By default, this is *, which pulls the complete class path into the bundle. This is fine when you’re creating a mega bundle, but you’ll usually want to limit the packages pulled into the bundle and give them an explicit version:

Export-Package: org.foo;version=1.0

If you want to export all packages except any internal or implementation packages, you can use a negated pattern. But remember that the negated pattern must appear before the normal pattern, because the bnd tool processes patterns from left to right:

Export-Package: !*.internal.*,!*.impl.*,org.foo;version=1.0

As discussed in chapter 5, it’s often a good idea to import your own exported API packages. Older versions of bnd automatically added imports for all exports, whereas the latest versions try to make better guesses about which exported packages should be imported. If you don’t want to import an exported package, you can add an attribute to each clause as follows:

Export-Package: org.foo;version=1.0;-noimport:=true
Import-Package

This is a comma-separated list of packages that should be imported into this bundle. By default, this is also *, which the bnd tool expands into any packages that are referenced from but not contained inside the bundle. Ideally, you should use this header to tweak the results of the generated list, rather than explicitly list the packages you want imported. The most important thing to remember is to leave the * at the end of the header; otherwise, you limit the ability of bnd to manage the set of imported packages for you:

Import-Package: !org.foo.test,org.foo.runtime,*
Private-Package

This is a comma-separated list of packages that should be included in this bundle but not exported. This isn’t a standard OSGi header, so it won’t have any effect at execution time; it’s only used when assembling the bundle. If a package matches both Export-Package and Private-Package, it will be exported.

Include-Resource

This is a comma-separated list of resource paths to include in this bundle. This isn’t a standard OSGi header, so it won’t have any effect at execution time; it’s only used when assembling the bundle. The simplest form of this header doesn’t accept any regular expressions and strips away directories when including resources. The following example includes two resources, both at the root of the bundle:

Include-Resource: src/foo/plugin.xml, plugin.properties

To place resources in a subdirectory, you must use the assignment form. All you need to do is put whatever location you want (followed by =) before the resource:

Include-Resource: META-INF/model=src/model

If you want to preprocess resources and replace any property placeholders ($...) with values at build time, put curly braces around the resource clause:

Include-Resource: {META-INF/model=src/model}

Embedding a JAR inside your bundle is as simple as naming it. You don’t need to know its exact location because bnd automatically scans the project class path for it. This feature is useful when you’re using bnd with repository-based build systems like Maven, where a dependency JAR can come from anywhere:

Include-Resource: foo.jar

If you want to unpack the full JAR instead of embedding it, put an @ at the front:

Include-Resource: @foo.jar

And if you only want certain parts, you can select them using Ant-style path expressions:

Include-Resource: @foo.jar!/**/*.xml
Service-Component

Normally, this header points to an XML resource describing Declarative Service components. The bnd tool goes a step further and also accepts inline short descriptions of components, automatically generating valid XML at build time. You can even use bnd annotations to mark up component classes and setter methods; list the component class names in the header, and bnd will do the rest. The official bnd site has a complete description of the Service-Component header as well as detailed examples.

A.1.3. Directives

If headers describe the what of bundles, then directives describe the how. They let you fine-tune the packaging process so you get exactly the bundle you want. Some of the more popular directives are as follows:

  • -classpath—Comma-separated list of additional class path entries.
  • -donotcopy—Regular expression of filenames that shouldn’t be copied into the bundle. The default excludes CVS and .svn directories.
  • -exportcontents—Same syntax as Export-Package, but doesn’t pull anything into the bundle. Useful in multimodule projects when you want to provide some general export instructions, but you don’t want to affect the bundle contents.
  • -failok—Still creates a bundle, even if errors are found in the instructions or content.
  • -include—Comma-separated list of properties files containing additional bnd instructions. Properties from included files override existing properties unless the name is prefixed with ~. A missing filename causes a build error unless the name is prefixed with -.
  • -manifest—Uses the given manifest file for the bundle instead of generating one.
  • -nouses—Disables generation of uses constraints. This can be useful if you expect to deploy the bundle on Equinox or Eclipse, as the additional constraints can slow down the bundle-resolution process on certain frameworks.
  • -output—Writes the generated bundle to the given file location.
  • -plugin—List of plugin class names that augment or extend the bundling process. Bnd includes optional plugins that can process Spring XML or generate bundles on demand in the style of Make.
  • -removeheaders—Comma-separated list of headers to remove from the final manifest. Useful if you don’t want bnd-specific headers like Include-Resource ending up in your final bundle.
  • -sources—Automatically adds the source for any classes pulled into the bundle under OSGI-OPT/src. The source code must either exist in a directory or JAR on the class path, or be listed under the -sourcepath directive. OSGi-aware IDEs like Eclipse automatically look for embedded sources and use them when debugging, so adding them can help developers.
  • -versionpolicy—Defines the policy to use when selecting import ranges. The default policy is to only include the major and minor segments of the version, with no upper limit. To give a concrete example: if you were building a bundle against SLF4J 1.5.8 with the default version policy, any generated import for the org.slf4j package would use an open-ended range of org.slf4j;version="1.5".

We’ll cover version policies in more detail in section A.1.5 and suggest some common policies.

A.1.4. Variables and macros

Instructions beginning with a lowercase letter are taken as variables (also known as properties), which can be used with macros to control or parameterize the bundle contents. Bnd accepts curly, square, round, and angled brackets around macros; this can be useful if your build system attaches its own meaning to a specific bracket type, such as Maven and ${}. For consistency, we’ll stick to using round brackets throughout this appendix, because they won’t conflict with Maven property interpolation.

The simplest macro is the property placeholder consisting of just a variable name:

$(variable)

Bnd defines other macros of varying complexity that can parse, search, and filter bundle contents—essentially providing its own mini-language to control the build process. All bnd macros start with a keyword, followed by one or more parameters separated by semicolons:

$(keyword;param1;param2)

Let’s look at some of the more useful macros:

  • $(classes;query)—Searches the content of the bundle for classes that match the given query. You can use this to select all public classes that implement a certain interface:
    $(classes;PUBLIC;IMPLEMENTS;org.foo.Extension) Or those that use certain annotations somewhere in the class:
    $(classes;ANNOTATION;*.Inject) This macro is useful for scanning component details at build time and recording the results in the manifest, so you can avoid having to repeatedly scan the bundle class path at execution time. You can find the full query syntax on the bnd site.
  • $(env;name)—Evaluates to the value of the named environment variable.
  • $(filter;list;regex)—Takes a comma-separated list and keeps only the entries that match the regular expression.
  • $(filterout;list;regex)—Takes a comma-separated list and removes any entries that match the regular expression.
  • $(findname;regex;replacement)—Searches the project class path for resources whose names match the regular expression. You can provide an optional replacement string for the resource name, which can also contain the usual back references to groups in the matched pattern. The following example macro evaluates to the names of all class resources, but with .java replacing .class:
    $(findname;(.*).class;$1.java)
  • $(findpath;regex;replacement)—Similar to findname, but matches against the complete path rather than just the name.
  • $(if;condition;true;false)—Evaluates to the true section when the condition string is empty; otherwise, evaluates to the false section. This macro is a bit counterintuitive: a condition string of false is treated as true, because it’s non-empty.
  • $(join;list;list;...)—Concatenates a series of comma-separated lists into one list.
  • $(now)—Evaluates to the current date and time.
  • $(replace;list;regex;replacement)—Replaces any entries in the list that match the regular expression with the replacement string. As with findname, the replacement string can contain references to matched segments.
  • $(sort;list)—Sorts the given comma-separated list according to lexicographical order.
  • $(toclassname;list)—Replaces entries (such as org/foo/Test.class) with their class name equivalent (such as org.foo.Test).
  • $(toclasspath;list;extension)—Replaces class names (such as org.foo.Test) with their path equivalent (such as org/foo/Test.extension).
  • $(version;mask;version)—Takes a version string and alters it according to the given mask. The mask contains one to four characters, each representing a segment of the version: major, minor, micro, and qualifier. An = character means leave the segment unchanged, whereas + or - means increment or decrement the segment value. Using fewer than four characters truncates the version. As you’ll see in the next section, you can use this macro to automatically create ranges for any given version.

A.1.5. Choosing a version policy

As we mentioned at the end of section A.1.3, the default policy for generated import versions is to keep the major and minor segments but drop the rest. Using the resolution rules from chapter 2, this means the bundle won’t resolve against previous incompatible releases, but it will continue to resolve against any future release.

If the default version policy isn’t for you, you can define your own with the help of the version macro from the last section, with $(@) representing the detected import version. To explicitly define the default policy, you write

-versionpolicy: $(version;==;$(@))

The default policy gives you maximum flexibility in the future while stopping the bundle from accidentally resolving against older, incompatible releases. To strengthen the lower bound further and only accept versions strictly older than the ones you built and tested against, use the entire version and don’t drop any segments:

-versionpolicy: $(@)

What if you want to guard against future breaking changes and exclude future versions that aren’t binary compatible? You can do this by adding an upper bound to the range:

-versionpolicy: [$(version;==;$(@)),$(version;+;$(@)))

An import version of 1.5.8 using this policy maps to a version range of [1.5,2). If you find all these similar brackets confusing, remember that bnd lets you mix bracket types, so you can always rewrite this last policy more clearly:

-versionpolicy: [$<version;==;$(@)>,$<version;+;$(@)>)

A.1.6. Mending split packages

As you saw back in chapter 6, when you’re modularizing legacy applications, you may encounter the thorny issue of split packages, where two different JARs contain the same package but with different contents. Bnd warns you when it detects split packages, but it still creates the bundle. These warnings can be irritating if you already know about (and don’t mind) the split package. Indeed, you may be creating this bundle in order to merge the different parts together. To remove these warnings, add the following package attribute to any known split packages:

Private-Package: org.foo.bean;-split-package:=merge-first

This tells bnd to silently merge the contents of the org.foo.bean package together but not overwrite existing entries if there’s any overlap. You can also choose not to perform any merging by using the ;-split-package:first attributes.

You now know the various headers, directives, and macros available to us when building bundles with bnd in Ant, but what if you’re using another system, such as Maven? Do you have to learn yet another syntax, or is there a way to reuse your existing knowledge of bnd?

A.2. Building with Maven

You saw in chapter 6 how easy it is to take an existing Ant-based project and migrate it to OSGi with bnd. But what if you use Maven? Maven (http://maven.apache.org) is another popular build tool from Apache that also uses XML to describe builds, but this time the description is declarative rather than procedural. Instead of listing the steps required to build a JAR (also known as an artifact), you list the packaging as jar in the project XML.

Maven favors convention over configuration; follow the Maven way, and you can keep your XML relatively lean and uncomplicated. The problem is when you need to do something special outside of the normal Maven build process. You can end up with pages of XML detailing each step of your customized build.

How well does OSGi fit with Maven? Will you need pages of configuration to assemble your bundle?

A.2.1. Introducing the maven-bundle-plugin

The Maven build process is extended by adding plugins to projects. Maven plugins contain one or more Maven plain old Java objects (mojos), each of which represents a specific goal, such as assembling a JAR from classes and resources. A well-written plugin complements the Maven process and requires minimal setup by following the convention-over-configuration mantra.

One such plugin is the maven-bundle-plugin (http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html) from the Apache Felix project. It adds a new packaging type called bundle that tells Maven how to package, install, and deploy OSGi bundles. Add this plugin to your project XML (or parent project) and change the packaging to bundle, and it should create a bundle instead of a plain old JAR. Let’s try this out!

First, you need a simple Maven project. You can create one with the archetype plugin:

$ mvn archetype:generate -DinteractiveMode=false 
    -DgroupId=examples -DartifactId=mybundle -Dpackage=examples.osgi

This creates a new Java project in the mybundle directory with example source and tests. To build this project, type the following:

$ cd mybundle

$ mvn clean install

You should see Maven compile, test, package, and install a JAR called mybundle.jar. If you look at the manifest inside the final JAR, it only contains a few entries about who built it:

$ jar xvf target/mybundle-1.0-SNAPSHOT.jar META-INF/MANIFEST.MF

$ cat META-INF/MANIFEST.MF

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: me
Build-Jdk: 1.6.0_22

Let’s change this into an OSGi build. Open the project file (pom.xml), and add the additional lines shown here:

<project>
  ...
  <build>
    <plugins>
       <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.1.0</version>
        <extensions>true</extensions>
      </plugin>
     </plugins>
  </build>
  ...
</project>

Setting extensions to true tells Maven that this plugin contains a new packaging type, in this case bundle packaging. To use this to build your project, you need to change the packaging listed in the project’s pom.xml from

<packaging>jar</packaging>

to

  <packaging>bundle</packaging>

You can now ask Maven to rebuild your project:

$ mvn clean install

If you compare the console output to the previous build, you should see that it uses the maven-bundle-plugin to package the project. The JAR manifest now contains the appropriate OSGi headers:

Manifest-Version: 1.0
Export-Package: examples.osgi
Bundle-Version: 1.0.0.SNAPSHOT
Build-Jdk: 1.6.0_22
Built-By: me
Tool: Bnd-0.0.357
Bnd-LastModified: 1289004026415
Bundle-Name: mybundle
Bundle-ManifestVersion: 2
Created-By: Apache Maven Bundle Plugin
Import-Package: examples.osgi
Bundle-SymbolicName: examples.mybundle

Notice how you didn’t need to add anything else to the project—the maven-bundle-plugin uses existing information (project metadata, resources, and source code) to generate reasonable defaults for the OSGi manifest. But what are these defaults, and how can you customize the bundle?

A.2.2. Going undercover

You may have noticed a couple of bnd headers in the last manifest. This is because the maven-bundle-plugin leans on the bnd tool to do the heavy work of assembling the bundle and generating the manifest. In other words, the main task of the maven-bundle-plugin is to translate Maven metadata into bnd instructions, so developers don’t have to repeat themselves over and over again. The default translations are listed in table A.1.

Table A.1. maven-bundle-plugin defaults

OSGi header

Maven metadata

Bundle-Name ${project.name}
Bundle-SymbolicName ${project.groupId}.${project.artifactId} with duplicate segments removed
Bundle-Version ${project.version} normalized to the OSGi format
Bundle-Description ${project.description}
Bundle-License ${project.licenses}
Bundle-DocURL ${project.organization.url}
Bundle-Vendor ${project.organization.name}
Export-Package All Java packages in the current project (except *.internal.* and *.impl.*)
Private-Package All Java packages in the current project
Include-Resource All project resources in the current project (with property substitution)

Although these defaults are usually enough for most Maven projects, you’ll occasionally want to tweak or add additional instructions to fine-tune the bundling process. Because the maven-bundle-plugin uses bnd, you can use the exact same instructions covered in the first part of this appendix. Let’s look at a real-world example. The following listing contains a customized maven-bundle-plugin configuration taken from the Google Guice project.

Listing A.1. Google-Guice maven-bundle-plugin configuration
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.1.0</version>
<configuration>
  <instructions>
    <module>com.google.inject</module>
    <_include>-${project.basedir}/build.properties</_include>
    <Bundle-Copyright>Copyright (C) 2006 Google Inc.</Bundle-Copyright>
    <Bundle-DocURL>http://code.google.com/p/google-guice/</Bundle-DocURL>
    <Bundle-Name>${project.artifactId}</Bundle-Name>
    <Bundle-SymbolicName>$(module)</Bundle-SymbolicName>
    <Bundle-RequiredExecutionEnvironment>
      J2SE-1.5,JavaSE-1.6
    </Bundle-RequiredExecutionEnvironment>
    <Import-Package>!com.google.inject.*,*</Import-Package>
     <_exportcontents>
      !*.internal.*,$(module).*;version=${guice.api.version}
    </_exportcontents>
     <_versionpolicy>
      [$(version;==;$(@)),$(version;+;$(@)))
     </_versionpolicy>
    <_nouses>true</_nouses>
     <_removeheaders>
      Embed-Dependency,Embed-Transitive,
       Built-By,Tool,Created-By,Build-Jdk,
      Originally-Created-By,Archiver-Version,
      Include-Resource,Private-Package,
      Ignore-Package,Bnd-LastModified
     </_removeheaders>
  </instructions>
</configuration>

Most of this customization is tweaking the Maven-produced manifest to match the one generated by the existing Ant build. You can avoid this by extracting the common bnd instructions to a shared file and using the -include directive to pull it into both Ant and Maven builds. Using a separate file for bnd instructions also avoids two formatting issues that can plague Maven bundle developers:

  • XML tags can’t start with -, so bnd directives listed in XML instead start with _.
  • Maven attempts to process any text containing ${...}, so use $(...) for bnd macros.

Other issues to watch out for when you start bundling Maven projects include the following:

  • The complete project class path is passed to bnd; so Export-Package: * will embed the entire class path, dependencies and all—which may or may not be what you want.
  • Bnd uses a pull approach. It doesn’t zip up target/classes; so, if any classes are missing or you see any unexpected additional classes, check your bnd instructions.

If you want to know more about how the maven-bundle-plugin translates your project details into bnd instructions, you can use mvn -X install to enable debug logging. But watch out: this output includes debug from all plugins used in the build, so you probably want to save it somewhere so you can search for bundle details at your leisure.

You now know how to take an existing Maven project and turn it into a bundle using the maven-bundle-plugin. Just as you did with Ant, you can use bnd instructions to tweak the manifest and select the bundle content. Is that all the maven-bundle-plugin does?

A.2.3. Embedding dependencies

In addition to translating project details into bnd instructions, the maven-bundle-plugin adds a few headers of its own that let you embed Maven dependencies without having to write lengthy Include-Resource headers. It also keeps the Bundle-ClassPath header in sync, so any embedded JARs are automatically available on the bundle’s class path.

You won’t be surprised to learn that the main header is called Embed-Dependency. It accepts a comma-separated list of patterns that are matched against the project’s Maven dependency tree. Matching dependencies can either be embedded or selectively unpacked inside the bundle. The full syntax of the Embed-Dependency header is as follows:

dependencies ::= clause ( ',' clause ) *

clause ::= MATCH ( ';' attr '=' MATCH | ';inline=' inline )

attr ::= 'groupId' | 'artifactId' | 'version' | 'scope' | 'type' |
         'classifier' | 'optional'

inline ::= 'true' | 'false' | PATH ( '|' PATH ) *

MATCH ::= <globbed regular expression>

PATH ::= <Ant-style path expression>

Pretty complicated, no? You may have noticed a resemblance between this syntax and the bnd tool syntax for selecting packages. Perhaps a few examples will make things clearer; the following listing is taken from the Apache Felix documentation for the maven-bundle-plugin.

Listing A.2. Embed-Dependency examples
<!-- embed all compile and runtime scope dependencies -->
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>

<!-- embed any dependencies with artifactId junit and scope runtime -->
<Embed-Dependency>junit;scope=runtime</Embed-Dependency>

<!-- inline all non-pom dependencies, except those with scope runtime -->
<Embed-Dependency>*;scope=!runtime;type=!pom;inline=true</Embed-Dependency>

<!-- embed all compile and runtime scope dependencies,
     except those with artifactIds in the given list -->
<Embed-Dependency>
  *;scope=compile|runtime;inline=false;
    artifactId=!cli|lang|runtime|tidy|jsch
</Embed-Dependency>

<!-- inline contents of selected folders from all dependencies -->
<Embed-Dependency>*;inline=images/**|icons/**</Embed-Dependency>

In addition to Embed-Dependency, the maven-bundle-plugin adds headers to do the following:

  • Select where to embed dependencies in the bundle (Embed-Directory)
  • Remove the groupId from the embedded name (Embed-StripGroup)
  • Remove the version from the embedded name (Embed-StripVersion)
  • Consider transitive dependencies as well as direct ones (Embed-Transitive)

Now, you may be thinking that Embed-Dependency coupled with Embed-Transitive is a quick way to create a mega bundle containing everything you need for your application (see section 6.2.1). Often this is true, but occasionally you end up pulling in a vast list of optional dependencies that aren’t needed at execution time. Forget about downloading the internet—you can end up embedding it!

You should also be careful when mixing the Export-Package header (which pulls in classes and resources) with Embed-Dependency. You can easily end up with duplicated content: one pulled in, the other embedded. Instead, try to use the -exportcontents directive when you want to export packages contained in embedded dependencies.

A.2.4. Deploying artifacts to OBR

In addition to embedding, the maven-bundle-plugin has built-in support for the OSGi Bundle Repository (OBR; see section 10.1.2). Whenever you use Maven to build and install a project of packaging type bundle, the maven-bundle-plugin automatically updates an OBR index file (called repository.xml) at the top of your local Maven repository. You can use this file to select and deploy your project bundles onto OSGi frameworks:

-> obr-repo add-url file:/Users/foo/.m2/repository/repository.xml
-> obr-repo list
-> obr-resolver deploy ...

You can even use it to remove stale bundle entries from your local OBR:

$ mvn bundle:clean

But how about non-local OBRs, like the one listing official Apache Felix bundle releases at http://felix.apache.org/obr/releases.xml? You can configure the maven-bundle-plugin to automatically update a remote OBR whenever it deploys a bundle to a remote Maven repository, but this isn’t enabled by default. For more details about enabling and configuring remote OBR updates, see the plugin documentation on the Apache Felix website.

A.2.5. Bundling non-JAR projects

What if you don’t want to change your project packaging type to bundle? Can you still get Maven to generate OSGi metadata for you? You’ll be pleased to hear that the answer is, yes—the maven-bundle-plugin provides a manifest goal that you can use to generate the OSGi manifest during other types of builds. To allow the use of this goal with other packaging types, you first need to tell the maven-bundle-plugin to process them, like so:

<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
  <supportedProjectTypes>war,ear,jar,zip</supportedProjectTypes>
</configuration>

Next, add an plugin execution to generate the manifest as part of the build lifecycle:

<executions>
  <execution>
    <phase>prepare-package</phase>
    <goals>
      <goal>manifest</goal>
    </goals>
  </execution>
</executions>

Finally, you need to get Maven to include the generated manifest in the final artifact. Exactly how this happens depends on the packaging you’re using, but most archives support some way to use an existing manifest file.

You’ve now built bundles using Ant and Maven. What about other build tools and IDEs?

A.3. For your consideration

Bnd and the maven-bundle-plugin aren’t the only option when developing OSGi bundles. As you saw back in chapter 7, Eclipse includes support for developing bundles courtesy of its Plug-in Development Environment (PDE). NetBeans and IDEA also provide add-ons for OSGi, and there are additional Ant tasks and Maven plugins specifically designed for developers targeting Eclipse or Spring. Whatever your workflow, you should be able to find something that works for you.

Let’s take a quick look at the alternatives currently available, starting with Eclipse PDE.

A.3.1. Eclipse PDE

The PDE (www.eclipse.org/pde) adds a new perspective for developing Eclipse plug-ins, but it can also be used to build plain OSGi bundles. Unlike bnd, which generates a manifest based on a small recipe of instructions, Eclipse PDE provides dialog boxes and wizards for working directly with the manifest. What you see is what will appear in the bundle. Although this often leads to simpler manifests, it also means you have more responsibility for keeping the manifest up to date. PDE helps by integrating closely with the Java development tools, but you do need to invest significant effort to do headless builds.

A.3.2. Apache Felix Sigil

Sigil (http://felix.apache.org/site/apache-felix-sigil.html) is a tool that applies the OSGi modularity concepts to the build environment. It extends build-time resolution technologies such as Maven and Ivy to resolve project dependencies primarily using the same Import-Package semantics encouraged by OSGi best practices. This leads to a greater degree of decoupling and has been shown in real-world scenarios to reduce extraneous dependencies by up to a factor of 10 compared to module-level dependencies. The Sigil project structure encourages delegation to avoid duplicated configuration and supports a flexible repository management framework. Sigil integrates with Eclipse and Ant/Ivy.

A.3.3. Eclipse bndtools

Bndtools (http://njbartlett.name/bndtools.html) is an alternative to Eclipse PDE based on the bnd tool. It provides dialog boxes and wizards for managing bnd instructions in Eclipse as well as menu options to run, test, and debug OSGi applications. Developers already used to bnd should have no problem picking up bndtools; others will find its forms, syntax highlighting, and auto-completion a useful introduction to building bundles from recipes.

A.3.4. IDEA Osmorc

Osmorc (http://www.osmorc.org) is a plugin for IntelliJ IDEA that lets you choose whether to use an existing manifest for your bundle or have the IDE generate it. Osmorc can generate a manifest based on either a simple form or a set of bnd instructions. You can also use it to run and debug OSGi applications on all the major frameworks.

A.3.5 NetBeans Netisgo

Netisgo (http://netbeans.org/features/java/osgi.html) is a plugin for NetBeans that forms a bridge between the NetBeans module system and OSGi. It allows native modules and OSGi bundles to interoperate by mapping their metadata at runtime. Net-Beans also provides templates for simple Ant- or Maven-based OSGi builds.

A.3.6. Maven Tycho

Tycho (http://tycho.sonatype.org) is a collection of plugins specifically developed for building Eclipse plugins, applications, and update sites in Maven. Its primary goal is to make the command line build match the Eclipse IDE build by replacing the standard Maven dependency resolution by a P2-based resolver. Developers can choose between an Eclipse style manifest-first approach or a maven-bundle-plugin style pom-first approach. Management of target platforms is also much easier with Tycho: add your required dependencies, and it will compute and download the appropriate target platform for you.

A.3.7. Spring Bundlor

Bundlor (http://www.springsource.org/bundlor) is an alternative to bnd that works with Ant, Maven, and Eclipse. Like bnd, it generates the bundle manifest from a recipe and uses instructions based on OSGi headers, but it uses a different syntax to control the results. Bundlor also scans non-Java dependencies like Spring or Blueprint configuration files to find references that don’t appear in Java code but still need to be imported into the bundle.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.186.79