如何在OSGi中正确实现ManagedServiceFactory作为Decalarative服务? [英] How do you properly implement a ManagedServiceFactory as Decalarative Service in OSGi?

查看:199
本文介绍了如何在OSGi中正确实现ManagedServiceFactory作为Decalarative服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have services that need to be created on a per-configuration base, each of which relies on an external resource and thus should manage it's own lifcycle (i.e. (de)register the service). Thus implementing these as DS and let SCR spawn multiple instances does not work.

可以实现注册ManagedServiceFactory的bundle来完美完成这个任务(参见my上一篇文章)。但是结果,如果工厂依赖于其他几个服务,你需要开始跟踪这些服务,并编写大量的胶水代码来获得一切运行。相反,我想实现工厂作为(singleton)声明性服务,为其注册 ManagedServiceFactory 在服务注册表。

One can implement a bundle that registers a ManagedServiceFactory to accomplish this task perfectly (see my previous post). But as a consequence, if the factory depends on several other services, you need to start tracking those services and write a lot of glue code to get everything running. Instead I'd like to implement the factory as (singleton) declarative service, for which the SCR registers a ManagedServiceFactory at the Service Registry.

这是我的尝试:

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);
    }
}
}

/ p>

and the service description:

<?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>

我已经发现服务描述中的factory属性是错误的路径,方式组件从未在服务注册表中注册为 ManagedServiceFactory ,而是成为 ComponentFactory

I already found out that the "factory" property in the service description is the wrong path, because this way the component is never registerd as ManagedServiceFactory in the Service Registry, instead it becomes a ComponentFactory.

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

As a kind of hack, I just added a component property, namely

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

并添加 configuration-policy =ignore。这工作:配置名为 my.project.servicefactory-foobar.cfg 的交给我的服务,它注册他们在服务注册表,一切正常。

and added configuration-policy="ignore". This works: configurations named my.project.servicefactory-foobar.cfg are handed to my service, which registers them as in the Service Registry, everything fine.

但是有两件事我不喜欢:

But theres two things about it i do not like:


  1. 手动设置属性 service.pid 感觉像一个脏的黑客对我

  2. 设置 configuration-policy =忽略阻止我配置 ManagedServiceFactory 自己。如果我转义这个属性或将它设置为require,我会得到一个 ManagedServiceFactory 一个名为 my.project.servicefactory.cfg ,然后为每个配置命名的两个服务命名为 my.project.servicefactory-foobar.cfg :one ManagedServiceFactory SCR产生和一个 ServiceInterface ,当我收到通知这个新的配置时,我的第一个 ManagedServiceFactory 注册。 (至少这不是指数增长,因为SCR覆盖工厂配置的 service.pid 属性)

  1. manually setting the property service.pid feels like a dirty hack to me
  2. setting configuration-policy="ignore" prevents me from configuring the ManagedServiceFactory itsself. If I escape this property or set it to require, I would get one ManagedServiceFactory for a configuration named my.project.servicefactory.cfg and then two services for each configuration named with the pattern my.project.servicefactory-foobar.cfg: one ManagedServiceFactory that the SCR spawns and one ServiceInterface that my first ManagedServiceFactory registers when it gets notified about this new configuration. (At least this is not growing exponetially because SCR overwrites the service.pid property for factory configurations)

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

So how should I set this up properly?

PS:对于那些想知道我的参考文件名的配置:我使用Felix Fileinstall配置,因此 foo.cfg 被放置到PID的 foo 的ConfigAdmin和 foo- bar.cfg 放在 -pid foo

PS: For those wondering about my reference to configurations on their filenames: I use Felix Fileinstall for the configurations, thus foo.cfg is put to the ConfigAdmin for PID foo, and foo-bar.cfg is put there for factory-pid foo.

推荐答案

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

Just use your DS instance headless, the properties, and register the service yourself:

@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(...);
       ...
    }
}

这篇关于如何在OSGi中正确实现ManagedServiceFactory作为Decalarative服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆