OSGI - handling 3rd party JARs required by a bundle - java

I'm just getting started with OSGI development and am struggling to understand how best to handle dependant JARs.
i.e. if I'm creating a bundle the likelyhood is that I will need to use a few 3rd party JARs. When I create my bundle JAR to deploy to OSGI, obviously these 3rd party JARs are not included and thus the bundle will not run.
I understand that one option is to turn these JARs into bundles and also deploy them to the OSGI container. However if they only need to be used by the one bundle this doesn't seem ideal.
What is the best solution to this? Can the JARs be embedded within the bundle JAR and if so is this a reasonable approach?

You can include a third party jar inside your bundle by adding the third party jar to the root directory of the bundle jar file and then adding a bundle classpath header to the bundle's manifest, e.g.:
Bundle-ClassPath: .,my3rdparty.jar
If you want to place third party jar to subdirectory, specify the path without using heading ./, e.g
Bundle-ClassPath: .,lib/my3rdparty.jar # (not ./lib/my3rdparty.jar)

I would almost always bundle each jar separately. OSGi itself is meant for modularization and you take the whole system ad absurdum by not doing this.
If you want to convert JARs into bundles you might want to use the BND Tool written by Peter Kriens. But first I would suggest you look for the bundle in the SpringSource Enterprise Bundle Repository if they haven't already done the work for you.

It is possible to embed non-OSGi dependencies into the bundle.
An easy way to do this is to use Maven to manage your dependencies and Maven Bundle Plugin to build your bundle. Take a look at the <Embed-Dependency> and <Embed-Transitive> instructions of the Maven Bundle Plugin described in the section Embedding dependencies of the plug-in documentation page.
As Roland pointed out this is not an ideal solution with respect to the intentions of OSGi, i.e. modularization and reuse of individual modules. However it might be pragmatic solution for time being until the 3rd-party dependencies can be converted into OSGi bundles.

This thread is a bit old, but I wanted to point out one of the limitations of embedding dependencies. Recall that dependencies are at the jar level, but when you export packages some may need to come from the embedded dependencies. If this happens, you will end up with duplicate classes, one set inline in the top level bundle and another in the embedded jar. Of course, you can inline the entire embedded jar, but before you know it this propagates across your entire dependency chain. This is just one of the problems that Roland and others refer to.

Here is an example if you are using the Maven Bundle Plugin.
Note: This plugin automatically imports packages that your dependencies need. This may or may not be a problem for you. Thankfully, you can suppress the packages you don't really need to import (see below).
<Import-Package>
<!-- this was imported by one of the dependencies; I don't really need it -->
!org.apache.jackrabbit.test,
*
</Import-Package>
<Include-Resource>
lib/concurrent-1.3.4.jar,
lib/jackrabbit-core-2.6.5.jar,
lib/jackrabbit-spi-2.6.5.jar,
lib/jackrabbit-spi-commons-2.6.5.jar,
lib/lucene-core-3.6.0.jar,
lib/tika-core-1.3.jar
</Include-Resource>
<Bundle-ClassPath>
.,
concurrent-1.3.4.jar,
jackrabbit-core-2.6.5.jar,
jackrabbit-spi-2.6.5.jar,
jackrabbit-spi-commons-2.6.5.jar,
lucene-core-3.6.0.jar,
tika-core-1.3.jar
</Bundle-ClassPath>

Can we use OSGI to override the bootstrap classloader jars loaded during runtime, like if we wanted to override JAXP1.4.5 available with Java7 to JAXP1.6, there is -Dendorese feature to override the default API to upgraded API. Can we able to do this thing with the help of OSGI.

Related

is bndtools a future bundle tools for OSGI bundle?

I saw there are some community osgi.enroute, equinox and etc are encouraging bndtools for osgi bundle. However, there are a lot of a special key that I have never seen and can't find in their official website. For e.g.
Require-Capability:\
osgi.service;filter:="blahblahblah";effective:=active
Provide-Capability: osgi.service;objectClass=net....
And there are sometimes doing like
META-Persistence:
Webcontext-path:
Ok, where is this documentation from? Who the hell know if putting like this it will auto look up? Which mean I put JDBC-Driver then it will lookup?
Are they any bndtool cheat sheet or docs that can refer all this stuff.
As I know maven felix plugin had helped us to bundle nicely private export and import. What for I want to migrate to bndtools?
And I see apache karaf(popular OSGI runtime) is still using felix maven plugin which is more clear and understandable.
Is this a reason why OSGI until now still less popular than other JAVA framework? Can I still stick to the maven Felix plugin bundle rather than using these complicated tools?
The newest enroute examples use a maven build. So they are not very different from apache karaf builds. For creating bundles with maven you have two choices. The maven-bundle-plugin (from felix) and the bnd-maven-plugin from the bnd community.
Both use bnd under the hood, so they only have small differences. bnd-maven-plugin uses bnd.bnd by default for configuration. maven-bundle-plugin can also use this configuration style. I see the trend that many project use bnd-maven-plugin as it is more up to date with bnd versions but you can use both.
The real differences are with building the deployment artifact. In bndtools you build a jar out of a bndrun file while in karaf you usually create a feature file. This is where you really have to decide which way you go. If you use a self contained jar for your application then bndtools is a great choice. If you plan to deploy into karaf then karaf features are the best choice.
Btw. In both cases bndtools plugin for eclipse provides some nice support. Especially looking into the Manifest of jars and editing support for bnd.bnd files is nicely supported.
Regarding configurations needed in the bnd.bnd file. These configurations are needed in the same way if you use the felix maven-bundle-plugin.
The good news is that if you use the newest specs / examples then you rarely have to touch the bnd.bnd or the plugin config in maven. There are annotations for almost every needed configuration. There is good documentation inside the OSGi specs themself but the easiest approach is starting with examples.

Classloader to isolate a jar (class identity crisis)

I'm using jarX that has embedded dependencies that conflict with my own dependencies, so I'm creating a classloader to isolate jarX's dependencies from my main classloader.
jarX is outside my app's classpath, but my classes that use jarX's classes are in my classpath, so when I instantiate my classes loaded via the custom classloader, I run into the class identity crisis in the form of ClassCastException as the JVM's version of my classes are considered different from those loaded by my custom classloader.
I found this blog post where they solved a similar problem by only interacting with the custom classloader loaded classes via reflection, which seems to solve this problem.
It just feels like it should be easier than this. Does anyone know a better way to handle this problem?
The easiest way is to open jarX, remove the offending classes, and done. It is a bad practice to embed dependencies in a JAR unless that is JAR is meant to be used only as a standalone runnable fat-jar. JARs that are meant to be used as libraries should not embed dependencies.
When you notice that people package third-party classes in their JARs, I'd recommend pointing out to them that this is generally not a good idea and to encourage them to refrain from doing so. If a project provides a runnable fat-jar including all dependencies, that is fine. But, it should not be the only JAR they provide. A plain JAR or set of JARs without any third-party code should also be offered. In the rare cases that third-party code was modified and must be included, it should be done under the package namespace of the provider, not of the original third-party.
Finally, for real solutions to building modular Java applications and handling classloader isolation, check out one of the several OSGi implementations or project Jigsaw.
Can you post which jar is it and what are the classes that it overlaps, with the full stacktrace? Have a look at this tool I wrote to generate a list of duplicate classes in the WAR, there is an option to exclude duplicates of the same size.
These are some measures that can be done to solve this:
Try to reduce the number of duplicates by doing a case by case analysis of why the overlap exists. Add maven exclusions for jars that are complete duplicates.
Check if there is a version of the same jar without the dependencies that you could use, which jar is it, xerces, etc?
If there is no jar without dependencies, you can you exclude the other jar that overlaps jarX and see if the application still works. This means all components that need the jar have a compatible version of the jarX library
Separate the application into two WARs each with the version of the library you need. This will reduce the number of libraries in which
These where measures that are likelly to be more maintainable long-term
If the previous measures do not work:
open the jar, delete the duplicate classes and publish in the maven repository with a different name jarX-patched
you can configure nexus to serve a patched jar instead of an unpatched jar transparently
If your container supports OSGI that would be even better, but if you don't use a OSGI container for development as well, then the application would not work in development.

Handling split packages: Require-Bundle with maven-bundle-plugin

I'm adapting an existing collection of libraries, building them as OSGi bundles. It's a multi-module Maven project, with several layers of POM inheritance and aggregation. Ideally, plugin configuration would be placed in parent POMs only.
The project is composed of more than 100 jars. There's already a mega bundle that encompasses the entire library and export all packages. My effort aims at making the library more modular, which is the main reason of having them as OSGi bundles in the first place.
The main issue is this library has a split package nightmare, and I cannot change the package structure. I'm trying to solve the issue using Require-Bundle, as recommended in the book OSGi in Action, even though the book mentions it's not a good practice. I tried the recommendation of using an arbitrary attribute named "split" in Import-Package to separate parts of a bundle and only import certain packages. But due to the number of bundles providing the same package, that turned out to be too complicated to configure.
My question is how to configure the maven-bundle-plugin <Require-Bundle> directive, if at all possible, to use wildcards (e.g. *) as a form of telling it to use all Maven dependencies, instead of having to manually list all bundles names and versions; i.e. is there an alternative to this:
<Require-Bundle>lib-api; version=${project.version}</Require-Bundle>
that uses some kind of wildcard matching and that could be put in a parent POM?
In short, no. bnd has no support for Require-Bundle, it treats it as a normal header.

OSGI and maven dependencies among bundles and jars

I got a question regarding OSGI Bundles and "normal" maven jar dependencies.
The following scenario:
A multi module maven project: A
with the modules A.X, A.M:
A.X is a OSGI Bundle
A.M is normal java application that launches the OSGI framework and loads the bundle A.X
In the project top-level pom (A.pom) I define a dependency to commons-logging-1.1.1
Then I use commons-logging in my OSGI Bundle A.X.
The maven-bundle-plugin generates the manifest for A.X with an import entry where 'commons-logging' occurs.
When I start A.M and print out all my loaded jars (with getSystemClassLoader...) on the console then ../../../commons-logging-1.1.1.jar is listed.
Because of the maven-dependency from the top-level pom.
Now I try to install my OSGI bundle A.X and get a "unresolved constraint in bundle.....commons-logging" exception.
Why canĀ“t the commons-logging dependency (from A.X) be resolved with the commons-logging lib that is already in memory (in A.M) when the bundle is installed?
I am grateful for any help!!!!
Printing out the loaded jars with getSystemClassLoader doesn't necessarily tell you what's available via OSGi - remember that OSGi has it's own class-loading mechanisms.
As I understand, the commons-logging must be exported from some other bundle so that OSGi can wire it up to your A.X component - likely there is bundle or feature for commons-logging that you can easily add as a dependency.
I'm not sure which OSGi container you're using (I use Fuse), but there should be some way to look at the imports and exports of the bundles you are using. Since A.X imports commons-logging, another bundle needs to export it (with appropriate version).
In the fuse world, adding a dependency to a system bundle is as easy as adding it to a features.xml file. But since I don't know which container you're using, I'm not sure how you can do this.
Does this help?
That's because one of your OSGI bundles is using something in commons logging, which is not an exported package in osgi. So you either find a version of commons-logging that is bundlelized and exports the package you are trying to use or you add the jar to the bundle-classpath of the user bundle (there are other, dirtier options as well). The first option is much better than the second one since it is modular; i.e. you could update commons-logging without changing any other bundle.
Like was already mentioned, the fact that it's in the app classpath is irrelevant

Why make my project an OSGI bundle as opposed to a standard JAR package?

For what reasons would I want to make my project an OSGI bundle as opposed to just a standard JAR package? Does it only make sense if it is going to be used by an application that uses an OSGI framework (eg: Equinox/Eclipse)? Or is it also useful from a development point of view, ie: being able to easily reuse my OSGI bundle by other projects during Eclipse development?
OSGi provides support for modules, you could control the dependencies. Each module may include and exclude packages from other bundles. You can also replace bundles during runtime. Making a whole project a single bundle has none of these benefits. I would only wrap a jar like a jdbc driver as bundle if it is not available as an OSGi bundle.
First check whether your project would have a benefit. Then identify which modules should be a bundle.
If your project is a public or open source library, then please do make it an OSGi bundle. This will be of great help to OSGi developers who may want to use your library.
On the other hand if your library is private then the benefits of OSGifying it are limited. Mostly it will be an advantage if you decide to adopt OSGi strategically later. You may also derive some benefit from the explicit dependencies, i.e. you can look into the bundle to work out exactly what it depends on.
There is no runtime cost of doing this. The OSGi data in the manifest is simply ignored by non-OSGi runtimes.
You will have to generate the OSGi manifest though as part of your build step. The best tool to use for this is Bnd, which can be easily integrated into any ANT build -- use it as a replacement for the "JAR" task. If you are building with Maven, then use the Maven Bundle Plugin (which uses Bnd internally).
This is useful only if it's going to be used from within an OSGi container as you mentioned.
If you are searching an answer on why it is useful in general is something you can find a lot just by googling - start from Wikipedia:
http://en.wikipedia.org/wiki/OSGi
In general, I'd say OSGi's main benefits are encapsulation/versioning, solving JAR hell and management provided by the framework, which may or may not be interesting to you depending on your project.
I definitively suggest reading about OSGi if you haven't already - it's very interesting technology. I would suggest reading Neil Bartlett's articles on EclipseZone - this is the first one:
http://www.eclipsezone.com/eclipse/forums/t90365.html
There are a bunch of them, so google them - very interesting read, which will also give you an idea whether this is something you should consider.
SpringSource is a big proponent of OSGi, so it's worth taking a look there, too:
http://www.springsource.org/osgi
If you ever plan on using it in an OSGi context then you might as well make it a bundle. I don't know that there are any negative affects to making it a bundle, whereas if you don't make it a bundle and find out later on that you need it to be then you may have to go back and fix it. Aside from that I personally don't know of anything other than OSGi which uses the manifest meta information - but like I said; I don't think it will hurt.
OSGIfying a project will allow OSGI to be used for dependency management in Eclipse instead of the standard Eclipse project build mechanism, or an external dependency management tool such as Ivy or Maven. Making a project into an OSGI bundle allows you to express that project's package dependencies as bundle dependencies (if a bundle exists for the package dependency) which will be handled by the OSGI framework instead of those other mechanisms (standard Eclipse project build/Ivy/Maven).
Standard Eclipse project dependencies are established by specifying other projects and libraries on your project's build path. Converting to OSGI would replace your build path references with MANIFEST.MF import-package or required-bundles declarations.
Advantages of using OSGI for dependency management over the standard eclipse mechanism are:
re-export dependences: your bundle can re-export their dependent packages which means code relying on your bundle doesn't also have to rely on your bundle's dependants if it also uses them
version management: so you can specify the minimum and maximum expected version of a dependency.
See also Should I use Eclipse plug-ins (or OSGi Bundles) as a plain dependency management tool?

Categories