Wednesday, 20 April 2011

OSGi Bundle lifecycles

One aspect of the OSGi model which distinguishes it from say Java EE, is the OSGi bundle lifecycle.  During the last few OSGi sessions I have presented, the bundle lifecycle has always been of interest and has often been the source of many questions, so I thought I’d talk about it in a blog post :o).  The easiest way of describing the model is to dive straight into the state diagram that describes the lifecycle.


The diagram, as with any state transition diagram, shows the possible states an OSGi bundle can be in at any time within an OSGi framework, along with the possible transitions it could make to other states.

There is one way into the state diagram (signified by the black blob at the top), and one end state (UNINSTALLED).  These are the ways which a bundle enters and exits an OSGi framework.

I’m going to use the Geronimo OSGi runtime that was created in an earlier blog post to show a bundle going through the various lifecycle states (feel free to run on just the OSGi frameworks if you wish - although the commands will be subtly different).  First, I’ll remove the bundles that were added in the last tutorial by running the following command from the /opt/geronimo/geronimo-tomcat7-javaee6-3.0-M1 directory (alter the file locations to suit your dir structure).

./bin/deploy –u system –p manager undeploy org.apache.aries.samples.blog.jpa.eba

Right, we now have a clean deployment, so lets install a bundle out of the aries blog sample.  Extract the bundles from the .eba file and install the biz bundle into the framework.  Run the following command from within the Geronimo console:

install file:///opt/geronimo/geronimo-tomcat7-javaee6-3.0-M1/org.apache.aries.samples.blog.biz-0.2-incubating.jar

You should have been returned a bundle id.  Type list and the biz bundle will now be the last in a long list of bundles.  Notice it’s in INSTALLED state.  We’ve reached the first state in the lifecycle diagram, above.  If we try to resolve the bundle by running the resolve command, the bundle remains in the INSTALLED state as the current OSGi framework does not contain the required bundles to satisfy the biz bundle’s requirements.  To check which dependencies the bundle is missing, try to start it by running start <bundle id>

Lets now install the API bundle:

install file:///opt/geronimo/geronimo-tomcat7-javaee6-3.0-M1/org.apache.aries.samples.blog.api-0.2-incubating.jar

If we view the list of bundles again we notice both our new bundles are in the INSTALLED state. However if we now try to resolve all bundles in the framework, by calling resolve. We notice that both bundles have now transitioned into the RESOLVED state.  This means that the bundle dependencies from both bundles have been met by the existing bundles in the OSGi framework. 

Install the final two bundles and resolve them:

install file:///opt/geronimo/geronimo-tomcat7-javaee6-3.0-M1/org.apache.aries.samples.blog.persistence.jpa-0.2-incubating.jar

install file:///opt/geronimo/geronimo-tomcat7-javaee6-3.0-M1/org.apache.aries.samples.blog.web-0.2-incubating.jar

resolve

Next we can actually start the bundles, by running start <bundle id> for each bundle in turn. Once all have been started, run the list command to ensure they are all in the ACTIVE state and then go to the blog sample webpage to make sure the blog is running.  You are also able to start a bundle from the installed state if it can resolve its dependencies. The framework will resolve the bundle first and then start it.

Right, so lets have a bit more of a play… lets stop a bundle and see what happens - First let’s stop the persistence bundle.  We’d expect the server to get to the web content as the web bundle still exists, however it will likely fail much beyond that.  Go to the webpage again, and you should see an exception from the web bundle part of our application stating the BloggingService is unavailable. This is because the BloggingService requires another service that was provided by the persistence bundle and therefore no longer exists in the service registry.  We should restart the persistence bundle and check the webpage to ensure we're all working again.

Let’s now stop the API bundle, by calling stop <bundle id> and they try to access the webpage again. Still working?  OK, lets go a stage further and uninstall the API bundle, by calling uninstall <bundle id>.  Check the webpage… Still working? Good isn’t it :)  This works because the consumer bundles that use the API bundle have previously cached the code it requires from it's dependencies, the API bundle.  The API bundle does not register any services, so the other bundles will not miss them, meaning the app can continue to run without the API bundle existing in the environment until a refresh is called on the OSGi framework.  The refresh wires up the new dependency map, refreshing the caches, which now will not include the API bundle.  This test was designed to show that the dynamism of OSGi is in the services rather than the bundles.  Yes, they are linked, without bundles there would be no services.

We can also uninstall bundles that are in the ACTIVE state.  Again, the framework will call stop on the bundle under the covers to get it into the RESOLVED state first and then uninstall the bundle.  The bundle is then back to the black blob at the start of the lifecycle :o)

Tuesday, 5 April 2011

Enforcing OSGi Modularity

Tom Watson is an IBMer based in the U.S. and a co-lead of the equinox project in eclipse.  He has kindly put together a presentation for our EnterpriseOSGi YouTube channel on how OSGi uses modularity.  Do go and take a look here.