Hello Philipp,
On 10 Dec 2014, at 14:43 pm, Bulu <[email protected]> wrote:
> On 09.12.2014 10:18, Marcel Offermans wrote:
>> Hello Philipp,
>>
>>> On 09 Dec 2014, at 10:03 am, Bulu <[email protected]> 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