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.
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).
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().
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.
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.
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:
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.
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.
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>
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.
18.118.152.58