OSGI: asking Framework to load class exported by a bundle without visiting each bundle's classloader?
OK. So I have a org.osgi.framework.launch.Framework which I created programmatically开发者_运维技巧 in the following way.
framework = ServiceLoader.load(FrameworkFactory.class).iterator().next().newFramework(getFrameworkConfig());
framework.start();
installBundles(BUNDLES_PATH); // installs bundles from a directory, by searching BUNDLES_PATH recursively for JARs
What I want to do, is have a universal loadClass method (as a method in this class) Which will scan the installed bundles, read their Export-Package: declarations, and call the correct bundle's loadClass method, based on the packageName of the class that I'm passing as a parameter.
Is there a smart way to do this? or is it better to just do this:
Class<?> c = null;
// else try every installed bundle one-by-one
for (Bundle bundle : framework.getBundleContext().getBundles()) {
try {
c = bundle.loadClass(className);
} catch (ClassNotFoundException e) {
// OK, move onto next bundle
continue;
}
if (c != null)
break;
}
return c;
I realize I could use services to just have the bundles publish their available services and have the framework query the service with getAllServiceReferences() but this is more work for the programmer, and I'm not sure I wanna go the route of Declarative services.
I would caution against taking this approach. An OSGi framework can contain multiple providers or versions of a package. Trying to make a unified class loader that correctly copes with this is not trivial. However if you want to query the packages being exported you have two options depending on which version of OSGi you are using.
If you are using OSGi prior to OSGi R4.3 you can use PackageAdmin. This is a service registered in the service registry that allows you to query what packages are exported by bundles in the framework. Of specific interest to you will be the getExportedPackage method. This allows you to select a provider of the package and then you can call loadClass on the bundle that provides the package.
PackageAdmin is deprecated in R4.3 (although equinox still implements it). This is more complicated. To do what you desire you need to make use of the new BundleWiring API. This involves getting hold of each bundle in the system and do the following:
BundleWiring bw = bundle.adapt(BundleWiring.class);
List<BundleCapability> capabilities = bw.getCapabilities(BundleRevision.PACKAGE_NAMESPACE);
for (BundleCapability bc : capabilities) {
String pkg = bc.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
}
in this you case need to cope with multiple providers and select the correct one. Working out the correct one is the hard part.
精彩评论