2

I am currently working on making some very OSGi-unfriendly 3rd-party libraries available to our OSGi-bundles. One of these libraries (which I have already turned into a bundle using bnd) manages to load classes that it should not be able to load (at least by OSGi-rules). Lets assume that bundle is called Foo, and the package from which it loads classes is called bar.

Foo has bar as optional import. This shouldn't matter though, since there is no bundle that exports bar. I am not using any boot-delegation. The jar-file that contains bar is on the application-classpath though (the OSGi-framework runs embedded in my application).

Apparently Foo somehow bypasses the OSGi-classloading infrastructure. How can this be done? I am pretty sure that it does not use a custom class-loader, because there is just no reason for it to have one (no feature Foo offers would require such a thing). So, what standard, out-of-the-box methods could be used by a bundle to bypass OSGi-classloading?

chad
  • 7,369
  • 6
  • 37
  • 56
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • sorry for offtopic, I'm 'struggle' with very similar task on embedding Felix into my application, (actually still have open question on it http://stackoverflow.com/questions/9822616/how-to-resolve-instance-of-consumer-when-felix-is-embedded), Isn't be very impudence to ask you share code how do you embed (actually init Felix) OSGi. Thank you in advance. You can send me info or even negative response to mvoronoy_at_gmail_com – Dewfy Aug 06 '12 at 13:16
  • I am having these problems in the context of Pax Exam tests, so I am not doing the embedding myself. I know that Pax Exam uses Pax Runner, which is supposed to make it easier to embed a framework. I have never done it myself though, so I cannot offer any help. – Björn Pollex Aug 06 '12 at 13:26

4 Answers4

1

What OSGi framework are you using? Do you have a command prompt command or other means to request detailed info about the package? The OSGi spec allows you to investigate in detail, and most frameworks provide matching commands/interfaces for the OSGi PackageAdmin and other APIs.

Does it happen with other OSGi frameworks?

If you use ProSyst's mBedded Server as OSGi framework, you can discover who is loading what from where using the command

pkginfo [<package>[ <package>]] - Shows the dependencies of the specified package(s). If there are no parameters, you receive information about all packages available in the framework.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
pooh
  • 652
  • 3
  • 2
1

This will do the trick if the classes are available on the Application class loader:

BundleContext.class.getClassLoader().loadClass("bar.X")

If you can get any class loaded by a loader you can get all the other classes. Of course if you would be running security you could forbid access to class loaders.

Peter Kriens
  • 15,196
  • 1
  • 37
  • 55
0

Well, following is my assumption without proofs.

The simplest way to implement non-OSGi optional import is usage of Class.forName(name) - please note the signature without classLoader. Let's look at source code for this:

return forName0(className, true, ClassLoader.getCallerClassLoader());

In other turn let's look at ClassLoader.getCallerClassLoader():

...
Class caller = Reflection.getCallerClass(3);
...

3 - is number of frames to invoke (for example getCallerClass(0) - will return Reflection class). You can easily count what code is #3 in stack and if it is non-loaded by OSGi it will use default classLoader.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
Dewfy
  • 23,277
  • 13
  • 73
  • 121
  • 1
    Yes, but since the bundle has a custom classloader, which follows the OSGi rules, in a properly implemented OSGi fw you should still remain in OSGi space even by using Class.forName, and this shouldn't be possible I think... – pooh Aug 02 '12 at 08:05
  • @pooh - look at phrase *OSGi-framework runs embedded in my application* Its mean that there is code that uses OSGi loaded classes, but not loaded by OSGi. (look for definition of embed: http://felix.apache.org/site/apache-felix-framework-launching-and-embedding.html#ApacheFelixFrameworkLaunchingandEmbedding-embedding) So it is highly possible that we have stack: [App Non OSGi]->[OSGi loaded]->[`Class.forName`] - this is exactly #3 – Dewfy Aug 02 '12 at 08:12
  • @Dewfy Your counting is wrong. 0 -> `Reflection.getCallerClass`; 1 -> `ClassLoader.getCallerClassLoader`; 2 -> `Class.forName`; 3 -> caller of `Class.forName`. – Marko Topolnik Aug 02 '12 at 08:59
  • It seems that Felix handles some cases of classloading not exactly according to spec.See for example https://issues.apache.org/jira/browse/FELIX-712 There were other issues too. Since here OSGi is embedded in the app, and therefore there are "non-OSGi" classes on the stack, it probably delegates all classloading to the system classpath, and not only Java.* as it should normally... – pooh Aug 02 '12 at 09:04
  • You can disable implicit boot delegation in the Felix framework if it is not working properly for you. The purpose of it is to try to guess when there is faulty code that expects boot delegation. Generally, it works well. If you find a specific case where it isn't working, you could consider reporting an issue at Felix. – Richard S. Hall Aug 02 '12 at 14:27
  • Actually I have already disabled implicit boot-delegation, so is probably not the cause. – Björn Pollex Aug 02 '12 at 15:06
0

The following is speculation since there isn't enough information to give a definitive answer. It's possible that the library is using the Thread Context ClassLoader (TCCL). If the bar package is visible to your own bundle (i.e. if it is a private package inside your bundle) and you invoke the Foo bundle, then the TCCL may have been set to allow the bar package to be loaded from your bundle.

To test this theory, try to change your code to explicitly set the TCCL to null before calling the Foo bundle: it would then throw a ClassNotFoundException.

Neil Bartlett
  • 23,743
  • 4
  • 44
  • 77
  • I have found one place in the responsible code that tries using the TCCL, which fails for the reasons you describe. Interestingly, it directly uses the system-class loader as failover. – Björn Pollex Aug 02 '12 at 15:08