Есть ли простой способ составить список потребительских компонентов для интерфейса?

Товарищи кодеры,

В настоящее время я пытаюсь найти простой и лаконичный способ получить список служб/компонентов, использующих данный интерфейс. Я использую gogo-shell работающего сервера Liferay 7.1.x и не могу найти простой и прямой способ сделать это.

Мы хотим переопределить ссылки на используемый сервис через OSGI-configuration, но сначала нужно найти все компоненты, использующие его. Поскольку существуют статические неохотные ссылки на сервисный компонент, простое предоставление альтернативы с более высоким рейтингом не является жизнеспособным решением.

Вот пакеты, связанные с gogo, которые я использую:

   35|Active     |    6|Apache Felix Gogo Command (1.0.2)|1.0.2
   36|Active     |    6|Apache Felix Gogo Runtime (1.1.0.LIFERAY-PATCHED-2)|1.1.0.LIFERAY-PATCHED-2
   72|Active     |    6|Apache Felix Gogo Shell (1.1.0)|1.1.0
  542|Active     |   10|Liferay Foundation - Liferay Gogo Shell - Impl (1.0.13)|1.0.13
  543|Active     |   10|Liferay Gogo Shell Web (2.0.25)|2.0.25

До сих пор я мог перечислить всех провайдеров интерфейса через se (interface=com.liferay.saml.runtime.servlet.profile.WebSsoProfile):

{com.liferay.saml.runtime.profile.WebSsoProfile, com.liferay.saml.runtime.servlet.profile.WebSsoProfile}={service.id=6293, service.bundleid=79, service.scope=bundle, component.name=com.liferay.saml.opensaml.integration.internal.servlet.profile.WebSsoProfileImpl, component.id=3963}
  "Registered by bundle:" de.haufe.leong.com.liferay.saml.opensaml.integration [79]
  "Bundles using service"
    com.liferay.saml.web_2.0.11 [82]
    com.liferay.saml.impl_2.0.12 [78]

Ознакомьтесь со всеми требованиями к комплектам через: inspect cap service:

com.liferay.saml.impl_2.0.12 [78] requires:
...
service; com.liferay.saml.runtime.profile.WebSsoProfile, com.liferay.saml.runtime.servlet.profile.WebSsoProfile provided by:
   de.haufe.leong.com.liferay.saml.opensaml.integration [79]
...

Но мне пока не удавалось перечислить фактические сервисы внутри этих пакетов, которые используют данный интерфейс (или сервисный компонент).

Единственное решение, которое я вижу до сих пор, — это перечислить все предоставляемые службы этих пакетов через scr:list bid, а затем проверить каждую службу с помощью scr:info componentId, чтобы узнать, использует ли она службу WebSsoProfile.

Ребята, вы знаете более быстрый способ найти сервисы с помощью WebSsoProfile-сервиса?


[РЕДАКТИРОВАТЬ]: мы решили проблему, не предоставляя переопределения конфигурации для всех потребителей службы WebSsoProfile, а скорее гарантируя, что наша реализация используется путем деактивации службы по умолчанию при запуске сервера. Вы можете ознакомиться с подходом, описанным здесь.

В любом случае, для целей отладки такой поиск был бы очень полезен. Поэтому, если кто-нибудь знает способ получить список всех потребителей интерфейса, опубликуйте свое решение!


person Nuw    schedule 13.02.2020    source источник


Ответы (1)


Стандартное решение — использовать команду inspect. У него есть специальное пространство имен для служб. Поскольку регистрация службы — это возможность, вы можете использовать inspect capability service:

g! inspect c service
org.apache.felix.framework [0] provides:
----------------------------------------
service; org.osgi.service.resolver.Resolver with properties:
   service.bundleid = 0
   service.id = 1
   service.scope = singleton
service; org.osgi.service.packageadmin.PackageAdmin with properties:
   service.bundleid = 0
   service.id = 2
   service.scope = singleton
service; org.osgi.service.startlevel.StartLevel with properties:
   service.bundleid = 0
   service.id = 3
   service.scope = singleton

....

Однако я считаю эту команду совершенно бесполезной. Команда негибкая и имеет ужасный результат.

Однако Гого намного мощнее, чем люди думают. Во-первых, вы можете использовать все методы в контексте пакета.

g! servicereferences org.osgi.service.startlevel.StartLevel null
000003   0 StartLevel

Если вы хотите увидеть свойства каждой службы:

g! each (servicereferences org.osgi.service.startlevel.StartLevel null) { $it properties }
[service.id=3, objectClass=[Ljava.lang.String;@4acd14d7, service.scope=singleton, service.bundleid=0]

Вы можете сделать это встроенной функцией:

g! srv = { servicereferences $1 null }
servicereferences $1 null
g! srv org.osgi.service.startlevel.StartLevel
000003   0 StartLevel                               

К сожалению, OSGi добавила в Bundle Context перегруженный метод для getServiceReferences(), который выдает NPE при вызове с нулевым значением. Gogo ужасен с перегруженными методами :-(

Однако добавить собственную команду с декларативным сервисным компонентом несложно. Вы можете использовать следующее:

@GogoCommand(scope="service", function="srv")
@Component(service=ServiceCommand.class)
public class ServiceCommand {

    @Activate
    BundleContext context;        

    @Descriptor("List all services")
    public ServiceReference<?>[] srv() throws InvalidSyntaxException {
        return context.getAllServiceReferences(null, null);
    }

    @Descriptor("List all services that match the name")
    public ServiceReference<?>[] srv(
            String... names)
            throws InvalidSyntaxException {
        ServiceReference<?>[] allServiceReferences = 
            context.getAllServiceReferences(null,null);
        if ( allServiceReferences==null)
            return new ServiceReference[0];
        return Stream.of(allServiceReferences)
                .filter(r -> {
                    String[] objectClass = (String[]) r.getProperty(Constants.OBJECTCLASS);
                    for (String oc : objectClass) {
                        for (String name : names)
                            if (oc.contains(name))
                                return true;
                    }
                    return names.length == 0;
                }).sorted().toArray(ServiceReference[]::new);
    }
}

Это добавляет команду srv в Gogo:

g! srv Help Basic
000004   1 Basic                                    
000005   1 Inspect   

Обновить. Если вы хотите узнать, какие пакеты используют определенный сервис, вы можете использовать:

g! each (srv X) { $it usingbundles }

Убедитесь, что у вас есть следующие зависимости от пути к классам:

-buildpath: \
    org.osgi.service.component.annotations,\
    org.apache.felix.gogo.runtime, \
    org.osgi.framework
person Peter Kriens    schedule 13.02.2020
comment
Спасибо за подробный ответ @peter-kriens! Пожалуйста, поправьте меня, если я ошибаюсь, но в вашем примере перечислены только все службы, зарегистрированные под определенным именем, и это то, что gogo уже может предоставить. Есть ли у вас какие-либо идеи о том, как я могу получить все службы, ссылающиеся на данное имя интерфейса, используя стандартные функции оболочки gogo? Если их нет, я думаю, что лучшим подходом было бы написать собственную команду. Но это кажется настолько распространенным вариантом использования, что я подумал, что должен быть способ получить это из коробки. - person Nuw; 18.02.2020
comment
Я согласен с тем, что кажется странным, что вы не можете получить все услуги. Однако более новый API перегружает метод getServiceReferences(String,String) методом getServiceReferences(Class,String). Первая форма принимает (null,null), вторая требует ненулевое значение. К сожалению, Gogo не позволяет выбрать один из перегруженных методов. Так что это не было оплошностью (это сработало), это просто обычная средняя программная гниль... И ядро ​​Gogo, похоже, не сильно изменилось за последние 10 лет. - person Peter Kriens; 18.02.2020
comment
Я понял вашу точку зрения об изменениях API в BundleContext. Но ваше решение не решает мою проблему. Мне не нужно находить все сервисы, которые зарегистрированы под определенным именем. Мне нужны сервисы, в которых есть ссылка на сервис, зарегистрированный под известным мне именем. - person Nuw; 20.02.2020
comment
Служба не имеет ссылки на службу, а пакет имеет. Итак, вы могли бы сделать: each ( srv X ) { $it usingbundles } - person Peter Kriens; 20.02.2020