Как я могу получить 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 работают таким образом. Написать такой расширитель нелегко.

Другие вопросы по тегам