stiemannkj1
stiemannkj1

Reputation: 4548

How can I obtain the BundleWiring of the calling Bundle in OSGi?

I have an active bundle called bundleA which implements a class called Example with a method called doSomething() from another bundle. ExampleImpl implements Example and is loaded via ServiceLoader (thanks to SPI Fly). In ExampleImpl.doSomething() from bundleA, I need to get the BundleWiring of the bundle which called doSomething() (without passing the Bundle or BundleContext since I cannot change the API). I can get bundleA's BundleWiring, but not the calling bundle's BundleWiring:

Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
BundleWiring bundleWiringOfBundleA = bundle.adapt(BundleWiring.class);

How can I obtain the calling bundle's BundleWiring?

In my particular case, the calling bundle will always be a WAB which happens to be running in Liferay Portal 7.0. So if there's a solution specific to Liferay Portal, I would accept that, but a more general OSGi solution would be fine as well.

Note that I want the calling bundle's bundle wiring not the bundle wiring of every bundle that depends on the current bundle wiring. I know that I can obtain the bundle wirings that are dependent on the current bundle wiring, but that won't help me obtain the calling bundle specifically:

Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
List<BundleWires> bundleWires =
    bundleWiring.getProvidedWires(BundleRevision.PACKAGE_NAMESPACE);
bundleWires.get(0).getRequirerWiring();

Upvotes: 0

Views: 781

Answers (4)

stiemannkj1
stiemannkj1

Reputation: 4548

In Liferay, the calling WAB's BundleContext is stored in the ServletContext as "osgi-bundlecontext":

BundleContext bundleContext = servletContext.getAttribute("osgi-bundlecontext");
Bundle bundle = bundleContext.getBundle();
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);

So as long as you have access to the ServletContext in Liferay you can obtain the calling bundle's Bundle and BundleWiring.

Upvotes: 0

Milen Dyankov
Milen Dyankov

Reputation: 3062

You said you can't change the API. But can you change the calling bundles? If so, then you could have a "proxy" service that calling bundles use instead of the original one. You can then pass Bundle and/or BundleContext to the proxy service and put your dependency logic there.

Another option that comes to mind is using ThreadLocal variables to pass this information to the called bundle, but I'm not sure about what side effects that approach may have.

Upvotes: -1

Christian Schneider
Christian Schneider

Reputation: 19626

You can use a BundleTracker and react on all WABs being installed. Then you can introspect each WAB and for example scan classes for annotations.

Declarative services and the existing WAB support work this way. Writing such an extender is not easy though.

Upvotes: -1

Neil Bartlett
Neil Bartlett

Reputation: 23958

You can't do this. OSGi does not intervene at all in cross-bundle method invocation, so the only thing you can possibly use to try to get this information is the Java call stack, accessed with Thread.currentThread().getStackTrace(). However the StackTraceElement objects that this returns only gives you class names not java.lang.Class objects, so there is no way to correlate those back to bundles.

Besides being impossible, I'm very skeptical that this would ever be a good idea. You shouldn't export implementation classes at all, let alone try to make them caller-sensitive.

If you need to implement behaviour that is sensitive to the calling bundle then the canonical and correct way to achieve that is to register a service using the ServiceFactory interface.

Upvotes: -1

Related Questions