I think that the most concise way to get what you want while still using DS is 
to use configuration to control the wiring. 

Each of the tagged services should set a target filter for the reference that 
they want injected. This can be set using Config Admin, or just using the 
reference annotation:

@Component(property = "tag = vanilla", immediate = true)
  public class C
  {
    @Reference(target="(tag=vanilla)" 
    B b;
  }

The injected services should then be created using Configuration Admin factory 
configurations, and setting the scope of anything that they use to prototype or 
prototype_required. 

  @Component(configurationPid="foo",
        configurationPolicy=REQUIRED)
  public class B
  {
    @Reference(scope=PROTOTYPE) D d;
  }

With the factory configuration for foo setting tag = vanilla. 

If you also need separate instances of D injected for each B then define them 
as prototype scope services.

  @Component(scope=PROTOTYPE)
  public class D
  {

  }

You will now have a vanilla tagged C injected with a vanilla instance of B 
injected with its own instance of D. 

I hope this helps, despite the phone formatting!

Tim


Sent from my iPhone

> On 14 Jul 2017, at 20:50, BJ Hargrave <hargr...@us.ibm.com> wrote:
> 
> If you need to create unique component instances with specific service 
> property values, then you would need to use ComponentFactory. However, then 
> your components would need to reference the proper ComponentFactory and call 
> it to create the desired instance.
>  
>   @Component(factory="B")
>   public class B
>   {
>     private @Reference D d;
>   }
> 
>   @Component(property = "tag = chocolate", immediate = true)
>   public class A
>   {
>     private B b;
>     private ComponentContext cc;
>     @Activate
>     private void activate(ComponentContext context) {
>       cc = context;
>     }
>     @Reference(target="(component.factory=B)")
>     private void bFactory(ComponentFactory f) {
>       Dictionary<String,String> props = new HashMap<>();
>       props.put("tag", cc.getProperties().get("tag"));
>       b = f.newInstance(props);
>     }
>   }
>  
> This creates a new instance of B for each instance of A. You may not want 
> this.
> --
> 
> BJ Hargrave
> Senior Technical Staff Member, IBM // office: +1 386 848 1781
> OSGi Fellow and CTO of the OSGi Alliance // mobile: +1 386 848 3788
> hargr...@us.ibm.com
>  
>  
> ----- Original message -----
> From: Mark Raynsford <list+org.o...@io7m.com>
> Sent by: osgi-dev-boun...@mail.osgi.org
> To: osgi-dev@mail.osgi.org
> Cc:
> Subject: [osgi-dev] Grouping services instantiated by Declarative Services
> Date: Fri, Jul 14, 2017 3:04 PM
>  
> Hello.
> 
> I have a somewhat unusual problem that would be rather laborious to
> explain here. In order to preserve the sanity of those reading this
> email, I'll try to distill it down to something more abstract.
> 
> I have a situation where I want to instantiate a tree of services, each
> of which share a common "tag" property. When a service A declares a
> reference to another service B, the exact instance of B that is used
> depends on the value of the tag property on A. This needs to work
> transitively.
> 
> To try to illustrate what I mean, a contrived (and obviously
> non-working example):
> 
>   @Component
>   public class D
>   {
> 
>   }
> 
>   @Component
>   public class B
>   {
>     private @Reference D d;
>   }
> 
>   @Component(property = "tag = chocolate", immediate = true)
>   public class A
>   {
>     private @Reference B b;
>   }
> 
>   @Component(property = "tag = vanilla", immediate = true)
>   public class C
>   {
>     private @Reference B b;
>   }
> 
>   @Component(property = "tag = vanilla", immediate = true)
>   public class E
>   {
>     private @Reference D d;
>   }
> 
> The A, C, and E components are the "root" components in this example,
> and the value of the "tag" property will define which specific
> instances of D and B get referenced. For example, assuming an OSGi
> system that magically implemented what I'm trying to do, the above
> arrangement would produce a tree of instances like the following:
> 
>   http://ataxia.io7m.com/2017/07/14/groups.svg.png
> 
> The process would probably go something like this:
> 
> The A component has a "chocolate" tag and refers to B. The system
> instantiates a new B with tag "chocolate" (because there isn't an
> existing one) and returns a reference to it. The same occurs with D
> for the reference in B.
> 
> The C component has a "vanilla" tag and refers to B. The existing
> instance of B with tag "chocolate" is ignored and a new B with tag
> "vanilla" is instantiated and returned to C. The same occurs for the
> reference to D in the "vanilla" B.
> 
> The E component has a "vanilla" tag and refers to B. The existing
> instance of B with tag "vanilla" satisfies the reference.
> 
> Note that at no point do the definitions of B or D refer to "chocolate"
> or "vanilla"; the tag is somehow magically propagated by those instances
> that attempt to get a reference to B or D. Naturally, if a hypothetical
> component G with tag "strawberry" asked for a reference to A, new
> instances of A, B, and D would be instantiated with tag "strawberry".
> 
> Is there some way to do this in DS without dropping down to the OSGi
> APIs like ServiceTracker? I could probably do all of the above manually
> somehow, but I'd prefer not to have to.
> 
> M
>  
> 
> attxrnvn.dat  Type: application/pgp-signature
> Name: attxrnvn.dat
> _______________________________________________
> OSGi Developer Mail List
> osgi-dev@mail.osgi.org
> https://mail.osgi.org/mailman/listinfo/osgi-dev
>  
> 
> <attccrq0.dat>
> _______________________________________________
> OSGi Developer Mail List
> osgi-dev@mail.osgi.org
> https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to