Метод события изменения OSGi не вызывается

Я играю с компонентами OSGi DS и файлом ConfigurationAdmin.

Я создал простой настраиваемый компонент

@Component(service=ConfigurableService.class)
public class ConfigurableService {

  private String message;

  @Activate
  public void activate(Map<String, Object> params) {
    System.out.println("Activate configurable");
    message = (String) params.get("msg");
  }

  @Modified
  public void modified(Map<String, Object> params) {
    System.out.println("Modify configurable");
    message = (String) params.get("msg");
  }

  @Deactivate
  public void deactivate(Map<String, Object> params) {
    System.out.println("Deactivate configurable");
    message = (String) params.get("msg");
  }

  public void execute() {
    System.out.println("Service says: " + message);
  }
}

Затем я создал командный компонент оболочки Felix Gogo для запуска конфигурации через ConfigurationAdmin.

@Component(property =   {
    CommandProcessor.COMMAND_SCOPE + "=fipro",
    CommandProcessor.COMMAND_FUNCTION + "=configure"
},
service = ConfigurationCommand.class
)
public class ConfigurationCommand {

  private ConfigurationAdmin cm;

  @Reference(unbind="-")
  public void setConfigAdmin(ConfigurationAdmin cm) {
    this.cm = cm;
  }

  public void configure(String input) throws IOException {
    Configuration config = cm.getConfiguration("org.fipro.osgi.config.ConfigurableService");
    Hashtable<String, Object> props = new Hashtable<>();
    props.put("msg", input);
    config.update(props);
  }
}

И, наконец, я создал еще один командный компонент оболочки Felix Gogo, который использует ConfigurableService

@Component(property =   {
    CommandProcessor.COMMAND_SCOPE + "=fipro",
    CommandProcessor.COMMAND_FUNCTION + "=welcome"
},
service = WelcomeCommand.class
)
public class WelcomeCommand {

  private ConfigurableService service;

  @Reference(unbind="-")
  public void setConfigurable(ConfigurableService service) {
    this.service = service;
  }

  public void updatedConfigurable(ConfigurableService service, Map<String, Object> properties) {
    System.out.println("ConfigurableService updated");
  }

  public void welcome() {
    service.execute();
  }
}

Если я запускаю приложение OSGi с пакетами, содержащими эти компоненты, я ожидаю, что при первоначальном выполнении welcome я увижу, что компонент активирован, а вывод службы равен нулю, потому что конфигурация еще не применена (убедитесь, что это изменяется при последовательных вызовах) . Если я впоследствии выполню configure Dirk, я ожидаю, что метод, аннотированный @Modified, будет выполнен, чтобы указать, что конфигурация службы была обновлена. Я также ожидаю, что метод updatedConfigurable в WelcomeCommand будет выполнен. По крайней мере, так я понял, прочитав спецификацию.

Сейчас наблюдаю разное поведение в Equinox и Felix.

Равноденствие:

Модифицированный метод вызывается, как и ожидалось, и ConfigurableService настроен правильно. Но updatedConfigurable(<Service>, <Map>) не называется. Только если я изменю сигнатуру метода на ServiceReference, будет вызван обновленный метод.

В спецификации сказано, что все методы эталонных событий поддерживают следующие сигнатуры методов.

void <method-name>(ServiceReference);
void <method-name>(<parameter-type>);
void <method-name>(<parameter-type>, Map);

Есть ли исключение для обновленного метода, которого я не видел в спецификации, или это проблема в Equinox, из-за которой я должен подать заявку?

Феликс:

Если я запускаю тот же пример на Felix в Bndtools, ни модифицированный, ни метод обновления не вызываются. Я проверил ConfigurationCommand, и есть доступный ConfigurationAdmin, поэтому нет никаких исключений при обновлении конфигурации. Но он никогда не применяется как-то.

Я что-то упустил при запуске примера на Felix?

Обновление:

Добавление выходных данных консоли к каждому методу события жизненного цикла приводит к следующему результату:

____________________________
Welcome to Apache Felix Gogo

g! ConfigurationCommand: Activate
ConfigurableService: Activate
WelcomeCommand: Activate
welcome
Service says: null
g! configure Dirk
g! welcome
Service says: null
g! exit 0
WelcomeCommand: Deactivate
ConfigurableService: Deactivate
ConfigurationCommand: Deactivate

Как видите, события модификации и обновления никогда не вызываются.


person Dirk Fauth    schedule 29.04.2016    source источник


Ответы (1)


Я думаю, проблема в жизненном цикле команд Gogo.

Gogo не удерживает служебные объекты, пока команда не выполняется. Он отслеживает ServiceReference, но не вызывает getService до тех пор, пока вы не вызовете команду welcome. Поэтому, когда вы вызываете welcome, будет создан экземпляр компонента WelcomeCommand, что вызывает создание экземпляра ConfigurableService в это время.

Позже, когда команда welcome завершается, WelcomeCommand освобождается, поэтому и WelcomeCommand, и ConfigurableService будут GC'ированы. Поэтому ни один экземпляр ConfigurableService никогда не живет достаточно долго, чтобы получить событие Modified.

Чтобы решить эту проблему, попробуйте сделать WelcomeCommand немедленным:

@Component(immediate = true, ...)

ОБНОВЛЕНИЕ

При дальнейшем обсуждении с Дирком по электронной почте выяснилось, что проблема заключается в привязке к местоположению. В Config Admin конфигурации по умолчанию «привязаны» к пакету, который их создает, в данном случае к пакету, который содержит ConfigurationCommand. После привязки они не могут быть использованы другим пакетом, поэтому ConfigurableService никогда не увидит конфиг.

Чтобы создать несвязанную конфигурацию, которую может использовать любой пакет, вызовите версию ConfigAdmin.getConfiguration() с двумя аргументами и передайте null в качестве второго аргумента.

person Neil Bartlett    schedule 29.04.2016
comment
Не могли бы вы проверить (используя команды scr:list и scr:info), что ConfigurableService действительно работает и экземпляр существует. Также, пожалуйста, избавьтесь от unbind="-", он не нужен, и я не знаю, какие у него могут быть побочные эффекты. - person Neil Bartlett; 29.04.2016
comment
Я удалил атрибут unbind="-". Я просто добавил его, потому что в спецификации сказано, что необходимо явно указать, что нет метода развязки. Новая поддержка аннотаций DS в Neon жалуется на иное. Для Феликса я перешел на Bndtools, и нет проблем с отсутствующим методом отмены привязки. Тем не менее это ничего не меняет. с помощью scr:list и scr:info покажите, что ConfigurableService активен (State: active). Для меня все выглядит нормально. Есть ли что-то особенное, что я должен искать? - person Dirk Fauth; 29.04.2016
comment
В спецификации об этом вообще не говорится, поэтому поддержку аннотаций DS в Neon необходимо исправить. Вам нужно только сказать unbind=-, если существует метод, конфликтующий с предполагаемым именем метода unbind. т.е. у вас есть метод с именем unsetConfigAdmin, но вы НЕ хотите, чтобы он использовался в качестве метода отмены привязки для setConfigAdmin. - person Neil Bartlett; 29.04.2016
comment
Что касается оставшихся проблем жизненного цикла... становится сложно отлаживать на таком расстоянии. Может быть, если вы поместите операторы печати в каждый из методов привязки/отвязки/обновления и методы активации/деактивации, а затем выгрузите вывод здесь? - person Neil Bartlett; 29.04.2016
comment
Извините, моя ошибка, это не спецификация, это Javadoc @Reference, в котором говорится: Чтобы объявить метод отмены привязки, необходимо использовать значение {@code -}.. Я добавил выходные данные консоли в каждый из методов, а также настроил команду ConfigureCommand для немедленного запуска. Я добавил вывод в исходный вопрос по причинам форматирования. - person Dirk Fauth; 29.04.2016
comment
Какая версия JavaDoc? Версия, которая у меня есть, выглядит следующим образом... Чтобы не объявлять метод отмены привязки, когда тип компонента содержит метод с именем-кандидатом, необходимо использовать значение {@code -}. (выделение добавлено). - person Neil Bartlett; 29.04.2016
comment
Думаю, DS 1.2, так как Equinox еще не поддерживает 1.3. - person Dirk Fauth; 29.04.2016
comment
Хорошо, я вижу это в компендиуме R5. Я предполагаю, что формулировка не так ясна, как должна быть, поэтому они обновили ее в R6. Несмотря на это, никогда не было необходимости указывать unbind=-, если только у вас не возникает конфликт имен методов. Поэтому я думаю, что это должно быть поднято как ошибка против Neon. - person Neil Bartlett; 29.04.2016
comment
Спасибо за вывод. Я подозреваю, что у вас вообще есть работающий администратор конфигурации. - person Neil Bartlett; 29.04.2016
comment
Пакет службы администрирования конфигурации Apache Felix установлен, разрешен и активен. И ConfigurationCommand получает экземпляр и может работать с ним. Так что я подозреваю, что он там и работает. Есть ли что-нибудь еще, что мне нужно сделать? Или проверить, есть ли он на самом деле? - person Dirk Fauth; 29.04.2016
comment
Для ConfigurationCommand (который является единственным пользователем ConfigAdmin напрямую) он говорит SatisfiedReference: ConfigAdmin. Это то, что вы просили, или вам нужна другая информация? scr:list не показывает ConfigurationAdmin, но я полагаю, потому что это не компонент DS, правильно? - person Dirk Fauth; 29.04.2016
comment
Нет, я имел в виду scr:info для ConfigurableService. Извините, я должен был быть более ясным. Должны ли мы перенести это в чат? - person Neil Bartlett; 29.04.2016
comment
Конечно, давайте перейдем в чат и потом опубликуем решение. Кстати, я только что заметил, что вы можете настроить, будет ли сообщаться об отсутствующем методе развязки как ошибка или его следует игнорировать. По умолчанию используется ошибка, поэтому в Neon нет проблем. Просто конфигурация, которую нужно изменить. - person Dirk Fauth; 29.04.2016
comment
Давайте продолжим обсуждение в чате. - person Dirk Fauth; 29.04.2016
comment
Args, не могу открыть чат из моего текущего местоположения :( - person Dirk Fauth; 29.04.2016
comment
Если значение по умолчанию в Neon — ошибка, то значение по умолчанию неверно, и это ошибка в Neon! - person Neil Bartlett; 29.04.2016