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] > >

