It’s been a bit since I blogged last, but I wanted to discuss something I’ve been busy with lately. Inspired by a recent presentation by a friend of mine, Craig Walls, and the announcement by Ales Justin to support OSGi in JBoss 5, I decided to see what all the fuss is about. Perhaps you’ve heard all the hype lately surrounding OSGi, but I wanted to let readers know what they are in for should they decide to trek the OSGi path.

Part 1 will really just be an introduction to OSGi, so for those who have been watching OSGi for awhile now (the OSGi Alliance was founded in 1999!) feel free to jump in on the next entry. But, for those who are OSGi newbies, this will help to get the ball rolling.

So what is modularity all about?

Modularity is the basis of the OSGi world and each bundle is considered a distinct module. Essentially bundles are just standard jars which happen to register with the OSGi container on deployment.

  • They inform the OSGi container of what services they expose and what services they consume.
  • They run in the same VM and all invocations of the module are in-process calls (no remote invocations).
  • Modules are restricted in their interaction with one another as the OSGi container defines restricted class-loading policies (only allowing classes from a module to be exposed if they are explicitly exposed).

Bundles are not a fit for all cases and not all jars are required to be OSGi bundles. In fact using tools like the Apache Felix Maven OSGi Plugin we can choose to selectively embed dependencies directly into our bundles. But, in this case always consider the scope of the classes contained in those embedded dependencies as there are specific rules related to class-loading in the OSGi container.

When modularity counts

Modularity is important in cases where we want to limit what our clients can and cannot use. For example, looking at the Seam Booking Example, let’s say we add a payment service. We can define the payment service through an API, aptly named: PaymentService. There is likely a fairly extensive implementation behind the PaymentService necessary to validate forms of payment, authorize charges, etc, but the Booking application is really only concerned with authorizing payment (not the messy details).

public interface PaymentService {
  public boolean authorizePayment(Payment payment);
}

The details of the implementation should be hidden from the Booking application. Unfortunately, if the payment-service.jar is loaded into our classpath, we suddenly have access to not only the interface, but all the implementation classes as well. So there is nothing to stop developer A from directly instantiating and invoking PaymentServiceImpl. And when developer B changes the name of this class and its implementation months down the line suddenly we have a break.

OSGi solves this by only providing visibility to the services which are exposed by a bundle. This makes things simple in the following package structure:

payment-service
- src/main/java
    - com.solutionsfit.payment
         PaymentService
    - com.solutionsfit.payment.internal
         PaymentServiceImpl
         ... ...

Notice the package structure above. The PaymentService interface is separated from the implementation which is in general good practice, but externalizing one package or the other has never been enforced. So how can it be done with OSGi?

Remember that crazy MANIFEST.MF file that perhaps you looked at one time to see what was in there. Or maybe you just noticed it sitting there and never bothered to look at it (Maven generates it for us anyway right!?). OSGi introduces some specific entries into the MANIFEST file that defines exactly what packages are imported and exported. So for our example above our manifest may look something like:

Manifest-Version: 1.0
Bundle-SymbolicName: com.solutionsfit.payment-service
Bundle-Name: Payment Service
Bundle-Version: 1.0.0
Bundle-Description: Payment Service
Import-Package: org.apache.commons.lang
Export-Package: com.solutionsfit.payment
Build-Jdk: 1.5.0_15
Bundle-ManifestVersion: 2

These entries simply let the container know what they require from other modules to execute:

Import-Package: org.apache.commons.lang

And what they make available to other modules:

Export-Package: com.solutionsfit.payment

Notice that we haven’t specified anything earth-shattering here. All we’ve done is said that we require commons-lang to be provided to us and we are making the com.solutionsfit.payment package available to others. Note that I don’t state where the dependencies come from! This means that in the above case any registered bundle could export the package that I use. You can also specify a version to be more specific:

Import-Package: org.apache.commons.lang;version=”2.4.0″

This allows multiple bundles to export the same package but we only use the version we are interested in. This becomes very useful in addressing dependency version issues between jars. Here bundle A can depend on 2.3.1 while bundle B depends on 2.4.0 and the OSGi container enforces this restriction for us. In the example above by not specifying a version, the latest version registered by a bundle will be chosen.

Note in our diagram above that the PaymentService is the only class available to the org.jboss.seam.example.booking bundle. This is because we explicitly specified that its package should be exported meaning that the OSGi container makes it visible to other bundles.

This all looks very Maven-ish to me…

Your right! The naming conventions and versioning are very similar to Maven and they fit well together. In general, the BundleSymbolic-Name is determined by appending the group-id and artifact-id of your Maven POM. The version is just stripped directly from the POM, so it all fits. In fact, if you want to make your jar a bundle, simply create a /src/resources/META-INF/MANIFEST.MF file by swapping in your project details in the entry above and add the following lines to your POM:

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifestFile>
              src/main/resources/META-INF/MANIFEST.MF
            </manifestFile>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

The next packaging of your project will be a OSGi bundle. Of course, the Apache Felix plugin mentioned previously provides a much more automated approach, but if you are into manual entry (sometimes the best way to learn), this approach will certainly work.

So besides visibility, what does this buy me?

Imagine the Booking application is running in production and your customers are happily booking trips to their favorite vacation destinations. You have realized that there is a critical bug in the production payment service that could result in substantial losses for your company. Do you bring down the application for temporary maintenance and perhaps lose those customers? No way!

With OSGi there is very loose coupling between the bundles. While OSGi will simply provide back a direct reference to the object registered by the bundle, this allows helpers like Spring-DM to proxy the PaymentService that will force the org.jboss.seam.example.booking to wait should the service go down.

If we simply replace the bundle with a bundle that includes the fix, the container will unregister the old bundle and register the new bundle. The proxy can then handle the reference shuffling and resume the service invocation.  This interaction will be almost instantaneous. Your customers will be completely oblivious to what has happened and you just saved your company a substantial amount of money (do I hear bonus?).

The diagram above obviously omits quite a bit of the magic of OSGi and hides some implementation details, but demonstrates the general idea.

Alright, alright, so all this stuff is very basic, where are the integration points! Don’t worry, in upcoming posts I’ll further discuss how the Booking application can use OSGi to simplify development.

Stay tuned…