2

我有需要在每个配置基础上创建的服务,每个服务都依赖于外部资源,因此应该管理它自己的生命周期(即(取消)注册服务)。因此将这些实现为 DS 并让 SCR 产生多个实例是行不通的。

可以实现一个注册 ManagedServiceFactory 的包来完美地完成这项任务(请参阅我的上一篇文章)。但结果是,如果工厂依赖于其他几个服务,您需要开始跟踪这些服务并编写大量胶水代码以使一切运行起来。相反,我想将工厂实现为(单例)声明性服务,SCRManagedServiceFactory在服务注册表中注册 a 。

这是我的尝试:

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.component.ComponentContext;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class Factory implements ManagedServiceFactory {

private BundleContext bundleCtxt;
private Map<String, ServiceRegistration> services;

public void activate(ComponentContext context) throws Exception {
    System.out.println("actiavting...");
    this.bundleCtxt = context.getBundleContext();
    services = new HashMap<String, ServiceRegistration>();
}

public void deactivate(ComponentContext context) {
    for(ServiceRegistration reg : services.values()) {
        System.out.println("deregister " + reg);
        reg.unregister();
    }
    services.clear();
}

@Override
public String getName() {
    System.out.println("returning factory name");
    return "my.project.servicefactory";
}


@Override
public void updated(String pid, Dictionary properties)
        throws ConfigurationException {
    System.out.println("retrieved update for pid " + pid);
    ServiceRegistration reg = services.get(pid);
    if (reg == null) {
        services.put(pid, bundleCtxt.registerService(ServiceInterface.class,
                new Service(), properties));
    } else {
        // i should to some update here
    }
}

@Override
public void deleted(String pid) {
    ServiceRegistration reg = services.get(pid);
    if (reg != null) {
        reg.unregister();
        services.remove(pid);
    }
}
}

和服务描述:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="ignore" name="my.project.servicefactory">
   <implementation class="my.project.factory.Factory"/>
   <service>
      <provide interface="org.osgi.service.cm.ManagedServiceFactory"/>
   </service>
   <property name="service.pid" type="String" value="my.project.servicefactory"/>
</scr:component>

我已经发现服务描述中的“工厂”属性是错误的路径,因为这样组件永远不会ManagedServiceFactory在服务注册表中注册,而是变成ComponentFactory.

作为一种hack,我只是添加了一个组件属性,即

<property name="service.pid" type="String" value="my.project.servicefactory"/>

并补充道configuration-policy="ignore"。这有效:命名的配置my.project.servicefactory-foobar.cfg被交给我的服务,它在服务注册表中注册它们,一切都很好。

但是有两件事我不喜欢:

  1. 手动设置属性service.pid对我来说就像一个肮脏的黑客
  2. 设置configuration-policy="ignore"阻止我配置它ManagedServiceFactory自己。如果我转义此属性或将其设置为要求,我将获得一个ManagedServiceFactory用于命名的配置my.project.servicefactory.cfg,然后为每个使用该模式命名的配置获得两个服务my.project.servicefactory-foobar.cfg:一个ManagedServiceFactory由 SCR 产生,一个ServiceInterface在我ManagedServiceFactory收到有关此新配置的通知时第一次注册. (至少这不会以指数方式增长,因为 SCR 会覆盖service.pid工厂配置的属性)

那么我应该如何正确设置呢?

PS:对于那些想知道我在他们的文件名上引用配置的人:我使用 Felix Fileinstall 进行配置,因此foo.cfg将 PID 放入 ConfigAdmin 中foo,并foo-bar.cfg放入factory -pidfoo中。

4

2 回答 2

3

只需使用无头的 DS 实例、属性并自己注册服务:

@Component(immedate=true, provide={}, serviceFactory=true, configurationPolicy=require)
public class Mine {
    BundleContext context;
    volatile ServiceRegistration r;

    @Activate
    void activate(BundleContext context, Map<String,Object> map) {
         this.context = context;
         track(map);
    }

    @Deactivate
    void deactivate() {
        if ( r != null)
              r.unregisterService();
    }

    void track(Map<String,Object> map) {
       ... // do your remote stuff
       r = context.registerService(...);
       ...
    }
}
于 2012-08-13T07:51:28.710 回答
2

为什么 DS 中对此的支持对您不起作用?见 112.6:

Factory Configuration – If a factory PID exists, with zero or more Configurations, that is equal to the configuration PID, then for each Configuration, a component configuration must be created that will obtain additional component properties from Configuration Admin.

这表示如果您的组件的配置 pid 与 CM 中的工厂 pid 相同,那么 DS 将为工厂 pid 下的每个配置创建一个组件实例。

于 2012-08-08T16:45:34.900 回答