yes Philipp, this is correct.

kind regards
/pierre


On Tue, Sep 23, 2014 at 9:00 AM, Bulu <[email protected]> wrote:

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

Reply via email to