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 <[email protected]> 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 <[email protected]> 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: [email protected]
>>> For additional commands, e-mail: [email protected]
>>>
>>>
>>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
>

Reply via email to