Thursday, January 24, 2008

Troubles with OSGi - Part 1 - Proxy Creation Issues with Hibernate

We are trying out using osgi as a container for our application hoping to leverage it's dynamic updates and staged rollout features. Our system needs to be updated/rolledback with 0 downtime. Yeah we're working on *that* critical an application ;).

I have run into some pretty interesting issues using OSGi. There is not a lot of info on typical business applications that use OSGi. Some of the issues we faced were not documented and we had to get a lot of help from many forums. So the next couple of posts would be some stories around how OSGi was used and what pitfalls were faced.

All our code was packaged into small(er) osgi bundles. Following bundles were created -

  1. Bundle 1 - All entity classes,
  2. Bundle 2 - All business logic classes,
  3. Bundle 3 - All DAO's ,
  4. Bundle 4 - All client classes.

In initial stages I like to know how and why things work so that we can trouble shoot issues easily later. This made me decide against using the dynamic-imports feature. So every dependency needed by a bundle had to be manually declared in the manifest file.

Most of the initial issues got resolved quickly. But we started getting NoClassDefFoundError for HibernateProxy in our main bundle. This was really weird because the bundle that was executing the code, had imported all of spring's and hibernate's packages.

A couple of hours were spent trying to recreate the bundles, re-declare all the imports etc, but still no progress. I decided debugging was the best way to go forward. I got all spring/hibernate sources and started stepping through. Here's what I found.

Hibernate creates a proxy for any entity which does lazy loading. This proxy is a cglib based proxy that implements the HibernateProxy interface and also derives from the actualy entity object. When CGLIB is called to create a proxy, it creates a new class definition and creates the byte array representing the class. This class is then loaded onto the entity object's classloader.

However in OSGi each bundle has it's own classloader. So the entity bundle that contained only the POJO's had a classloader of its own and this bundle did not import any packages from any other bundle. The business code bundle imported the entity, hibernate and spring bundles and so the bussiness code bundle's classloader was wired with the other 3 classloaders. When CGLIB created the proxy and tried to define the proxy class in Entity bundle which did not import hibernate packages, it was throwing the NoClassDefFoundError.

The fix was to import this package in the entity bundle and things were all set. But this whole issue raised 2 main concerns

1) The stack traces raised by Equinox OSGi framework does not give detailed info on source of an error and just gives info on the initial bundle that was executing the code when error occured. Is this an issue with Equinox alone or is it same across all other osgi containers ?
2) Even though a bundle may not directly use a class, you may still have to import it (or) use dynamic-imports and be masked from this. Either way it's still ugly.



Tags: ,

Subscribe to comments for this post

Monday, January 14, 2008

Hibernate, Encapsulation and OO

The current project I am working on, is a typical legacy application rewrite. The existing system in cobol has been around for ages and the code base had apparently got very bloated and unstructured with so many patches/fixes/what-not down the years.

One of the main issues in the old system was that the code had become un-manageable and making a small change involved poring over thousands of lines of code to find out where something was getting changed.

In the proposed java based system, in the tradition of all enterprise applications, we would be using hibernate and spring. When we reverse engineer Hibernate/JPA entities from DB schemas the java objects created have public getter/setters. This seemingly innocuous feature is the one I have a biggest gripe with. This totally violates the whole data abstraction notion in OO systems.

When the entities are exposed as such, it becomes easy for layers above it to change entity state. This is very convenient when writing code and lets one design classes that updates multiple entities. But this also leads into the same problem which caused the rewrite in the first place. By letting anyone update entities, we allow business logic to be just dumped into a class and be called. No structure is need.

I prefer having one gateway class where all business logic pertaining to one entity is located. This simplifies making any changes to the system and any impact analysis need not span the entire code base. But in a model where entities have public setters, this can never be enforced.

Whats to prevent the current rewrite from being as messed up as the system its replacing? Processes like code review helps to a certain extent. But when push comes to shove, cutting corners becomes the norm and out goes all the best practices. This leads us back into creating our own tangled web of code to replace the older tangled web. It may seem too far-fetched but after 8 years of looking/writing all sorts of patches/fixes and features, only one thing is certain. If it can be abused, it eventually will end up being. Maybe even by the original developers ;)

ObjectMentor has a blog posting about this that states that jpa/hibernate entities should be treated as datastructures and not objects. They suggest adding a new layer of objects that map to the hibernate/jpa data structures and the rest of the application code uses the created objects.

This is a good idea in that we can create proper OO code that are not limited by the active record style entity objects. This can potentially even help in resolving some of the issues i had with anemic data model.

Tags: ,

Subscribe to comments for this post

 
Clicky Web Analytics