Dynamically setting target property in OSGi Reference annotatation

拜拜、爱过 提交于 2020-01-06 02:32:05

问题


After reading an article on Reference target (and corresponding properties), I still don't understand how to retrieve a service, when target is set at runtime (typically target and properties are set at compile time and evaluated by SCR at runtime).

Let's say there are three service implementations defining@Property(name="type", value="csv"), @Property(name="type", value="xls") and @Property(name="type", value="pdf"), respectively.

And one consumer with:

//@Reference(target="(type=%runtime_variable%)")
Service service;

NOTE %runtime_variable% is automatically evaluated at runtime (read from a settings file).


Should I just call getServiceReferences(Class<S> clazz, String filter) in the @Activate/@Modified annotated method in order to get the right service at runtime?

How is the component.xml created, if I don't explicitly use @Reference and dynamically set the target in the @Activate/@Modified annotated method?

And can I use the@Designate metatype annotation to make my life simpler here?


回答1:


That article, you have read, is 7 year old and it is not clear to me which annotations it uses (yes, there are several). I'd suggest to ignore it. Today you better use Declarative Services (DS) and the standard OSGi annotations.

In short there are 2 important pieces:

  • XML files in /OSGI-INF folder inside the bundles providing / consuming services
  • Service Component Runtime (SCR) - a bundle that inspects other bundles at runtime and if it finds the above XML files, takes care of registering and wiring the services.

While you can write the XML files by hand, they are typically generated by Bnd or other build tools using Bnd (such us bnd-maven-plugin). This is done at build time when Bnd inspects your classes for annotations and uses the information provided to generate the XML files. Thus the annotations are not used at all at runtime.

As for the wiring, when you have

   @Reference(target="(type=pdf)")
   Service service;

The field service will be automatically wired to one of the instances (yes there can be more than one) of Service service registered in OSGi's service registry that matches the target filter. This is done at runtime by SCR. You can change the target at runtime by reconfiguring your component using its PID. You can do that programmatically or via properties files using Configuration Admin.

The @Designate annotation you mentioned relates to another OSGi specification called Metatype. It allows you to better define the types of the configuration fields. Here you can read more about how to use Metatype together with Declarative Services 1.3.

Another good source of information regarding OSGi annotations is here (ignore the Liferay specific ones)


To reflect your edited question, you have some options. One is to get all instances:

@Reference(
 cardinality = ReferenceCardinality.MULTIPLE,
 policy = ReferencePolicy.DYNAMIC,
 policyOption = ReferencePolicyOption.GREEDY
 )
protected void setService(Service service, Map<String, Object> properties) {
   String type = MapUtil.getString(properties, "type");
   _services.put(type, service);
}

Then you can get your service from _services map by type. Another is reconfigure your component. For example if you define it like this

@Component(
 configurationPid = "my.component"
)
public class MyComponent implements ... {
   @Reference(target="(type=pdf)")
   Service myService;
}    

you can configure it via my.component.cfg in which you specify

myService.target=(type=somethingElse)

You can do the same programmatically using the Configuration Admin API.




回答2:


Simply use

@Reference
Service myService;

At runtime you then create a configuration for your component and set a filter like this:

myService.target=(mykey=1)



回答3:


You could do something like this:

@Property(name = "myService.target", label = "My Service", description = "The target reference for the MyService, e.g. use target=(type=html) to bind to services by type.")
@Reference(name = "myService")
private Service myService;

you can then create configuration file for you component com.example.impl.MyComponent.config :

myService.target="(type\=pdf)"

you could also change this value on runtime using Apache Felix Web Console (http://localhost:8888/system/console/configMgr).



来源:https://stackoverflow.com/questions/47393876/dynamically-setting-target-property-in-osgi-reference-annotatation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!