Hello Mark, Tell me, why is this problem any harder under OSGi than with ServiceLoader?? In both cases, anybody can install a bundle or a JAR that provides a service with a name, and those names can collide.
In both ServiceLoader and OSGi there is a simple rule for selecting a single instance of a service where many are available. Under ServiceLoader it is just the first JAR on the classpath. With OSGi you can attach a service.ranking property to any service. This can be done by the developer of the service, or supplied/overridden at runtime using Config Admin. Note that even with service.ranking, it is possible to have multiple service with the same high ranking. In this case OSGi picks the service with the lowest service.id, which in effect usually means the one that was registered first. By the way it is generally bad practice to provide a service name via a method on the service interface. Better to add this as a property to the service metadata, so that it can be selected using declarative filters. For example: @Component(property = “name=JPEG”) public class JPEGImageFormat implements ImageFormat { … } @Component public class PaintProgram { @Reference(target = “(name=JPEG)”) ImageFormat formatter; // ... } Regards, Neil > On 21 Jul 2017, at 19:26, Mark Raynsford <list+org.o...@io7m.com> wrote: > > Hello. > > Consider an API like ImageIO. To write an image in the PNG format, one > calls: > > ImageIO.write(image, "PNG", output); > > The implementation of the write() method gets a list of the available > formats via ServiceLoader and picks the one named "PNG". The "PNG" > value is the sole criteria used to pick an image format provider. > > In OSGi, we'd use the whiteboard pattern (probably with declarative > services) to implement this. The implementation might look something > like: > > interface ImageFormat > { > String name(); > ... > } > > @Component > public final class ImageFormats > { > private final ConcurrentHashMap<String, ImageFormat> formats = > new ConcurrentHashMap<String, ImageFormat>(); > > @Reference( > cardinality = ReferenceCardinality.MULTIPLE, > policy = ReferencePolicy.DYNAMIC, > unbind = "onFormatUnregister") > public void onFormatRegister( > final ImageFormat format) > { > this.formats.put(format.name(), format); > } > > public void onFormatUnregister( > final ImageFormat format) > { > this.formats.remove(format.name(), format); > } > > ... > } > > This would work perfectly well, but what happens if two bundles > try to register a format with the same name? We could check for > and reject registrations with overlapping names, but that might > leave developers/users stuck with a format implementation that > they don't like. What if two different versions of the same bundle > are installed, and both try to register themselves? > > This is a problem that seems to come up in various guises each > time I work with OSGi, and I've not really seen a satisfactory > solution to it. Many solutions involve bubbling up the entirely > internal concern of there being multiple versions of a format > provider present to the API, and although this can work, it does > mean that users are then forced to intelligently pick providers > ("I just want PNG, why do I have to care which of the providers > I end up with?! Isn't the ImageFormats class supposed to pick > for me?!"). Part of this problem is caused by the fact that the > ImageFormats class exists at all; users could, for example, > search for services providing ImageFormat themselves via DS or > the OSGi APIs. Sometimes, though, a class analogous to ImageFormats > is necessary, particularly when you expect callers to be OSGi-unaware > and/or you only have very simple selection criteria (like a "PNG" > string). > > How do people that know more about OSGi than I do usually handle > this? > > -- > Mark Raynsford | http://www.io7m.com > _______________________________________________ > 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