Showing posts with label OSGi. Show all posts
Showing posts with label OSGi. Show all posts

Wednesday, January 14, 2009

How to Pull the Best out of OSGi - Even without OSGi!

Whew! When looking at my blog statistics I seem to have hit a hot topic with my last blog entry about OSGi...

I am delighted to see such attention in the community - because OSGi's principles are first class! I somehow got addicted about Peter Kriens and Oleg Zhurakousky's comments about "silver bundles". The world of the enterprise Java developer is a world of almost extreme diversity - When I start up a greenfield enterprise Java application, I have to decide from a huge variety of components. Most of us decide on an open-source stack - and there we hit the point - no "silver bundles" in our stack.

In this article I'll illustrate how to employ OSGi's modularity principles without using OSGi as the runtime platform - and therefore restore many existing library's "silver bundle" status. Needless to note that we will miss some benefits of OSGi. However, there's a good chance that you don't need these features (e.g. version conflict resolution or dynamic bundle installation
during runtime). Oleg noted that he does not think that "anyone in the right state of mind would deny OSGi" - and he's right - Therefore I do take special care that an application that follows these principles can be run within an OSGi runtime pretty easy once there is a need to turn over!

Everything's mentioned in this article is available as source code! I don't know how to deal with the sources yet. I would really like to contribute the stuff to SpringSource because I am convinced it's highly valuable for all Spring users - but they want to sell DM server - so it may not be their primary wish to promote such things in Spring core. If you find these things useful and if you think this would be a win for Spring core please leave a comment on this post! A comment to my last post noted another open source project (http://code.google.com/p/impala) that seems to have similiar objectives - maybe I will join Impala and contribute the stuff there. I'd be happy about any suggestions! In the meantime you can download the source code here:

Before I get started let me take two assumptions:
Assumption #1: Most applications do not need the high dynamics of OSGi. These applications may be redeployed in case new modules are available.
Assumption #2: Most applications do know the set of services they intend to use. They also know that they can or cannot operate if a service is not available in our current deployment scenario (e.g. the module containing the service is not deployed in this installation). In OOP terms: You either get an object connecting you to the service or you don't get such an object. You don't have to care about service objects suddenly vanishing at runtime.

These assumptions build the boundaries. If you have an application that needs to heavily load and unload modules at runtime and if you cannot predict who will contribute to your application (versioning conflicts, security, etc.) you will probably be perfectly happy with OSGi and you can stop reading. Eclipse is a perfect example. Please leave a comment if you know server-side applications with such requirements!

Enough of introduction ... Let's get started with the basic principles:
  1. An application is made out of a set of modules. A module is much like an OSGi bundle.
  2. A module provides services (described through Java interfaces) to others. The services ar instantiated by the module itself. Services are very much like OSGi services.
  3. A loader discovers modules (by convention or through rules in special deployment situations) and starts the modules.
  4. Constraints (e.g. published vs. private packages) are checked at build time.
Today, Spring DM would be my choice for OSGi development. To make a late turn to OSGi realistic and due to the fact that Spring is an essential part of many chosen open source stacks, a module is pretty much the same than a Spring DM module. The module ships with at least one application context where our objects are instantiated and our services are exported:

<!-- module internal stuff -->
<bean id="myService" class="com.blogspot.peterrietzler.internal.MyServiceImpl"/>
<!-- service export. supports a feature set comparable to Spring DM -->
<modules:service ref="myService" interface="com.blogspot.peterrietzler.MyService">
<modules:service-properties>
<prop key="someQoS">true</prop>
</modules:service-properties>
</modules>


Any other module may now reference our service. Here is an example using a plain reference matching any service and a reference matching only a service with a required quality of service (filters are RFC1960 - same as in OSGi):
<modules:reference id="myService" interface="com.blogspot.peterrietzler.MyService"/>
<modules:reference id="myService" interface="com.blogspot.peterrietzler.MyService" filter="(someQoS=true)"/>

You can also reference lists of services:

<modules:list id="myServices" interface="com.blogspot.peterrietzler.MyService"/>
<modules:list id="myServices" interface="com.blogspot.peterrietzler.MyService" filter="(someQoS=true)"/>

Modules are loaded independent of each other. Each module has it's own IOC container. This is important because this will allow aspects to be applied on a module scope (self-containment!). If a service is not available, e.g. because the module is not available in the current deployment, application startup fails. If your module can start without a specific service being available, then just mark it as optional and a null value or an empty list will be injected if the service is not available in your deployment:

<modules:reference id="myService" interface="com.blogspot.peterrietzler.MyService" optional="true"/>
<modules:list id="myServices" interface="com.blogspot.peterrietzler.MyService" optional="true"/>


When working with Spring DM you need to be careful with some parts of Spring, e.g. because Spring DM creates a proxy object for each bundle and other Spring components use the object's identities as keys in hashmaps. The Hibernate session manager is a pretty good example and
I leave it up to your own imagination what can happen if you have a Hibernate session manager exported as a Spring DM service :o). Additionally, Spring prototype beans are not supported to be exported as a service. To reduce these hard to recognize pitfalls there is some special support
for these two issues (note that this is not OSGi compliant and needs to be refactored to other design patterns in case of a turn over to OSGi).

  1. You can export a prototype scoped bean as a service. Each reference will be backed by one instance (behaves like in standard Spring).
  2. Each exported singleton service will be represented by the same object within all modules (behaves like in standard Spring).
Why bothering about this and why accepting something that does not match Spring DM / OSGi concepts ? Because these are really hard to observe pitfalls. Spring DM is so close to Spring that you intuitively think that you can do the same things as you can do with standard Spring. In fact
there are some very subtle differences. You can e.g. run into situations where your application seems to work but behind the scenes it just seem work because it falls back to some (in this case unwanted) default strategies (such as creating a new Hibernate session and database transaction for each method call in your data access layer).

Last thing is module loading. I follow the Spring DM conventions: By default all XML files in the META-INF/spring directory are loaded in the modules IOC container. In order to mark something as a module you put a module-info.properties file into the META-INF/spring directory. This file is in it's most basic form just a marker file that tells the module loader that this is a module to be loaded (much like hte OSGi manifest). In more sophisticated scenarios the module.properties file can specify strategies how a module should be instantiated. The minimal module.properties file just contains an artifical module name:

Name: MyModule

Application startup is easy:

new ModuleApplicationContextLoader(new ClasspathModuleLoader(), new DefaultServiceRegistry()).loadApplicationContexts();

To include a module in your startup process just put in on the classpath. This greatly simplifies integration testing. If you are using Maven you don't have to do any special setup since everything will already be on your classpath! For special situations and deployments you can either implement your own module loader or you use module loading rules. Here is an example for a module loading rule file:

<?xml version="1.0" encoding="UTF-8"?> <modules xmlns="http://www.rietzler.com/schema/spring/modules/loader/resolver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:resolver="http://www.rietzler.com/schema/spring/modules/loader/resolver" xsi:schemaLocation="http://www.rietzler.com/schema/spring/modules/loader/resolver http://www.rietzler.com/schema/spring/modules/loader/resolver.xsd" includeByDefault="false">

<!-- include only modules with matching names. evaluated against module.properties file -->
<include name=".*Include.*"/>
<!-- include only modules matching the given RFC1960 filter. evaluated against the module.properties file -->

<include filter="(moduleQoS=xxx)"/>

<!-- provide your own rules -->

<rule class="com.rietzler.spring.modules.loader.XmlModuleResolverBuilderTest$IncludeByNameRule" parameters="MyModule" />

</modules>


Build-time constraint checks are currently out of scope of the source code. However, I use Classycle (http://classycle.sourceforge.net) to enfore similiar constraints that OSGi does at runtime. With Classycle it would be a pretty easy task to write a tool that understands OSGi exported packages and checks against OSGi bundles.

For further details you can have a look at the source code. It's not final production quality, but it already contains source code documenation and you can inspect the tests and test resources for getting further information.

Saturday, December 20, 2008

Is OSGi going to become the next EJB ?

A few weeks ago I spotted an article that stated OSGi as "the next big thing after Spring". Actually, there are a whole bunch of articles, blogs etc... out there in the wild - all praising OSGi as one of the next "big things" that will reach many sectors in the Java space. I don't doubt this and I do admit that OSGi solves many problems and supports top notch architectural models such as high modularization and micro services. However, on the other side - after using OSGi for a couple of years and see how it performs (in the meaning of development performance) in different areas I really have doubts about OSGi.

Here are some things I love and hate about OSGi:

The concept of creating a system out of even hundred of typically pretty small bundles is very good. The really good thing about bundles in OSGi is that they have defined borders - not only in the sense of dependencies but also in the sense of runtime. Each bundle can serve as a micro application, having it's own lifecycle, having it's own citizens and each bundle can carefully decide which objects to expose to the outside world. Carefully adopted, this leads to a system with loose coupling and a high probability for reuse. However, at the same time the lifecycle model of OSGi makes life complicated. Actually, tracking services and managing all the aspects of what to do when services come and go is nasty (I've seen systems that had tried to manage these things with pretty large state machines in their bundle activators ... this is boiler plate that no one wants to write!) - Luckily, there's Spring DM out there that helps us manage these things. To be honest - I'd never even think about starting an OSGi project without using Spring DM. Altough Spring DM greatly reduced the complexity of bundle setup, it's still complicated. I still need to start the OSGi runtime and install and start the bundles - and I have to take care that all other bundles that I need are installed and started too ...

I personally think that we - as developers - have to enforce constraints on ourselves! We have to automatically check the defined constraints and let the build process fail if we e.g. accessed some classes we were not meant to access. OSGi's versioning concept (as a side effect ...) makes a first step of bringing the enforcement of architectural constraints to the developer's daily life by definining export and import packages ... and introduces a completely new dimension of problems! OSGi resolves versioning issues at runtime by giving each bundle it's own class loader and let that class loader see exactly the classes in the versions it depends on. Sounds neat ? Yes it is - and you will curse it! This leads to a really new dimension of problems, because it really changes the way your environment works. Your code passes all your unit tests, but once you start it in an OSGi runtime it crashes; Libraries crash because the enhance their classes at runtime; Singletons designed as static objects get created more than once; The story continues ... You typically end up in a situation where you constantly tweak your modules build specifications (that creates your manifest) and spread absolutely counter-intuitive dependencies across your whole system. Spring DM also addressed this topic - by adding some directives to your services and tweaking around with the class loaders ... and you still need to tweak and spread dependencies. I'm shivering at the thought that I need this workaround to even get started ...

Especially that class loading hell leads to a new dimension of problems. You will quickly notice that you cannot go on without a strong and automated integration testing suite that incorporates OSGi (another thing that Spring DM supports).

Now - what's my conclusion about all that stuff. First of all - before considering OSGi I would really check if I have the ultimate requirement to exchange bundles at runtime without shutting down the system - and even in this case I would really revisit these requirements and see if I can limit them to a corner where I could use other techniques for dynamically loading modules at runtime. There are alternatives out there fostering the architectural principles (e.g. you could use an IOC container, use independent container instances to enforce module independence, do constraint checking at build time, etc...) - most of these things are much closer to the KISS principle, avoid all the additional boiler plate code and build configuration - and therefore allow you to stay more agile.

I almost forgot the title :o) There's another technology out there with pretty the same characteristics (in terms of things being complicated): EJB. Spring is propably the most popular example of what can happen when a technology is way too complicated and makes life hard. Maybe we will experience the same thing with OSGi in in the next years ? I cannot say ... however, if this is the case, then there is a certain irony in that SpringSource now heavily supports OSGi :o)

Cheers,
Peter