How to select an appropriate service implementation?
<p>I've created a service with multiple implementations, like so:</p>

<pre><code>@ProviderType
public interface MyService {
    public void printMessage();
}

@Component
public class Foo implements MyService {
    public void printMessage() {
        System.out.println("foo");
    }
}

@Component
public class Bar implements MyService {
    public void printMessage() {
        System.out.println("bar");
    }
}
</code></pre>

<p>The real implementations are obviously a bit more complex (I can't just make a single implementation where <code>printMessage</code> takes an argument!). The consumers of the service need to be able to select an appropriate implementation based on a property - for simplicity, we can assume I'm using the name of the implementation.</p>

<p>The factory method used by the existing non-OSGi implementation is something like this:</p>

<pre><code>public MyService getService(String property) {
    switch (property) {
        case "ham":
            return new Foo();
        case "spam":
            return new Bar();
    }
}
</code></pre>

<p>The real implementation is, again, more complicated (it's based on a substring match of the <code>property</code> parameter). The simplest approach (for me) to convert this to OSGi would be to make this factory method into a static method of <code>MyService</code>, returning only the necessary filter string, and to make consumers take care of the fiddly bits with getting a BundleContext, then getting and ungetting the service:</p>

<pre><code>public class MyConsumer {
    private BundleContext context;

    @Activate
    public void activate(BundleContext context) {
        this.context = context;
    }

    public void doStuff() {
        Collection&lt;ServiceReference&lt;MyService&gt;&gt; refs = context.getServiceReferences(MyService.class, MyService.getService("ham"));
        ServiceReference&lt;MyService&gt; service = refs.iterator().next();
        context.getService(service).printMessage();
        context.ungetService(service);
    }
</code></pre>

<p><strong>Is there a better way to create a "factory" that returns "services", but doesn't require that the consumers deal with BundleContexts etc.?</strong></p>

<p>I've found a couple approaches that won't <em>quite</em> work:</p>

<ul>
<li><code>@Reference(target = "ham")</code> (I know that syntax is wrong) allows me to select an implementation based on a property, but only at compile-time.</li>
<li>A <code>ServiceFactory</code> allows different bundles to get different instances of the service, but not to specify implementation.</li>
</ul>