你如何正确地实施ManagedServiceFactory作为Decalarative服务的OSGi

2019-07-30 21:06发布

我有需要在每个配置中的基础,其中的每一个依赖于外部资源创造的,因此服务应该管理它自己的lifcycle(即(DE)注册服务)。 因此,实现这些为DS,让SCR产卵多个实例不起作用。

一个可以实现注册一个ManagedServiceFactory完美地完成这项任务(见一束我以前的帖子 )。 但作为一个结果,如果工厂取决于其他一些服务,你需要开始跟踪这些服务,并写了很多的胶水代码让一切运行。 相反,我想实现这个工厂(单)声明的服务,为此,SCR注册一个ManagedServiceFactory在服务注册。

这里是我的尝试:

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>

我已经发现,在服务描述的“工厂”属性是走错了路,因为这样一来该组件从未registerd为ManagedServiceFactory在服务注册,而不是将其变成一个ComponentFactory

作为一种黑客攻击,我只是增加了一个组件属性,即

<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 itsself。 如果我难逃此属性或将其设置为需要,我会得到一个ManagedServiceFactory的配置命名my.project.servicefactory.cfg然后两个服务与图案命名的每个配置my.project.servicefactory-foobar.cfg :一个ManagedServiceFactory该SCR产卵和一个ServiceInterface ,我的第一ManagedServiceFactory寄存器时,它被通知对这个新的配置。 (至少,这并不exponetially增长,因为SCR覆盖service.pid属性的工厂配置)

所以,我应该怎么设置这正常吗?

PS:对于那些想知道我自己参考自己的配置文件名:我用菲利克斯Fileinstall的配置,从而foo.cfg被付诸ConfigAdmin为PID foofoo-bar.cfg是放在那里的工厂 -pid foo

Answer 1:

只要用你的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(...);
       ...
    }
}


Answer 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下的每个配置创建组件的一个实例。



文章来源: How do you properly implement a ManagedServiceFactory as Decalarative Service in OSGi?