Завершение пакета схемы OSGI после остановки указанной службы

у меня такая проблема. У меня есть два комплекта чертежей OSGI. Один из них похож на сервис, а другой использует его. Я запускаю их на karaf. Итак, я хочу реализовать функциональность, поэтому, когда я останавливаю службу, мой другой пакет также должен быть остановлен. Мои XML-файлы

    <?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd ">

    <reference id="weatherService" availability="mandatory" interface="com.myslyv4uk.weather.api.WeatherService" />  

    <bean id="showWeatherImpl" class="com.myslyv4uk.client.impl.ShowWeatherServiceImpl"
        init-method="start" destroy-method="stop" >
        <argument ref="weatherService" />
    </bean>

</blueprint>

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd ">

    <bean id="weatherServiceImpl" class="com.myslyv4uk.weather.impl.WeatherServiceImpl"
        init-method="start" destroy-method="stop" />

    <service ref="weatherServiceImpl">
        <interfaces>
            <value>com.myslyv4uk.weather.api.WeatherService</value>
        </interfaces>
    </service>  
</blueprint>

Код Java пропущен. Я просто скажу, что ShowWeatherService использует WeatherService для печати случайного числа. У них обоих есть метод старт/стоп. Мне нужно реализовать конфигурацию или функциональность таким образом, чтобы после удаления пакета WeatherService из karaf также был остановлен ShowWeatherService. Проблема в том, что я не могу сделать ссылку из WeatherService на ShowWeatherService, потому что это будет циклическая ссылка, если эти пакеты не запустятся. Что я должен делать? Как я могу отделить пакет от другого пакета?


person Bohdan Myslyvchuk    schedule 13.10.2017    source источник
comment
Проверьте SCR OSGi. У вас могут быть компоненты, которые активируются/деактивируются в зависимости от наличия/отсутствия службы OSGi (среди прочего)   -  person Grzegorz Grzybek    schedule 13.10.2017
comment
@GrzegorzGrzybek спасибо за ваш комментарий, но, как я понял, это декларативные услуги. И я использую схему. Переписывание в декларативные сервисы — это последнее средство, которого я хочу избежать.   -  person Bohdan Myslyvchuk    schedule 13.10.2017


Ответы (2)


ПРЕДУПРЕЖДЕНИЕ

В этом ответе я объясню, как остановить пакет Blueprint, когда требуемый сервис исчезнет. Этот код работает так, как задумано, однако это плохая идея по разным причинам.


Вы можете зарегистрировать слушателя при привязке/отвязке службы и действовать при удалении службы. Это пример того, как это сделать.

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd ">

    <bean id="referenceListener" class="your.ReferenceListener">
        <property name="bundleContext" ref="blueprintBundleContext"/>
    </bean>

    <reference id="weatherService"
               availability="mandatory"
               interface="com.myslyv4uk.weather.api.WeatherService">
        <reference-listener ref="referenceListener"
                            unbind-method="unbind" />
    </reference>

    <bean id="showWeatherImpl" class="com.myslyv4uk.client.impl.ShowWeatherServiceImpl"
        init-method="start" destroy-method="stop" >
        <argument ref="weatherService" />
    </bean>

</blueprint>

Компонент referenceListener вызывается при удалении службы. Внедрив контекст пакета, вы можете остановить сам пакет:

public class ReferenceListener {

private Logger log; // set this up
private BundleContext bundleContext;

public void setBundleContext(BundleContext bundleContext) {
    this.bundleContext = bundleContext;
}

// Called when the service is injected
public void bind(ServiceReference<?> sr) {
    log.info("Bind of ServiceReference {} to bundle {}",
            sr, bundleContext.getBundle());
}

// Called when the service is removed
public void unbind(ServiceReference<?> sr) {
    log.info("Unbind of ServiceReference {} from bundle {}",
            sr, bundleContext.getBundle());
    try {
        if (bundleContext.getBundle().getState() == Bundle.ACTIVE) {
            log.warn("Bundle {} will be stopped after unbind of mandatory ServiceReference {}",
                    bundleContext.getBundle(), sr);
            bundleContext.getBundle().stop();
        }

    } catch (BundleException e) {
        log.error("Cannot stop bundle {} after unbind of ServiceReference {}",
                bundleContext.getBundle().getBundleId(),
                sr,
                e);
    }
}
}

Это решение работает, но имеет некоторые недостатки, например, если вы перезапустите контейнер, служба будет удалена, поэтому пакет будет переведен в состояние STOPPED.

person Alessandro Da Rugna    schedule 16.10.2017
comment
Программная остановка вашего собственного пакета — ужасная вещь. В StackOverflow вы не всегда должны давать спрашивающему именно то, что он хочет, особенно если он просит что-то, что может навредить ему. - person Neil Bartlett; 18.10.2017
comment
@NeilBartlett Спасибо за комментарий, я согласен с вами и поставил предупреждение в верхней части сообщения. Поскольку это то, о чем просил OP, я оставлю это здесь для справки, приветствуются любые другие решения, совместимые с Blueprint :-) - person Alessandro Da Rugna; 18.10.2017
comment
Спасибо, @AlessandroDaRugna, ваш ответ дал мне подсказку, как решить мою проблему в производстве. На самом деле, при остановке службы мне нужно было завершить некоторую логику, и в этом мне помог метод unbind0method. Большое спасибо - person Bohdan Myslyvchuk; 23.10.2017

Я бы не стал останавливать связку, которая нуждается в обслуживании, когда эта служба выходит из строя. Это не тот способ, которым это должно обрабатываться в OSGi.

Вместо этого ваш пакет showWeatherImpl может предложить себя как сервлет, используя шаблон http whiteboard. Это означает, что он предлагает службу, реализующую сервлет. Blueprint автоматически отменит регистрацию всех сервисов пакета, если обязательная ссылка на сервис выйдет из строя.

Конечно, это не поможет, если вы, например, зарегистрируетесь как сервлет, используя код Java в bean-компоненте в showWeatherImpl. В этом случае вы можете использовать обратные вызовы ссылок на сервисы, которые будут уведомлять вас о приходе и уходе сервисов.

И, конечно же, как упомянул Гжегож, декларативные сервисы по умолчанию гораздо более динамичны, чем план, и гораздо лучше справляются с такими ситуациями.

person Christian Schneider    schedule 13.10.2017
comment
Насколько я знаю, если обязательная ссылка на службу выходит из строя, любой последующий вызов этого экземпляра будет заблокирован (поскольку вы никогда не получаете службу, а получаете прокси-сервер для службы) и в конечном итоге повышаете ServiceUnavailableException. - person Alessandro Da Rugna; 16.10.2017
comment
да. Это правда. Так что это работает только в том случае, если у вас есть непрерывная цепочка услуг. Доска OSGi http является таким случаем. В других случаях, когда вы получаете вызов извне в ваш компонент, в то время как его зависимость недоступна, он блокируется. Для меня это одна из причин, почему я стараюсь использовать только DS, если могу. - person Christian Schneider; 17.10.2017