Dheeraj Kumar Aggarwal
Dheeraj Kumar Aggarwal

Reputation: 642

OSGi classloader issues

I am very new to OSGi.

I am developing a plugin A (osgi bundle), suppose A which depends on libraries, suppose B-1.0 and C-1.0. Now If the library C-1.0 depends on library B-2.0 (Note: the different version of library B). So my plugin has two different versions of the library B in its classpath. Now, How can I handle this situation ?

As I am studying from last 4-5 days about OSGi that it creates a classloader for each plugin in the JIRA application, so that dependency version mismatch do not occur between plugins. But What would a developer do If a plugin itself needs two different versions of a library jar ?

Can I create two different classloaders in a single osgi bundle through OSGi, say one for package X and another one for package Y ?

Please help me in any of the above scenarios or point me to the right direction.

Thanks in advance.

Upvotes: 1

Views: 2897

Answers (3)

Neil Bartlett
Neil Bartlett

Reputation: 23948

Remember that bundles do not depend on other bundles!!

Bundles import packages that are exported by other bundles. (unless you have used Require-Bundle, but you should not). So to rephrase the scenario from your example:

  • Bundle A imports package org.foo. Bundle C exports package org.foo, and OSGi wires the import to the export. So far so good.

  • Bundle C also imports package org.bar. Bundle B 1.0 exports package org.bar. Therefore OSGi wires these together and everything is still fine.

  • Now... bundle A also imports package org.wibble. Bundle B 2.0 exports package org.wibble. This is fine as well! Bundles B 1.0 and B 2.0 are simply different bundles as far as OSGi is concerned, they can both be installed at the same time.

So when you look at the dependencies the way they actually work, you find that it's perfectly possible for A to import code that comes from two different versions of B. However there is a limitation. Consider the following:

  • Bundle D imports packages org.foo and org.bar v1.0 (yes, packages are versioned).
  • Bundle E exports package org.foo, which satisfies the import in D. Bundle E also imports package org.bar v2.0.
  • Some other bundles (say F v1 and F v2) export the 2 versions of the org.bar packages.

Actually this scenario can still work. D can import version 1.0 of package org.bar from somewhere, and E can import version 2.0 of package org.bar from somewhere else, at the same time as D is importing package org.foo from E. I personally find this pretty incredible! But it does not work if org.foo "uses" org.bar, where "uses" means that some types in org.bar are visible in the API of org.foo. In this case, bundle D would be exposed to 2 different copies org.bar, which is not allowed, so OSGi will prevent bundle D from running by not allowing it to enter RESOLVED or ACTIVE states.

Upvotes: 1

sjlee
sjlee

Reputation: 7876

Since each OSGi bundle has its own classloader, there will be 4 bundles in the runtime, and also 4 classloaders (A, B-1.0, B-2.0, C-1.0).

You may have two copies of the same class included in B (one from 1.0 and another from 2.0). If you run this, you may simply run into a ClassCastException in the A code because two versions of B classes are not the same.

OSGi provides a "uses" clause to detect this type of situations early. For example, C may have a uses clauses like the following:

Export-Package: c.some.package;uses="b.some.package";version="1.0"
Import-Package: b.some.package;version="2.0"

In this case, you will have an earlier failure (while resolving A), known as a uses conflict, because C places a constraint for its consumer on an acceptable version of B.

Conceptually, the only way to fix this problem is to have consumers of B (A and C in this case) agree on the version of B.

Upvotes: 0

Anup
Anup

Reputation: 1

In osgi bundle or plugin you'll have meta-inf flie which will define which classes you import if you pass extra agrument being the version=2.0 then it will use the class from B-2.0 if you don't specify anything then it'll resolve to one that is loaded by classloader first.

i.e. import-package(C 1.0): b.some.package; version="2.0" or b.some.package; version="[2.0,4.0)"

import-package(A 1.0): b.some.package; version="1.0" or b.some.package; version="1.0"

Hope this helps

Anup

Upvotes: 0

Related Questions