Resolving dependencies in OSGi container in Liferay DXP
UPDATE 21/12/2017: This post of Ignacio Roncero Bazarra describes another solution about the third party bundles.
This case is very common. You want to use a third party library, for example
morphia. Its a wrapper for the MongoDB driver. I chosen this library for our example because it was tricky in comparison to others, like apache commons.
Our starting point about including third party libraries in ur modules was the blog entry of Nebinger. If you don't know the article, you should read it. David describes 4 ifferent ways you can take, to resolve the problem. But, wait. What exacly is the problem?
So this is actually a common misconception - there is a difference between building in gradle using the dependency manager and the OSGi runtime environment that does not have a similar dependency manager.
OSGi purposely does not download dependencies, especially transitive dependencies, as this would lead to an unstable environment.
The build process will include transitive dependencies when compiling your code, but BND is not a compiler it's just building the jar file and including what you tell it to.
So yes, under normal circumstances, you must include all dependencies and transitive dependencies yourself. That said, some projects don't use "optional" markers in their transitive dependencies so OSGi sees them as must-haves. You have to add the classpath declaration in the BND file to forcibly exclude those packages that you really don't want.
This is definitely a PITA, but it's that way for a reason.
At the beginning I saw option 1 and said to myself, no, this is not for me. Putting the jars in the
lib/ext dir of the tomcat, is not pretty.
Next, option 2. David said...
Let OSGi Handle Them. This is the second easiest option, but it's likely to not work. If you declare a runtime dependency in your module and if OSGi has a bundle that satisfies the dependency, it will be automatically available to your module.
To be honest, because OSGi is new to me, this sounded like something very complicated. So I didn't give it a real try.
Option 3, is to create an uber module. This is a module that contains the third party jars in the form of the binary code. So, bnd tools unzip the jar and place the class files in the jars module. This will work with third party jars that don't have dependencies very good. A disadvantage is, that the auto publish functionality in eclipse will be a little slower. But, the main disadvantage is th case where you have more dependencies to consider. In case of morphia there are many dependencies. In this case, you must update your
bnd.bnd file with the new dependency, deploy, and see if it works. If it doesn't work, its likely you need a new dependency. Then, you have to go to the gogo shell and run
diag to see what you are missing. I tried it out, but not for long...
Option 4 is like option 3 with the difference that the bnd tools will make a module jar that contains the third party jars. No big difference, the same big problem with the dependencies.
The only option left is option 2. I searched a little bit and find out that morphia is packaged as a OSGi bundle. Hurray! I deployed the jar in liferay and is stayed at the status
installed. I should supply the dependencies to the module. One dependency was the mongo db driver. In the maven repository the default driver is not a OSGi bundle, but there is a hint to find the bundled one. So I downloaded it and deployed it. It worked. Now Morphia needed the proxy tools. In the maven repository I couldn't find any bundle for this library.
While searching I found this repository from Spring. It is frozen, but you find a dozen of third party libraries wrapped as OSGi bundles. Luckily I found my dependency also there. I deployed it in Liferay and at last, everything worked very nice.
My modules are now very small and are being published very quickly, while all libraries live in OSGi container as bundles, and if someone need them, he can use them.
So, Option 2, should be the default. I think liferay should make a gradle plugin to fetch the libs as OSGi bundles and deploy them in liferay while deploying the custom modules. I don't know if this is possible, it would be very handy.
Add new comment
The build process will include transitive dependencies when compiling your code, but BND is not a compiler it's just building the jar file and including what you tell it to