OSGi修改事件方法不称为

时间:2016-04-29 08:00:58

标签: java osgi apache-felix equinox declarative-services

我正在玩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 shell命令组件来通过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);
  }
}

最后我创建了另一个利用ConfigurableService

的Felix Gogo shell命令组件
@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();
  }
}

如果我使用包含这些组件的bundle启动OSGi应用程序,我希望在最初执行welcome时,我会看到该组件已激活且服务输出为null,因为尚未应用任何配置(确保连续通话时这会发生变化)。如果我之后执行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中的一个问题,我应该为此提出一张票?

菲利克斯:

如果我在Bndtools中的Felix上运行相同的示例,则不会调用修改方法和更新方法。我检查了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

如您所见,永远不会调用修改和更新的事件。

1 个答案:

答案 0 :(得分:3)

我认为问题是Gogo命令的生命周期。

当命令未运行时,Gogo不会保留服务对象。它会跟踪ServiceReference,但在您实际调用getService命令之前不会调用welcome。因此,当您调用welcome时,WelcomeCommand组件将被实例化,这会强制在那时实例化ConfigurableService

稍后当welcome命令完成时,WelcomeCommand被释放,因此WelcomeCommandConfigurableService都将被GC。因此,ConfigurableService的任何实例都没有足够长的时间来接收Modified事件。

要解决此问题,请尝试立即WelcomeCommand

@Component(immediate = true, ...)

<强>更新

通过电子邮件与Dirk进一步讨论,结果是问题是位置绑定。在Config Admin中,配置默认情况下“绑定”到创建它们的包,在这种情况下是包含ConfigurationCommand的包。一旦绑定,它们就不能被另一个bundle使用,因此ConfigurableService永远不会看到配置。

要创建可供任何捆绑包使用的未绑定配置,请调用ConfigAdmin.getConfiguration()的两个arg版本并为第二个arg传递null