Time for action - creating the project POM

The next step is to create the pom.xml file, which tells Maven and the Felix plugins how to build this project.

The Project Object Model (POM) is located in the project base directory (in this case, under com.packtpub.felix.bookshelf-inventory-api).

Create a file named pom.xml. You will edit its contents as we go through their meaning in the coming sections.

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

The first part is common to all POMs; it's the XML schema information and the POM model version.

The Bundle identity

Next comes the project identification; this information will be used in the construction of the bundle JAR, as well as for referring to it from other projects as a dependency.

The artifactId will be used in the naming of the packaged JAR and will also be used in the generated manifest metadata as the Bundle-Name:

<groupId>com.packtpub.felix</groupId>
<artifactId>com.packtpub.felix.bookshelf-inventory-api
</artifactId>
<version>1.5.0</version>
<packaging>bundle</packaging>
<name>Bookshelf Inventory API</name>
<description>Defines the API for the Bookshelf inventory.
</description>

The previous syntax says that we're working with the com.packtpub.felix.bookshelf-inventory-api bundle artifact, which is in the com.packtpub.felix group and currently having the version 1.5.0.

The packaging element tags this project to be treated as a bundle when packaging the artifact. This will be picked up by the Felix plugins (we'll set those up in a short while).

More on bundle versions

Versions are used to distinguish between multiple releases of the bundle. In its simplest form, a version would be a number that grows sequentially between releases of the bundle, also called major releases.

In the most complete form, the version is made of dot separated parts the major, minor, micro, and qualifier parts. The major, minor, and micro parts are numbers, and the qualifier part is alpha-numeric and allows underscore (_) and dash (-). For example, 1.618.p-5 is a valid version for a bundle, and so are 1.1, 3.4.1, and 2.

The idea is to be able to encode in the bundle version information about the relative differences between releases of the bundle. This information allows making decisions about whether to update to a newer release of a bundle or not.

When a new release of a bundle comes out with no changes to its API, it means that it mainly addresses bug fixes. This is reflected in an increment of the micro version. When a backwards compatible change is made to the code (that is, a component depending on the previous version can use this one without changing it), the minor version is incremented.

For example, say you have Bundle A that holds Class X and another bundle, B, that uses the method doThat() from Class X. Bundle A was released with version 1.3.0. However, there's a bug in method doThat().

More on bundle versions

When a new version of Bundle A is released with the fix to that bug being the only change (that is, the API has not changed), it is released with version 1.3.1 (increment to the micro version part). We know that Bundle B can use this new version safely by a mere inspection of the new version.

More on bundle versions

In this scenario, versions 1.3.0 and 1.3.1 are interchangeable a bundle that depends on the bundle with version 1.3.1 can use that with version 1.3.0. In this example, this would not make sense because we know that version 1.3.0 was buggy and the bug was fixed with version 1.3.1. However, in some cases, a micro release may have introduced regression defects and the previous version would be more desirable.

In this same example, adding a method to Class X, say addItem(), is a backwards compatible change, that is, parties that were dependent on the previous version are not affected by upgrading to this one. All the methods that they need are still there. The result is a release of the bundle with version 1.4.0.

More on bundle versions

In a typical development process, the version of a bundle is important in order to follow its progress and to reflect on its backwards compatibility with previous releases. Of course, the version provides a hint of the kind of change that occurred. The release notes would contain more details on the actual changes.

There are a few factors that may impact compatibility, the main driving logic being the work required for the integration of the updated bundle. Here are a few examples:

  • Changing the implementation of a method is typically both forwards and backwards compatible. The bundle requires regression testing and some validation end-to-end testing.
  • Adding a method to an interface is backwards compatible when the third party uses this interface. However, it is not the case when the third-party extends it, as it will require development for the integration of the changed bundle.
  • Making a bean attribute optional when it was mandatory is backwards compatible, however, the opposite is not.

The above highlights the importance of keeping a close eye on dependencies and their versions, as well as documenting the usage of each dependency.

As mentioned earlier, in our case, to make the mapping between the released bundles and the book chapters easier, we will use the chapter number as a minor version for the bundle. Therefore, the first released version of a bundle will not be 1.0.0. As the changes made through the chapters are all backwards compatible, this does not break the versioning schema. However, it provides an easy reference back to the chapter in which this bundle was released.

Let's go back to our POM now and look at its dependencies section.

Dependencies

The dependencies section of the POM lists the components that this artifact depends on. It identifies each of those dependencies by specifying their groupId, artifactId, and version.

The scope of a dependency defines whether the dependency is required at compile time (default), at runtime, during the unit and integration testing phase (test), whether the dependency is already available on the target platform (provided), or that the dependency JAR is explicitly provided on the filesystem (system ).

This bundle doesn't have any dependencies yet. Therefore, its dependencies section is empty:

<dependencies>
</dependencies>

Later in this chapter, when working on the inventory implementation, we'll see an example of a dependencies section that's not empty.

Customizing the build

We had tagged this project with the bundle packaging in the identification part previously. This packaging type is a custom packaging (that does not come with the default Maven distribution). It is defined by the maven-bundle-plugin provided by the Felix project.

The maven-bundle-plugin attaches to some of the goals in the build lifecycle and assists in the creation of the bundle. For example, it will generate the manifest OSGi headers based on the analysis of the code and the directives provided in the plugin configuration part of the POM.

To instruct Maven to use this plugin during the build process, we add it to the build plugins section in the POM:

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

The configuration section tells the plugin how to generate the bundle manifest file including OSGi-related information. Here, the Bundle-Category and Bundle-SymbolicName are set:

<configuration>
<instructions>
<Bundle-Category>sample</Bundle-Category>
<Bundle-SymbolicName>${artifactId}
</Bundle-SymbolicName>

The ${artifact} is Maven's way of requesting the substitute with the value of the artifactId in this POM.

I've picked sample as the bundle category, but we could have categorized it as inventory to reflect its purpose. This attribute has no functional impact.

This bundle will provide the com.packtpub.felix.bookshelf.inventory.api package for export. It will be imported by the inventory implementation and the bookshelf bundles.

<Export-Package>
com.packtpub.felix.bookshelf.inventory.api
</Export-Package>
</instructions>

The remoteOBR element provides the plugin with the name of the distribution management repository (see the following section):

<remoteOBR>repo-rel</remoteOBR>
<prefixUrl>
file:///C:/projects/felixbook/releases
</prefixUrl>
</configuration>
</plugin>

The plugin will update a repository.xml file on that distribution repository and use the prefixUrl for references to the bundle artifacts.

We'll also keep a tight check on which Java version we're using as this is a good practice to avoid later integration and deployment issues. The plugin that Maven uses during the compile phase is the maven-compiler-plugin. Here we configure it to use source compatibility and to generate bytecode for Java release 1.5; this is similar to using the -source and -target options of the javac tool.

<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

Defining the distribution parameters

The last item we need to look at in the POM is the definition of the bundle distribution management section. The distribution management section is used during the deploy phase of a build and tells Maven where the packaged bundle is to be deployed.

<distributionManagement>
<!-- releases repo -->
<repository>
<id>repo-rel</id>
<url>file:///C:/projects/felixbook/releases</url>
</repository>
</distributionManagement>
</project>

That's it for the setup of the project POM. Let's move on to the Book bean interface definition.

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

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