Tech Ads

Back to Article List

NOTE: BEA was acquired by Oracle, so Dev2Dev became part of OTN

Originally published December 2007 [ Publisher Link obsolete ]

OSGi on the Server Side


Since BEA became part of Oracle, Dev2Dev was taken off-line and became part of Oracle's developer site OTN. In light of this, you can only find a copy of the full article here.

Abstract

Formed in 1999, the OSGi alliance made its first steps into the Java market within the embedded device segment. Years later it further extended its reach to Java desktop projects, providing a major foundation for the modularity and extensibility of the Eclipse open-source IDE project. Now, as the service's era dawns up on us, OSGi is stepping into its latest Java frontier: the server side.

Like many other alliances in the tech industry, OSGi's best practices and development policies are dictated by consensus among its many member companies. And in the case of OSGI's server side presence, numerous prominent Java vendors have already started shifting their SOA product lines around OSGi blueprints, one such case being BEA's own microService Architecture (mSA) which relies on OSGi for its backplane components.

This article will address why OSGi has stepped into Java/SOA server side initiatives, including its main benefits and constraints as Java vendors shift their SOA focus to OSGi. It will also provide an in-depth look at what exactly constitutes working with OSGi from a developer and architect point of view, as well as OSGi's future role with Java in the broader sense of the platform.

OSGi key concepts

With much of OSGi's principles successfully applied to everything from smart phones to IDE's(Integrated Development Environments), it can be difficult to sum-up every OSGi aspect in a few sentences, however, the following key concepts should be enough to give you a feel for OSGi's overall place in the Java ecosystem

  • The environment and framework : OSGi is often categorized as a Java framework, however, don't let this often overused word in the Java world make you pigeonhole OSGi along side the now hundreds of frameworks available to ease everything from Java web development to Java testing, OSGi crosses this boundary, effectively providing an ad-hoc environment that facilitates modularizing an application into smaller and more manageable pieces.
  • The JVM companion: Since OSGi's roots are in the embedded market, it should come as no surprise that OSGi's primary focus is on boosting the capabilities of the lowest common denominator in Java: The Java Virtual Machine. While the JVM has more than a decade of engineering behind it, for certain tasks -- such as system services and dynamic loading -- it has fallen shy of the expected curve in some vertical industries, giving way to initiatives like OSGi to fill in feature gaps.
  • The Java packaging bundle: Of course no environment or framework is exempt from having its own packaging model, so just as you may have become accustomed to dealing with WAR(Web Archives) and EAR(Enterprise Archives while working with Java EE applications, or the more general purpose JAR(Java Archives) on your Java projects, so to OSGi has its own packaging model which goes by the name of a "bundle". For now, don't worry to much about what makes up a bundle -- we will get to that in a little while -- just be aware that the term "bundle" practically goes hand in hand with OSGi.

Bearing in mind this is but just the tip of the conceptual iceberg behind OSGi rather large scope, lets move ahead and address what OSGi brings to the table on the server side.

Why OSGi on the server side: SOA and complexity.

If you look at the current state of affairs in the server side Java market, you will notice there has been a marked shift toward enabling service orientated architectures(SOA) in the enterprise. While this has been classified as a cataclysmic change by some and by others as a natural evolutionary step, one cannot deny SOA has brought on a new way of thinking about how applications are created and deployed, and as a consequence, rethinking the same infrastructure used to support such an architecture.

A quick glance at the infrastructure used in the enterprise for enabling a SOA, will reveal a mix of Java EE containers, lightweight frameworks and other such middle-ware for this purpose, while there is nothing wrong with this infrastructure per-se, the way in which such software is deployed makes for a monolithic -- all or nothing -- approach which goes in part against the SOA tenets of nimbleness and re-usability.

Most Java applications are manageable enough in isolation, the real issues start to arise once these seemingly simple pieces are placed in production environments alongside other Java parts, or if you will, the service orientated cloud for the enterprise. The way in which enterprise Java middle-ware and the JVM work in these scenarios, is the all or nothing concept, giving way to a few obvious headaches:

  • Bloated memory foot-prints: With some Java application deployments requiring a hefty 1 or 2 GB of memory -- on occasions more -- to run properly in enterprise settings, this creates a resource black-hole on the server side in proportion to the amount of applications that need to be deployed in a single server instance.
  • Class/Versioning conflicts: Evolving software pieces are another predicament under these scenarios. With everything loaded under the same umbrella -- JVM and classpath -- the greater the number of applications deployed in a single server instance, the greater the possibility applications might use different staple libraries -- JAR files -- making for a sure recipe to class loading and versioning conflicts.
  • Duplicate or unnecessary parts: All application owners take care of providing the necessary dependencies for proper execution, however, once applications are deployed in production environments, it can become quite difficult to determine if certain dependencies aren't already being met by some other application or if an application is actually using 100% of the dependencies intended by its creators.

Now, if there were to be a common solution to all the previous points it would be that of dynamic loading, a mechanism by which the building blocks of an application could be determined on-the-fly, limiting resource consumption to only those essential pieces required for proper operation. As it turns out, OSGi growing up from the resource-starved embedded market offers precisely this, an extremely efficient way of installing, starting, stopping, updating and un-installing modules on an as needed basis.

With this, OSGi creates an excellent symbiosis between the JVM -- which currently lacks such dynamically loading and versioning features -- and the more heavyweight Java enterprise applications which are often brought to a grind given their more complex dependencies. [ NOTE to Jon , the following is what I assume BEA has intended for OSGi, a further proof-read by someone internal at BEA would be best to corroborate] In the case of BEA's microService Architecture relying on OSGi for its backplane components, what this implies is that BEA's product line will be homogenized into numerous OSGi bundles, effectively enhancing the way its numerous parts interact amongst each other and limiting possible versioning and class loading conflicts that may arise when deploying the full stack of BEA products.

Here again, the implications behind using OSGi in this context are a little bit simplified, but the high-level view should be enough for you to grasp what OSGi is intended to solve. So with that said, lets move onto what makes up the moving parts behind OSGi : An environment and its corresponding bundles.

OSGi's working parts: Environment and bundles

An OSGi environment provides the necessary 'black-box' to take advantage of the many aforementioned features. In this case, I opted to use the term 'black-box' because the creation of an environment falls entirely on the shoulders of an OSGi vendor/provider, in much the same way Java EE containers fall into the realm of vendors. As a developer or architect, your only concern should be understanding the deployment and programming models behind OSGi, which can be equally leveraged across any OSGi environment of your choosing -- in a strikingly similar fashion to Java EE.

For those of you who have moved beyond Java EE containers, and onto lightweight frameworks like Spring, don't be put of by the last comparison between Java EE containers and OSGi environments, as there is in fact relevance and undergoing work to integrate OSGi's capabilities with those of Spring, as we move along you will be able to glean how your Spring projects can also benefit from OSGi. Be advised that in OSGi the terms: 'environment','implementation','run-time','container' and 'framework' are often used interchangeably, just keep an open-mind on the lexicon as these often refer to the same piece of software distributed by an OSGi vendor/provider.

Once your start exploring OSGi environments, you may be surprised to learn that the same environment capable of being used on something as small as a smart phone, can also be used to manage a desktop application as well as your server-side projects, the reason for this is that OSGi's deployment and programming model is equally applicable under all these different scenarios, which brings us to the most concrete of parts in OSGi: A bundle. Grasping the concept of a bundle is a critical step to understanding OSGi, since it will be what you as a developer or architect will be dealing with directly most of the time, so with that said, here is a brief introduction on the concept followed by a hands-on example.

A bundle -- also often referred to as a module -- is the packaging format used in OSGi that contains Java classes, resources, as well as other processing instructions used by an underlying OSGi environment, a packaging which in itself has a very similar structure to that of a JAR file. Which begs the question, what is so special about an OSGi bundle if its packaged in the same way as a JAR file ? Or better yet, why on earth would you re-package all your existing application JAR files to comply with an OSGi bundle JAR format ?

OSGi image

As it turns out, the contents of an OSGi bundle JAR file -- or simply OSGi module -- which are Java classes and other application resources, are not made available via the classical Java classpath, instead they are delegated to an OSGi environment which then creates a type of class loader graph aimed at resolving dependencies between all the underlying classes and resources contained in each OSGi bundle JAR file deployed onto an OSGi environment.

This concept of a class loader graph is special for a few reasons, for one it limits the amount of Java classes and resources that are loaded at any single point in time during the execution of an application, and by relying on a graph model, any application running within an OSGi environment can automatically create, merge or destroy branches on an as needed basis in order to fulfill class dependencies, giving way to the dynamic install, start, stop, update and un-install capabilities mentioned at the outset. Equally important is the fact that since OSGi bundles are composed of plain Java classes and resources, an OSGi environment is agnostic to the underlying application logic, so it is you may encounter OSGi bundles ranging from an Eclipse IDE plug-in, an XML parser, a console-based application, a Servlet, to some other variation.

Armed with this background, now its time to take a look at an actual OSGi bundle. Since we are dealing with an introduction on OSGi bundles, the examples presented here are as stripped down as possible, however, as you move along the examples, try to extrapolate how these same principles would apply to more elaborate bundles in the enterprise space, such as a Logging package, Servlet engine, or some other variation.

The bundle we will now create is designed as a flight carrier service, which will in turn be available to other OSGi bundles for obtaining seating availability to certain cities.

package intro.carrier;

import java.util.Properties;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceEvent;

import intro.carrier.service.FlightService;

/**
 * This class implements a simple bundle that uses the bundle
 * context to register international flight availability service
 * with the OSGi framework. The flight service interface is
 * defined in a separate class file and is implemented by an
 * inner class.
**/
public class Activator implements BundleActivator
{
    /**
     * Implements BundleActivator.start(). Registers an
     * instance of a flight service using the bundle context;
     * attaches properties to the service that can be queried
     * when performing a service look-up.
     * @param context the framework context for the bundle.
    **/
    public void start(BundleContext context)
    {
        Properties props = new Properties();
        props.put("Seating", "International");
        context.registerService(
            FlightService.class.getName(), new FlightImpl(), props);
    }

    /**
     * Implements BundleActivator.stop(). Does nothing since
     * the framework will automatically unregister any registered services.
     * @param context the framework context for the bundle.
    **/
    public void stop(BundleContext context)
    {
        // NOTE: The service is automatically unregistered.
    }

    /**
     * A private inner class that implements a flight service;
     * see FlightService for details of the service.
    **/
    private static class FlightImpl implements FlightService
    {
        // The set of cities contained in the flight service
        String[] c_flight =
            {"mexico city", "paris", "london", "sao paulo", "toronto"};

        /**
         * Implements FlightService.checkAvailability(). Determines
         * if the passed in city is available 
         * @param flight the flight to be checked.
         * @return true if the flight seating is available,
         *         false otherwise.
        **/
        public boolean checkAvaiability(String flight)
        {
            flight = flight.toLowerCase();

            for (int i = 0; i < c_flight.length; i++)
            {
                if (c_flight[i].startsWith(flight))
                {
                    return true;
                }
            }
            return false;
        }
    }
}

Right off the bat, notice we import numerous org.osgi.framework classes which represent the bread and butter of most every OSGi bundle, next, we declare two initial methods that are also central to OSGi: start and stop, which as their name implies, are invoked to either register and unregister OSGi bundles from the underlying environment. The remaining code is a straight-cut inner class used as the service logic, nothing fancy, just a few hard-coded values to serve our purpose and a dependency on the following interface:

package intro.carrier.service;
/**
 * A simple service interface that defines a flight service.
 * A flight service simply verifies the existence of seating.
**/
public interface FlightService
{
    /**
     * Check for the availability of a flight.
     * @param flight the flight to be checked.
     * @return true if the flight seating is available,
     *         false otherwise.
    **/
    public boolean checkAvailability(String flight);
}

That's all as far as Java code is concerned, now lets illustrate the OSGi descriptor which needs to accompany the previous Java classes:

Bundle-Name: International Flights
Bundle-Description: A bundle that registers International Flight service
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Bundle-Activator: intro.carrier.Activator
Export-Package: intro.carrier.service
Import-Package: org.osgi.framework

The name and description parameters are self-explanatory, the Bundle-Vendor parameter on the other hand, refers to the OSGi implementation that will be used for deployment, which in this case refers to the Apache Software's Foundation OSGi implementation named Felix. The Bundle-Version field simply represents our first bundle iteration 1.0.0

The remaining fields deserve a little more attention, Bundle-Activator refers to the class which contains the actual activation logic -- start and stop methods -- while the Export-Package is used to indicate which packages in the bundle will be made available to other OSGi bundles, in this case, we indicate that our service package be made accessible. Finally, Import-Package is used to indicate the dependencies which need to be loaded in order for the bundle to be deployed successfully.

Java code compilation is done in the same fashion as any other Java source file -- so long as the OSGi implementation is available in the compiling classpath -- while the actual creation of the OSGi bundle can be made using the standard jar utility included in Java SE. Our final packaged OSGi bundle would have a directory structure like the following listing :

+-|
  |
  +-META-INF-+
  |          |+MANIFEST.MF
  |
  |
  +-intro/carrier-+
  |               |+Activator$1.class
  |     	  |+Activator$FlightImpl.class
  |		  |+Activator.class
  |
  |
  +-intro/carrier/service-+
                          |+FlightService.class

It's a somewhat lengthy and mechanical process, a reason why we won't illustrate the remaining bundles used in our introductory application. You can refer to the sample download code which includes an automated build script for easing the creation of numerous sample OSGi bundles. The good news is that packaging an OSGi bundle is almost always a one time affair, just like a JAR file -- and in most cases, this will be done by a third party provider. Inclusively, there are already large repositories of OSGi bundles which offer everything from JMX, RMI to XMLRPC ready to be used in your projects, one such repository is Oscar Bundle Repository .

Ok, now that you have a handle on OSGi bundles, let's move onto actually running and deploying an application using bundles.

Running and deploying an OSGi application

The application we will now create is made up of four OSGi bundles, two of which contain business logic classes or services, another that contains a monitoring service for listening to events as they occur in an OSGi environment, and a final bundle which contains logic to invoke service calls and return results in a text-based format. Here again, bare in mind the variety of classes an OSGi bundle can contain, our bundles encompass both the server logic, client logic and an ancillary monitoring function, take a look at the sample download code so you can really get a feel for this, and see how easily we could have also included database logic or some other supporting function.

Running and deploying OSGi bundles is highly specific to the implementation you will be working with, in this sense, you can encounter everything from fancy GUI's for running and deploying OSGi bundles to command-line utilities. Since our OSGi bundles will be built targeting Apache's OSGi implementation named Felix, the following steps illustrate the deployment process from this implementation's command-line utility.

Once you have Felix 1.0 installed on you workstation, make sure you copy all the OSGi bundles created in the sample download to the Felix sub-directory named bundle. Next, move to Felix's top level directory and invoke the following command java -jar bin/felix.jar, after that you will be prompted with Enter profile name:, introduce any name that's to your liking -- its not that critical for our sample, if your on a *nix station, Felix will create a sub-directory by this name under your home directory/.felix directory to place the installed OSGi bundles.

After you type in a profile name, you will see the first loaded OSGi bundles on the command prompt. The sequence of events you have so far should look something like the following:

[Assuming inside top level Felix directory]
[web@ws_osmosis felix-1.0.0]$ java -jar bin/felix.jar

Welcome to Felix.
=================

Enter profile name: introtutorial

DEBUG: WIRE: 1.0 -> org.osgi.service.packageadmin -> 0
DEBUG: WIRE: 1.0 -> org.osgi.service.startlevel -> 0
DEBUG: WIRE: 1.0 -> org.ungoverned.osgi.service.shell -> 1.0
DEBUG: WIRE: 1.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 1.0 -> org.apache.felix.shell -> 1.0
DEBUG: WIRE: 2.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 2.0 -> org.apache.felix.shell -> 1.0
DEBUG: WIRE: 3.0 -> org.osgi.service.obr -> 3.0
DEBUG: WIRE: 3.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 3.0 -> org.apache.felix.shell -> 1.0
->

You are now interacting with an OSGi environment. At this point its worth mentioning what states an OSGi bundle can be in, an active state refers to a bundle being in the actual class loader graph mentioned previously, an installed state on the other hand refers to a bundle being ready for use or prepped to be included in the class loader graph, where as the resolved state refers to a bundle being dynamically loaded on account of a required dependency. Lets move on so you can see these states first hand, type in the command ps to look over the installed bundles:

-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.0.0)
[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.0)
[   2] [Active     ] [    1] Apache Felix Shell TUI (1.0.0)
[   3] [Active     ] [    1] Apache Felix Bundle Repository (1.0.0)

The previous listing indicates the Felix core bundles are active in the environment, now lets install our sample application bundles as illustrated in the following listing:

[Assuming sample bundles are located in Felix bundle sub-directory]
-> install file:bundle/listener.jar
Bundle ID: 4
-> install file:bundle/carrier.jar
Bundle ID: 5
-> install file:bundle/carrier2.jar
Bundle ID: 6
-> install file:bundle/userdesk.jar
Bundle ID: 7
-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.0.0)
[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.0)
[   2] [Active     ] [    1] Apache Felix Shell TUI (1.0.0)
[   3] [Active     ] [    1] Apache Felix Bundle Repository (1.0.0)
[   4] [Installed  ] [    1] Service listener (1.0.0)
[   5] [Installed  ] [    1] International Flights (1.0.0)
[   6] [Installed  ] [    1] Domestic Flights (1.0.0)
[   7] [Installed  ] [    1] Service Tracker-based flight client (1.0.0)

In this last listing, notice how our bundle display (ps) now indicates an Installed state for all our four application bundles. Now lets start bundle number 6 -- Domestic Flights -- and then start/call bundle number 7 to query a flight.

-> start 6
DEBUG: WIRE: 5.0 -> intro.carrier.service -> 5.0
DEBUG: WIRE: 5.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 6.0 -> intro.carrier.service -> 5.0
DEBUG: WIRE: 6.0 -> org.osgi.framework -> 0
-> start 7
DEBUG: WIRE: 7.0 -> intro.carrier.service -> 5.0
DEBUG: WIRE: 7.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 7.0 -> org.osgi.util.tracker -> 0
Enter a blank line to exit.
Enter flight: Seattle
Flight available to :Seattle
Enter flight: Atlanta
No flight available to :Atlanta
Enter flight:
-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.0.0)
[   1] [Active     ] [    1] Apache Felix Shell Service (1.0.0)
[   2] [Active     ] [    1] Apache Felix Shell TUI (1.0.0)
[   3] [Active     ] [    1] Apache Felix Bundle Repository (1.0.0)
[   4] [Installed  ] [    1] Service listener (1.0.0)
[   5] [Resolved   ] [    1] International Flights (1.0.0)
[   6] [Active     ] [    1] Domestic Flights (1.0.0)
[   7] [Active     ] [    1] Service Tracker-based flight client (1.0.0)
->

Starting both bundles is straightforward, and the client bundle performs as expected, prompting us for a city and answering with a text message of either Availability or No Availability, however, notice the final status on bundle number 5. Even though we didn't explicitly do anything to affect it, it now shows a Resolved state, the reason for this is that both bundle number 6 and 7 depend on the intro.carrier.service package which is only available in bundle number 5, OSGi simply took care of resolving what its active bundles needed, and switched the state behind bundle number 5 to Resolved indicating a dependency was fulfilled. If you wish, poke around installing, un-installing, starting and stopping all these numerous bundles, so you can further see how OSGi handles the process, feel free to type in help to obtain a list of all the available OSGi commands.

This sample flight application may seem trivial, but when you take this same principal and apply it to more elaborate environments like those in the enterprise, which can have hundreds our thousands of classes loaded simultaneously without necessarily having a need for them, the concept of OSGi discriminating against what needs to be loaded and when it needs to be done, can have powerful performance implications.

The blurry future: OSGi, Java Modules, JSRs, Java EE

Acknowledgments: Thanks to InfoQ, Peter Kriens, Alex Blewitt and Eric Newcomer, for their lively on-line discussions on these OSGi, JSR and Java EE specification insights.

The capabilities offered by OSGi are of course a boon when it comes to dynamic Java loading and the other services that the Java platform lacks, but this does not mean Java's standardized body, or what is the same, the people behind JSR committees have been "a sleep at the wheel" as they often say. There is in a fact activity on numerous fronts regarding OSGi's features, namely JSR-291 which relates to OSGi/Java integration, JSR-277 which is a standalone Java module spec -- similar in scope to OSGi -- and the wider encompassing JSR-316 which refers to the upcoming version for Java EE 6.

The blurry future as implied by the title, stems from the degree of acknowledgment each of these JSR initiatives has for one another. In terms of development maturity, its clear that OSGi related technology -- hence JSR-291 -- is further along the lines than the one related to Java modules -- JSR-277 -- the latter of which is set out to be part of Java SE 7. However, the critical acknowledgment part comes into play when one looks at the future and enterprise focused Java EE 6 spec -- JSR-316 -- given that it fails to mention OSGi related features, and simply defers any decisions in similar fronts, to the yet to be implemented Java module spec JSR-277 that is said will come to fruition in Java SE 7.

Of course, this blurry future is strictly pertaining to Java EE 6, being that the JSR 277 expert group -- Java module system -- has already stated it will strive to inter-operate with JSR 291/OSGi . All in all, OSGi is the most mature of the three -- thanks in part to its influence and adoption in other Java fronts of course -- so the question mark that remains is how will Java EE 6 and the Java module system -- which are still on the drawing board -- complement or integrate with OSGi.

Example Code

You can download the code associated with this article.

To install, unzip the downloaded file and make sure you have Java Ant and Apache Felix OSGi on your workstation. In the top level directory run ant all to build all the sample OSGi bundles, all bundles will be generated under the bundles directory. Next, copy all four sample OSGi bundles, under Apache Felix bundle directory (alongside Felix's included jar files), then fallback to Apache Felix top level directory and execute: java -jar bin/felix to initiate an OSGi command line session. When prompted, type in the profile name of your choice, you will then have an active Felix OSGi session, execute the commands presented in the article to install or un-install bundles, or type help to get a complete listing of available operations.

Summary

The OSGi alliance has been in existence for some time now, influencing a series of sectors that required the minuscule details of dynamic Java loading, as well as other fronts not covered by the standard Java platform. Now, with the emergence of service orientated architectures in the enterprise, server side Java developments are moving onto this same nimble and agile framework/environment to provide more robust application capabilities.

Having reviewed both the composition and creation of OSGi bundles, along with a comprehensive look at how to deploy and run OSGi bundles in an application, you should now be in an ideal position to realize the benefits and limitations of using OSGi in server side architectures, and with it, the influence OSGi has had and will continue to have on the Java platform as a whole.

References


Originally published December 2007 [ Publisher Link obsolete ]

NOTE: BEA was acquired by Oracle, so Dev2Dev became part of OTN

Back to Article List