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 <[email protected]> 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
> [email protected]
>
>
> ----- Original message -----
> From: Mark Raynsford <[email protected]>
> Sent by: [email protected]
> To: [email protected]
> 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
> [email protected]
> https://mail.osgi.org/mailman/listinfo/osgi-dev
>
>
> <attccrq0.dat>
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
[email protected]
https://mail.osgi.org/mailman/listinfo/osgi-dev