Как я могу получить BundleWiring вызывающего Bundle в OSGi?
У меня есть активный пакет под названием bundleA
который реализует класс под названием Example
с методом под названием doSomething()
из другого комплекта. ExampleImpl
инвентарь Example
и загружается через ServiceLoader
(спасибо SPI Fly). В ExampleImpl.doSomething()
от bundleA
Мне нужно получить BundleWiring
пачки, которая называется doSomething()
(без прохождения Bundle
или же BundleContext
так как я не могу изменить API). я могу получить bundleA
"s BundleWiring
, но не вызывающий пакет BundleWiring
:
Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
BundleWiring bundleWiringOfBundleA = bundle.adapt(BundleWiring.class);
Как я могу получить вызывающий пакет BundleWiring
?
В моем конкретном случае вызывающим пакетом всегда будет WAB, который работает в Liferay Portal 7.0. Поэтому, если есть решение, специфичное для Liferay Portal, я бы с этим согласился, но более общее решение OSGi также подойдет.
Обратите внимание, что я хочу, чтобы проводка пакета вызывающего пакета не была проводкой пакета каждого пакета, которая зависит от текущей проводки пакета. Я знаю, что могу получить проводки пакета, которые зависят от текущей проводки пакета, но это не поможет мне получить вызывающий пакет конкретно:
Bundle bundleA = FrameworkUtil.getBundle(ExampleClass.class);
List<BundleWires> bundleWires =
bundleWiring.getProvidedWires(BundleRevision.PACKAGE_NAMESPACE);
bundleWires.get(0).getRequirerWiring();
4 ответа
В Liferay, вызывающий WAB BundleContext
хранится в ServletContext
как "osgi-bundlecontext"
:
BundleContext bundleContext = servletContext.getAttribute("osgi-bundlecontext");
Bundle bundle = bundleContext.getBundle();
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
Так что, пока у вас есть доступ к ServletContext
в Liferay вы можете получить вызывающий пакет Bundle
а также BundleWiring
,
Вы не можете сделать это. OSGi вообще не вмешивается в перекрестный вызов метода, поэтому единственное, что вы можете использовать для получения этой информации, - это стек вызовов Java, доступ к которому осуществляется с помощью Thread.currentThread().getStackTrace()
, Тем не менее StackTraceElement
объекты, которые это возвращает только дает вам имена классов не java.lang.Class
объекты, поэтому нет никакого способа сопоставить их обратно в связки.
Помимо того, что это невозможно, я очень скептически отношусь к тому, что это будет хорошей идеей. Вы не должны экспортировать классы реализации вообще, не говоря уже о том, чтобы пытаться сделать их чувствительными к вызовам.
Если вам нужно реализовать поведение, чувствительное к вызывающему пакету, то каноническим и правильным способом достижения этого является регистрация службы с использованием ServiceFactory
интерфейс.
Вы сказали, что не можете изменить API. Но можете ли вы поменять звонки? Если это так, то у вас может быть "прокси" -сервис, который используют вызывающие пакеты вместо исходного. Затем вы можете пройти Bundle
и / или BundleContext
в службу прокси и поместите туда свою логику зависимости.
Другой вариант, который приходит на ум, это использование ThreadLocal
переменные для передачи этой информации в вызываемый комплект, но я не уверен, какие побочные эффекты может иметь этот подход.
Вы можете использовать BundleTracker и реагировать на все устанавливаемые WAB. Затем вы можете анализировать каждую WAB и, например, проверять классы на наличие аннотаций.
Декларативные сервисы и существующая поддержка WAB работают таким образом. Написать такой расширитель нелегко.