The most common question I've heard regarding OSGi is how do I carve my application into bundles? There is no clear cut answer, but I typically look at functional subsystems within the enterprise (shipping, fulfillment, billing, etc...) and then at the horizontal slices within those systems (presentation, services and persistence). This will tend to provide a good balance for dealing with change and running efforts in parallel without introducing too much complexity. In order to share business objects across separate bundles within the system, we'll need to carve out a domain bundle that others can use.
I'll use pax-construct in these examples as it provides bundle management on top of maven in a relatively intuitive and easy to use fashion. The steps are relatively short to get up and running with a domain bundle.
Start out by creating the project using pax-create-project
This command will setup a maven project for this OSGi system using an OSGi archetype. From here you may want to update the main pom.xml to generate eclipse project and classpath files, update the compiler version used by Maven, and switch it to use equinox over felix as the OSGi container. The main pom.xml will then resemble this
<?xml version="1.0" encoding="UTF-8"?><project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.pillartech.raffle</groupId><artifactId>raffle</artifactId><version>1.0-SNAPSHOT</version><name>com.pillartech.raffle (OSGi project)</name><description>Generated using Pax-Construct</description><properties><org.osgi.service.http.port>8080</org.osgi.service.http.port><org.osgi.service.http.port.secure>8443</org.osgi.service.http.port.secure></properties><packaging>pom</packaging><modules><module>poms</module><module>provision</module><module>domain</module></modules><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.6</source><target>1.6</target></configuration></plugin><plugin><groupId>org.ops4j</groupId><artifactId>maven-pax-plugin</artifactId><version>1.4</version><configuration><provision><param>--platform=equinox</param></provision></configuration><executions><execution><id>ide-support</id><goals><goal>eclipse</goal></goals></execution></executions></plugin></plugins></build></project>
After the main project is created pax-runner will be able to start an osgi container from this folder and automatically deploy any homemade or imported bundles automatically. Before we do that, let’s give it something to deploy. Run pax-create-bundle from the main project directory, keeping the group id the same as the one you used when creating the project.
The pax-create-bundle command will create a familiar project structure for anyone who has used maven. From here you can explore the sample code, delete it when ready and then create your domain classes. My simple example just has two domain classes an Entry and a Raffle. If you are creating domain objects that are not anemic, you’ll probably have a good chance of needing some third party libraries. In my code I planned on using the commons-lang libraries for their equals and hashcode builders. When presented with the need for an external jar in an OSGi environment, you have to ask yourself if this should be embedded into your own bundle as a dependency or installed as a separate bundle within the container. Both have pros and cons, but the decision boils down to whether you feel this jar will be used by other bundles within the system. The commons-lang jars are only useful right now in our domain bundle so we’ll embed. Just update your pom.xml file with the dependency and maven will take care of bringing the external jar into a repository and ensuring that it’s compiled into your bundle. Now is also a good time to add a test dependency on TestNG or JUnit and write some unit tests around the logic in your domain classes.
One other thing to note before deploying this bundle. Pax Construct will make use of BND to generate the manifest file. BND scans the source files, generates an import list, and provides sensible defaults for the manifest so that you don’t have to roll it by hand each time. Since we are just using our domain bundle as a standalone bundle to be consumed by others and it doesn’t have a service or activator, you can simply nuke the generated line in the osgi.bnd file. If all has gone according to plan so far, the last thing is to fire it up. From the main project directory you can run mvn install to compile the domain and then run pax-provision to start up the container and deploy your bundle. Hopefully you get a slew of nifty ascii art indicating that pax-runner has successfully started up and you are greeted with an OSGi prompt. Issuing a short status command if you are using equinox should result in 2 happily active bundles:
So far we’ve created a project, learned how to use pax-construct, embedded a third party jar, and created a bundle that is relatively useless by itself. In the next post, we’ll see how to make use of that bundle from another.
Code samples are available on github.