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: depend on several linked services
Date Tue, 23 Sep 2014 07:00:36 GMT
Ok, if I understand correctly:
- createComponent only ever builds one component, as soon as the first 
tracked service (ie. dependency) appears. (1 to n relation)
- createAdapter creates a new component *for each* tracked service which 
appears. (n to n relation)

Note: I'm on DM 3.2 for now, so Component.getService() is what I was 
looking for.

Thanks & regards Philipp

On 23.09.2014 08:41, Pierre De Rop wrote:
> Hi Philipp;
>
> so;  regarding your first question, the
> DependencyManager.createComponent()  method returns a singleton component
> (only one instance is created).
>
> But the createAdapterService() method is a bit different: it's a kind of
> "adapter pattern" applied to OSGi services. An adapter is actually a
> factory that creates another component on top of an existing service that
> is adapted to another interface.
>
> But in the previous example, the DeviceConsumer component is not providing
> an interface (because it seems that you don't need this ?). So, if you have
> two Devices, then two "DeviceConsumer" components will be created, and each
> one will be bound to a Device/DeviceParameter pair.
>
> I have committed a sample code [1], which is illustrating all this, except
> that I adapted the Device interface to a DeviceAccess interface, and the
> DeviceConsumer just tracks the DeviceAccess adapted interface (this example
> has nothing to do with the OSGi device access spec, which I don't know
> about).
>
> Notice that the DeviceAccess adapter service inherits from the Device
> service properties (see the DeviceAccessConsumer code).
>
>
> Regarding your second question, yes you can obtain the service instance
> from the Component interface.
> But there is an api break between DM 3.2.0 and DM 4.0.0.
>
> in DM 3.2.0, you can get the service instance using component.getService()
> method, which returns the Object instance.
>
> but in DM 4.0.0, you will have to call the Component.getInstances() method
> which returns all the component instances. When you use a component
> implemented with several compositions, then you can have multiple object
> instances.
>
> hope this helps;
> cheers;
>
> /Pierre
>
>
> [1]
> http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/device/
>
> On Mon, Sep 22, 2014 at 6:04 PM, Bulu <bulu@romandie.com> wrote:
>
>> Hello Pierre
>> Yes, this is exactly what I need! Thanks so much.
>>
>> A few more questions:
>> - How does createAdapterService differ from createComponent, if you don't
>> publish any service?
>>
>> - When setting custom lifecycle callback methods targetting a separate
>> object
>>
>> createComponent()
>>                  .setImplementation(Consumer.class)
>>                  ...
>>                  .setCallbacks(myManager, "init", "start", "stop",
>> "destroy"));
>>
>> the myManager instance gets the Component object passed in the lifecycle
>> methods
>> (  start(Component c)  ). Can I get the actual object (here the Consumer
>> instance) from this Component?
>>
>> Regards Philipp
>>
>>
>>
>> On 22.09.2014 17:41, Pierre De Rop wrote:
>>
>>> Hello Philipp,
>>>
>>> So, let's see if I understand you correctly:
>>>
>>> - you have N "Device" services (each having a "device.id" service
>>> propery).
>>> - then you have N corresponding DeviceParameter instances, each one also
>>> having a "device.id" service property, matching a corresponding Device.
>>> - and you want to consume each pair of Device / DeviceParameter (having
>>> both the same value for the "device.id" service property).
>>>
>>> So, one possible solution (if I my understanding is correct) could consist
>>> in implementing your Consumer as a DependencyManager "Adapter" component,
>>> and this adapter would then define dynamically from it's init() method an
>>> extra dependency on the DeviceParameter, by reusing the id from the
>>> original Device service.
>>>
>>> Let's see what it could look like using a sample code. First here are the
>>> sample for the Device/DeviceParameter related classes:
>>>
>>> public interface Device {
>>>       int getDeviceId();
>>> }
>>>
>>> public class DeviceImpl implements Device {
>>>       final int id;
>>>
>>>       DeviceImpl(int id) {
>>>           this.id = id;
>>>       }
>>>
>>>       @Override
>>>       public int getDeviceId() {
>>>           return id;
>>>       }
>>> }
>>>
>>> public interface DeviceParameter {
>>>       int getDeviceId();
>>> }
>>>
>>> public class DeviceParameterImpl implements DeviceParameter {
>>>       final int id;
>>>
>>>       DeviceParameterImpl(int id) {
>>>           this.id = id;
>>>       }
>>>
>>>       @Override
>>>       public int getDeviceId() {
>>>           return id;
>>>       }
>>> }
>>>
>>> Now, let's define an Activator which creates two pair of
>>> Device/DeviceParameter:
>>>
>>>
>>> public class Activator extends DependencyActivatorBase {
>>>       @Override
>>>       public void init(BundleContext context, DependencyManager dm) throws
>>> Exception {
>>>           createDeviceAndParameter(dm, 1);
>>>           createDeviceAndParameter(dm, 2);
>>>       }
>>>
>>>       private void createDeviceAndParameter(DependencyManager dm, int id)
>>> {
>>>           Hashtable<String, Object> props = new Hashtable<>();
>>>           props.put("device.id", id);
>>>           dm.add(createComponent()
>>>               .setImplementation(new
>>> DeviceImpl(id)).setInterface(Device.class.getName(), props));
>>>
>>>           props = new Hashtable<>();
>>>           props.put("device.id", id);
>>>           dm.add(createComponent()
>>>               .setImplementation(new
>>> DeviceParameterImpl(id)).setInterface(DeviceParameter.class.getName(),
>>> props));
>>>       }
>>> }
>>>
>>> Now, here is the DeviceConsumer: First, let's add a declaration in the
>>> Activator.init method, which defines the DeviceConsumer as an "Adapter":
>>>
>>>           dm.add(createAdapterService(Device.class, null)
>>>               .setImplementation(DeviceConsumer.class));
>>>
>>> This says that we'll instantiate a DeviceConsumer component (which is here
>>> not providing a service) when a Device services comes up.
>>>
>>> And now, we define the DeviceConsumer like this:
>>> (Notice the init method, where we declare an extra dependency, dynamically
>>> created using the device id of the initially injected Device object)
>>>
>>> public class DeviceConsumer {
>>>       volatile Device device; // injected before init()
>>>       volatile DeviceParameter deviceParameter; // extra dependency defined
>>> from init(), but injected before start()
>>>
>>>       void init(Component c) {
>>>           // Dynamically add a dependency on the corresponding
>>> DeviceParameter service.
>>>           DependencyManager dm = c.getDependencyManager();
>>>           c.add(dm.createServiceDependency()
>>>               .setService(DeviceParameter.class, "(device.id=" +
>>> device.getDeviceId() + ")")
>>>               .setRequired(true));
>>>       }
>>>
>>>       void start() {
>>>           // At this point, we have been injected with
>>> theDevice/DeviceParameter pair.
>>>           System.out.println("Created a DeviceConsumer for device id " +
>>> device.getDeviceId() + ", device parameter id "
>>>               + deviceParameter.getDeviceId());
>>>       }
>>> }
>>>
>>> So, in the init() method, we are using the id of the injected Device in
>>> order to create an extra dependency on the corresponding DeviceParameter.
>>> And, when the init() method returns, Dependency Manager will recalculate
>>> the dependencies, and when the corresponding DeviceParameter comes in,
>>> then
>>> it will be auto-injected in the "deviceParameter" field and then, your
>>> start () method will be called, where you can manipulate the pair of
>>> Device/DeviceParameter.
>>>
>>> One important remark: the above code works with the upcomming DM 4.0.0
>>> (currently committed in the Felix sandbox, from [1]), but if you are using
>>> the currently released DM (3.2.0), then in your init() method, you will
>>> have to call an extra "setInstanceBound(true)" method:
>>>
>>>       void init(Component c) {
>>>           DependencyManager dm = c.getDependencyManager();
>>>           c.add(dm.createServiceDependency()
>>>               .setService(DeviceParameter.class, "(device.id=" +
>>> device.getDeviceId() + ")")
>>>               .setRequired(true)
>>>               .setInstanceBound(true));
>>>       }
>>>
>>> This "setInstanceBound" method has been removed in the DM 4.0.0 (currently
>>> committed in [1]), but in the DM 3.2.0, you still have to call this method
>>> when you declare extra dependencies from any component's init methods.
>>>
>>> Does this help ? Does this corresponds to what you would need ?
>>>
>>> Since this example is interesting (hope it corresponds to your needs), I
>>> will probably commit it in the sample code from the DM 4.0.0, in [2].
>>>
>>>
>>>
>>> [1]
>>> http://svn.apache.org/viewvc/felix/sandbox/pderop/
>>> dependencymanager-prototype/
>>> [2]
>>> http://svn.apache.org/viewvc/felix/sandbox/pderop/
>>> dependencymanager-prototype/org.apache.felix.dependencymanager.samples/
>>>
>>> cheers;
>>> /Pierre
>>>
>>> On Mon, Sep 22, 2014 at 4:15 PM, Bulu <bulu@romandie.com> wrote:
>>>
>>>   Hello all
>>>> I'm trying Felix Dependency Manager and have come across the following
>>>> case.
>>>>
>>>> For each registered service of type A, I want to create a component, only
>>>> when the corresponding service B is also present. The corresponding
>>>> service
>>>> is determined by a property of A.
>>>>
>>>> Example:
>>>> I have a services of type "Device" which each have a unique property "
>>>> device.id".
>>>> objectClass=com.example.Device
>>>> device.id=device_0001
>>>>
>>>> I have another service DeviceParameter, which uses the same id to
>>>> indicate, it is corresponding to the above device
>>>> objectClass=com.example.DeviceParameter
>>>> device.id=device_0001
>>>>
>>>> Now I want to start a consuming component, which uses both. That is for
>>>> each Device service which appears, create the consumer as soon as the
>>>> corresponding DeviceParameter also appears.
>>>>
>>>> // component, not registered as a service
>>>> class Consumer {
>>>>     // injected by DM. Both are required for Consumer to be built
>>>>     private volatile Device d;
>>>>     private volatile DeviceParameter p;
>>>>     ...
>>>> }
>>>>
>>>> How can this be done in DM?
>>>>
>>>> For the record, my attempt so far:
>>>>           mgr.add(createComponent()
>>>>                   .setImplementation(Consumer.class)
>>>>                   .add(createServiceDependency()
>>>>                           .setRequired(true)
>>>>                           .setService(Device.class.getName()))
>>>>
>>>>                   .add(createServiceDependency()
>>>>                           .setRequired(true)
>>>>                           .setService(DeviceParameter.class.getName(), "(
>>>> device.id=" + ... +")")));
>>>>
>>>> How to fill the filter "..."?
>>>>
>>>> Thanks 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