如何在OSGi中正确实现ManagedServiceFactory作为Decalarative服务? [英] How do you properly implement a ManagedServiceFactory as Decalarative Service in OSGi?
问题描述
我有需要在每个配置基础上创建的服务,每个服务依赖于外部资源,因此应该管理其自己的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:
- 手动设置属性
service.pid
感觉像一个脏的黑客对我 - 设置
configuration-policy =忽略
阻止我配置ManagedServiceFactory
自己。如果我转义这个属性或将它设置为require,我会得到一个ManagedServiceFactory
一个名为my.project.servicefactory.cfg
,然后为每个配置命名的两个服务命名为my.project.servicefactory-foobar.cfg
:oneManagedServiceFactory
SCR产生和一个ServiceInterface
,当我收到通知这个新的配置时,我的第一个ManagedServiceFactory
注册。 (至少这不是指数增长,因为SCR覆盖工厂配置的service.pid
属性)
- manually setting the property
service.pid
feels like a dirty hack to me - setting
configuration-policy="ignore"
prevents me from configuring theManagedServiceFactory
itsself. If I escape this property or set it to require, I would get oneManagedServiceFactory
for a configuration namedmy.project.servicefactory.cfg
and then two services for each configuration named with the patternmy.project.servicefactory-foobar.cfg
: oneManagedServiceFactory
that the SCR spawns and oneServiceInterface
that my firstManagedServiceFactory
registers when it gets notified about this new configuration. (At least this is not growing exponetially because SCR overwrites theservice.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屋!