If the title doesn’t make it obvious this post is all about OSGification. It’s an attempt to present and categorize practices in the following categories:
- Good practices
- Bad practices
- Pure practices
This post assumes that you have basic understanding of OSGi.
How do I make a project OSGi compliant?
In this section I will give a really brief overview of the OSGification process. Keep in mind that its “really brief”.
To make your project OSGi compliant you need to take the following steps
- Provide a proper MANIFEST with proper package imports/exports etc.
- Resolve class loading issues.
- Make sure that all runtime dependencies are OSGi compliant.
Java Service Loader  Java allows you to load object that are defined under META-INF/services/yet.another.interface. This works great when using flat class loaders but will not work that great when your class loaders are isolated.
This section discusses about approaches that are generally considered as bad. I’d say don’t be afraid to use one of them just because they are generally considered bad, as long as you know the side effects and you are ready to live with them. Maybe the term last resort would be more appropriate to describe them.
Creating Uber Jars
Sometimes people in order to avoid the overhead of bundling all their runtime dependencies and also avoid class loading issues between their bundles and their dependencies they are bundling everything together under a single bundle. This results in having everything loaded from a single class loader which will eliminate challenges ,  &  which were mentioned above.
This comes at the cost that you will not be able to add, remove or update a part of your application, since everything is part of the same artifact. I would avoid that approach, but its still better than nothing.
Fragments & Dynamic Imports
A fragment can attach itself on one existing bundle. Once the bundle gets attached both bundles can share classes and resources. This sounds cool, but there are two things that you might want to consider. The first one is that a bundle can be attached to one and only one bundle (can have a single host) and that may be limiting for your needs. The second problem is that in order to attach a bundle to a “host” bundle, you will need to refresh the host bundle. That will cause a chain reaction refreshing all bundles that depend from the host. The refreshing action will restart the activator of the bundle that is being refreshed and that is not always nice.
Dynamic Imports is an approach that is used for dealing with class loading issues  and it actually allows you to specify imports with wildchards. This usally serves the need of loading classes from packages that are not known in advance. However, this can have lot of side effects, such as unwanted wirings between bundles that can affect the process of adding removing or updating bundles.
I would use fragments if I had no other means of solving my problem, but I would avoid dynamic imports at all.
This section discusses about approaches that are generally applied, but they are not really pure. This means that even though they do work without serious side effects there are not the best thing to do. However, in many cases they are a realistic approach that will get you to the “OSGi ready” ready state.
Thread Context ClassLoader
I tried to explain above why the Class.forName is something that will probably not work inside OSGi. But there are a lot of libraries out there that heavily rely on it. On top of that there is a good chance that you are using it too inside your application. A potential solution is to “fallback” to the thread context class loader (a.k.a TCCL). This approach is based on the fact that a library may not be able to possibly know how to load class using its name, but the caller of the library might do. So the caller may set the thread context class loader and the library may use that to load classes.
Imagine a library that deserializes data into Java Objects. That library will try to load the class most probably using Class.forName and will fail. If you modified the library to “fallback” to the TCCL if it failed to load the class, you could have the code that uses that library to set the value of TCCL just before calling the library and then restore it to its original value after the invocation. Of course this assumes that the class loader you are going to use as TCCL is able to load the class. In many cases that is valid for a bundle that uses a library and this is why it usually works.
Some real world examples:
The fact that this approach assumes that you will be able to set the TCCL right before the invocation and also that the caller bundle will be able to load the target class does not guarantee that the approach will work in all cases. In most cases it does, yet there still might be cases were it will fail.
This is also the reason why many consider this approach “a bad practice“. In practice I see more and more libraries and frameworks using this approach and it seems that it works with no side effects. I think that the key here is to know when to use it and when to go by a more pure approach.
Object Factories and Resource Loaders
With this approach you avoid direct loading of the class or the resource and instead you delegate to a Factory or Loader. For application that is intended to run both in and out of OSGi you can have a default implementation that will assume flat class loaders, but inside OSGi you can have an implementation that makes use of OSGi services in order to load classes, create objects or load resources.
Passing the Class Loader
Structuring your API in such a way that whenever it comes to loading classes, to allow the passing the class loader. Although this has the least possible side effects, its not always feasible.
Use a BundleListener as a complement to the ServiceLoader
As I already mentioned above the Java ServiceLoader will not work that well inside OSGi. An approach that you can follow to work around this problem, is to use a bundle listener that will listen for bundle events and for each bundle that gets installed, it will look for META-INF/services/yet.another.interface. It can then use the bundle class loader to load and instantiate the implementation of the Service. Finally it can either register it to the OSGi service registry or to a local registry from which the bundle can look the service up.
Please note, that I am not sure if this is commonly used practice (haven’t seen it documented), but it worked for me quite well in the past, without side effects so I decided to add it in this section. Feel free to drop a comment if you think the opposite.
Also note, that there is also Apache Aries – SPI Fly which intends to provide a global solution to the bridging the java service loader with the OSGi service registry. Finally, I’ve read some things about the OSGi 5 and some work related to the java service loader, but I don’t know more than that yet.
I’ll repeat myself by saying that the initial motivation for this blog post was the fact that every now and then I encounter people that are “pure or nothing“. I think that its better to go by a not sure pure approach, that do nothing. Especially for existing projects, the road to OSGification can be cross in many steps and not single one.
The last year I’ve been spending time on Jclouds working on the OSGi support. The initial approach was to just get it running in OSGi. In every single release of jclouds improvements are applied and with the help and feedback of the community, some questionable approaches have been replaced with more solid ones. I feel that this attitude should be an example for projects that consider providing OSGi support. “No need to go for all or nothing. Step by step is also an option!“