Hello Philipp,

On 10 Dec 2014, at 14:43 pm, Bulu <b...@romandie.com> wrote:
> On 09.12.2014 10:18, Marcel Offermans wrote:
>> Hello Philipp,
>> 
>>> On 09 Dec 2014, at 10:03 am, Bulu <b...@romandie.com> wrote:
>>> 
>>> In Felix DM, can I publish a certain object as several services / 
>>> interfaces, but each with different properties?
>>> Calling setInterface() multiple times does not seem to do the trick. 
>>> Calling setInterface(String[],Dictionary) will assign the same properties 
>>> to each.
>>> 
>>> If I use several interface (with that last call), can I change the 
>>> properties in init(). I see I can do the following, but that changes the 
>>> one set of properties for all interfaces
>>> 
>>> public void init(Component c){
>>>  ...
>>>  Dictionary<String, Object> props = c.getServiceProperties();
>>>  props.put(someKey, someValue);
>>>  c.setServiceProperties(props);
>>> }
>> OSGi allows you to publish a service with multiple interfaces, but the 
>> properties then apply to all of them. DM follows that model, so what you’re 
>> seeing makes sense from that point of view. If you want different 
>> properties, you have to define multiple DM “components” (which can all use 
>> the same instance if that’s what you want).
> 
> If the component is instantiated only when the dependencies are met, can this 
> approach also be used?
> 
> Component c1 = Component compo = createAdapterService(Device.class, null)
>  .setImplementation(DeviceAdapterImpl.class)
>  .setInterface(DeviceAdapter.class.getName(), null);
> mgr.add(compo);
> 
> // here also publish all instances of the component (ie. for each adapted 
> Device) as an EventHandler with properties topic & filter.

If you have an adapter, it will create an instance of DeviceAdapterImpl for 
every Device it finds. That makes it a bit harder to create a second component 
based on that same implementation, because only after the adapter instance has 
been created can you try to use it in a second component. I would take this 
approach:

in your activator:

mgr.add(createAdapterService(…)…); // basically with the same interface and 
implementation you had

in DeviceAdapterImpl create an init / destroy method as follows:

private Component c2;

void init(Component c) {
  dm = c.getDependencyManager();
  c2 = dm.createComponent()
    .setInterface(EventHandler.class.getName(), propsForTopicAndFilter)
    .setImplementation(this);
  dm.add(c2);
}

void destroy(Component c) {
  dm = c.getDependencyManager();
  dm.remove(c2);
}

So as soon as you have an instance created by the adapter, in its init method 
create another component, with the right service interface and properties, and 
in the destroy clean up again.

However, in your example, if you need the adapter to publish both as 
DeviceAdapter and as EventHandler, why not just register it as both and have 
the properties for topic/filter available on both interfaces. They are not used 
for DeviceAdapter, but that is not really a problem. Service properties that 
have no special meaning for a service can in general be ignored.

>>> Unrelated: can I use component as a dependency without publishing it as a 
>>> service? Like so:
>> You might have hit “send” too soon… You cannot depend on something that is 
>> not a service. You can have a component that does not publish a service but 
>> does have dependencies on other services.
>> 
>> Well, the only thing you could do is implement some custom form of 
>> dependency, but that would then have to lookup components in a registry. 
>> Which almost sounds like another service registry. :)
>> 
>> 
> OK too bad. My tendency was to use DM as a more general dependency injection 
> framework. But I'm reluctant to publish a service just to acquire it again in 
> the same bundle, because it then becomes public API.

Well, that is not necessarily true:

If you publish a service, as an interface or class, that is private to your 
bundle, then it will be in the service registry, but since nobody else outside 
your bundle will be able to access that class or interface so effectively it 
will be invisible. The only way to “see” it is to getAllServiceReferences() 
instead.

Another option is to use a component that consists of a composition, instead of 
a single instance. A composition is a fixed collection of instances associated 
with a component. All dependencies that are declared on that component will be 
injected into all instances in the collection. This is probably not the best 
way to “privately” publish a service and consume it in the same bundle, but it 
might be something that comes in handy in similar situations.

Greetings, Marcel

Reply via email to