felix-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Bulu <b...@romandie.com>
Subject Re: Dependency Manager: publish adapter with properties of the adapted service
Date Thu, 25 Sep 2014 09:39:10 GMT
Yes OK. This is what I'm currently doing.

First publish the adapter as EventHandler and later (in init() ) set the 
properties correctly.
I just thought it wasn't clean.
Thanks again Philipp

On 25.09.2014 11:34, Pierre De Rop wrote:
> Ah ok; I understand.
>
>  From your adapter (DeviceConsumerImpl), in the init() method, just call
> component.setServiceProperties()  instead of component.setInterface method.
>
> Something like this:
>
> class DeviceConsumerImpl implements DeviceConsumer
>      void init(Component c) {
>          DependencyManager dm = c.getDependencyManager();
>
>          // add a dynamic dependency on the DeviceParameter ...
>          c.add(dm.createServiceDependency()
>              .setService(DeviceParameter.class, "(device.id=" +
> device.getDeviceId() + ")")
>              .setRequired(true));
>
>          // Now, set our adapter service properties, which will be appended
> to the republished
>          // adapted service properties !
>
>          Hashtable props = new Hashtable();
>          props.put(EventConstants.EVENT_TOPIC, "my/device/events");
>          props.put(EventConstants.EVENT_FILTER,"(device.id=" +
> device.getDeviceId() + ")");
>          c.setServiceProperties(props);
>      }
>
> This works with DM 4.0.0, but should also work with DM 3.2.0 (but I did not
> have time to test).
>
> regards
> /Pierre
>
> On Thu, Sep 25, 2014 at 11:07 AM, Bulu <bulu@romandie.com> wrote:
>
>> Hello Pierre
>>
>> My example was too simple, I would like to republish the adapter with
>> values from the adapted service, but under new keys.
>>
>> Specifically, the new interface is EventHandler and I want to build the
>> EVENT_FILTER from the adapted service (ie. Device) properties..
>>
>>
>> Dictionary props =new  Hashtable();
>> props.put(EventConstants.EVENT_TOPIC, "my/device/events");
>>
>> props.put(EventConstants.EVENT_FILTER,"(device.id=xxx)"); // xxx comes
>> from the Device instance
>>
>> mgr.add(createAdapterService(Device.class,null)
>>    .setImplementation(DeviceConsumerImpl.class)
>>    .setInterface(EventHandler.class.getName(), props);
>>
>> Philipp
>>
>>
>> On 25.09.2014 10:53, Pierre De Rop wrote:
>>
>>> Hi Philipp;
>>>
>>> On Thu, Sep 25, 2014 at 8:54 AM, Bulu <bulu@romandie.com> wrote:
>>>
>>>   Hello all
>>>> (sorry for asking so many questions - they come-up as I write my code)
>>>>
>>>>   no problem at all :-)
>>>
>>>   In DM, how can you adapt a certain service and re-publish under a new
>>>> interface using some properties of the adapted service?
>>>>
>>>>   When you define an adapter (DeviceConsumer), the service properties of
>>> the
>>> adapted service (Device) are automatically propagated to the new adapter
>>> interface (DeviceConsumer).
>>>
>>>
>>>
>>>
>>>
>>>   Example:
>>>> interface Device{
>>>>     int getId();
>>>> }
>>>> each published with property
>>>> device.id=xxx
>>>> where xxx is the int from getId()
>>>>
>>>> elsewhere, we want to adapt the Device services
>>>> mgr.add(createAdapterService(Device.class,null)
>>>>     .setImplementation(DeviceConsumerImpl.class)
>>>>     .setInterface(DeviceConsumer.class.getName(), props);
>>>>
>>>> here, "props" should again contain the device.id=xxx value, but its not
>>>> yet available, so the above cannot work.
>>>>
>>>>   since the adapted service properties are propagated, I think you don't
>>> need
>>> to pass a props to the setInterface method; just pass "null":
>>>
>>> mgr.add(createAdapterService(Device.class,null)
>>>     .setImplementation(DeviceConsumerImpl.class)
>>>     .setInterface(DeviceConsumer.class.getName(), null);
>>>
>>> If you pass some properties to the setInterface method, those properties
>>> will be appended to the service properties of the original adapted
>>> service,
>>> so in the end the re-publised service will contain the adapted service
>>> properties + the properties you pass to the setInterface methods.
>>>
>>>
>>>
>>> does this help ?
>>>
>>>
>>> regards
>>> /Pierre
>>>
>>>
>>>   We could inject it in the service's init method:
>>>> class DeviceConsumerImpl {
>>>>     Device d;
>>>>     public void init(Component c){
>>>>       Dictionary<String, Object> props = new Hashtable<>();
>>>>       props.put("device.id", d.getId())
>>>>       c.setInterface(DeviceConsumer.class.getName(), props);
>>>> }
>>>>
>>>> but this fails with IllegalStateException (it seems you cannot publish
>>>> (ie. setInterface) a new service while the object is being initialized).
>>>>
>>>> So how should it be done?
>>>>
>>>> I came up with a workaround, which is to publish the service at first
>>>> with
>>>> incomplete properties, and just update them in the init method when the
>>>> values are present. But that seems like a hack... Is there a better way?
>>>>
>>>> Thanks Philipp
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On 24.09.2014 18:09, Pierre De Rop wrote:
>>>>
>>>>   Hi Philipp;
>>>>> see my response, inlined below:
>>>>>
>>>>>
>>>>> On Wed, Sep 24, 2014 at 4:46 PM, Bulu <bulu@romandie.com> wrote:
>>>>>
>>>>>    Hello all
>>>>>
>>>>>> If the published property of a service is based on a value in the
>>>>>> actual
>>>>>> service object, and that value later changes, how can I update the
>>>>>> properties using DM?
>>>>>>
>>>>>> Example: You have Device objects (and the corresponding impl)
>>>>>> public interface Device{
>>>>>>      public int getRoom();
>>>>>>      public void setRoom(int i);
>>>>>> }
>>>>>>
>>>>>> Maybe you originally register the device like this
>>>>>>
>>>>>> Device d = new DeviceImpl();
>>>>>> s.setRoom(12);
>>>>>> Dictionary<String, Object> props = new Hashtable<>();
>>>>>> props.put("room", d.getRoom());
>>>>>> mgr.add(createComponent()
>>>>>>       .setImplementation(d)
>>>>>>       .setInterface(Device.class.getName(), props));
>>>>>>
>>>>>> ... later somebody else (maybe a consumer of the service...) calls
>>>>>> d.setRoom(13)
>>>>>>
>>>>>> How can I update the "room" property of the service?
>>>>>>
>>>>>> I believe I could keep the Component from start(Component c) and
later
>>>>>> use
>>>>>> its setServiceProperties() but is that clean/correct?
>>>>>>
>>>>>>    This is indeed possible, but alternatively, you could also declare
a
>>>>>>
>>>>> ServiceRegistration field in your implementation class, which will be
>>>>> injected once the device service has been registered.
>>>>> And later, from the setRoot(int id)  you can then use the service
>>>>> registration in order to modify or add some service properties.
>>>>>
>>>>>
>>>>>
>>>>>    like so:
>>>>>
>>>>>> class DeviceImpl implements Device {
>>>>>>      private Component c;
>>>>>>      private int room;
>>>>>>      public void start(Component c){
>>>>>>        this.c = c;
>>>>>>      }
>>>>>>
>>>>>>      public void setRoom(int i){
>>>>>>        room = i;
>>>>>>        c.setServiceProperties(c.getServiceProperties().put("room",
i));
>>>>>>      }
>>>>>> }
>>>>>>
>>>>>> Is this correct? Is there a better method or pattern to use? Any
>>>>>> problems
>>>>>> to expect from keeping the Component around?
>>>>>>
>>>>>>    if you use this pattern instead of using the ServiceRegistration,
as
>>>>>>
>>>>> described before, then yes, it would also work, except that there is
a
>>>>> little mistake in the above example: the setServiceProperties takes a
>>>>> Dictionary as parameter, while the c.getServiceProperties().put("room",
>>>>> i)
>>>>> returns an object.
>>>>>
>>>>> Since the Component.getServiceProperties() method returns a copy of the
>>>>> actual service properties, you could then do like this:
>>>>>
>>>>> Dictionary props = component.getServiceProperties();
>>>>> props.put("room", i);
>>>>> component.setServiceProperties(props);
>>>>>
>>>>>
>>>>>    Also, what happens when the service consumer which is calling
>>>>> setRoom(),
>>>>>
>>>>>> is actually filtering on that property, so that his object gets removed
>>>>>> still while he is calling the method?
>>>>>>
>>>>>>    there are two cases:
>>>>>>
>>>>> 1) using DM 3.2.0, if your consumer calls the device.setRoom(int id)
>>>>> method, then at the time this methods calls
>>>>> "component.setServiceProperties()", then the consumer will be
>>>>> synchronously
>>>>> called in it's "changed" callback if one has been defined and if the
>>>>> dependency filter on the device service is still satisfied.
>>>>>
>>>>> And if the consumer dependency filter is not satisfied anymore, then
the
>>>>> consumer will be synchronously called in its stop callback (because the
>>>>> consumer is losing the device service, and the consumer component will
>>>>> then
>>>>> being stopped), and then the consumer "unbind(Device)" callback will
be
>>>>> called (if defined).
>>>>>
>>>>> And at this point, you will then return from the intial invocation of
>>>>> the
>>>>> device.setRoot(int id) method.
>>>>>
>>>>> 2) using DM 4.0.0 (not yet in the trunk, only in sandbox), the same as
>>>>> above applies except if the
>>>>>     parallel Dependency Manager is enabled.
>>>>>
>>>>> Indeed, In DM 4.0.0, you can now optionally register a threadpool in
the
>>>>> service registry, in order to handle all component events concurrently
>>>>> (service depenency management, and lifecycle callbacks).
>>>>> So, in this case, when you would call component.setServiceProperties(),
>>>>> or
>>>>> serviceRegistration.setProperties() method, you would then be
>>>>> asynchronously called in your consumer.stop / consumer.unbind(Device)
>>>>> method.
>>>>>
>>>>> regards;
>>>>> /Pierre
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>    Regards Philipp
>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>>>
>>>>>>
>>>>>>
>>>>>>   ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>
>>>>
>>>>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Mime
View raw message