On 2017-07-22T00:22:31 +0100 Neil Bartlett <njbartl...@gmail.com> wrote:
> Hello Mark, 'Ello. > > 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 Java < 9, it's not so much that it can't happen, but more that having two different versions of the same jar file on the classpath is considered a mistake, and build tools like Maven will (via the Enforcer plugin) try to prevent that from happening. In Java 9, it's explicitly an error for two modular jars in the same ModuleLayer to export the same package, so the program won't even start up if you try it. In OSGi, having multiple versions of a bundle installed and running is not considered an error (although it's probably not exactly encouraged either), so the hypothetical ImageFormats class that tracks providers by name would give inconsistent results in that situation. > 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. Yes, I'm aware. As I mentioned in the other message to this list, using the service ranking and ID would *probably* be fine given a very long-running framework instance, because the ordering of service.id will most likely reflect the order in which a given set of bundle versions were installed. However, if you start up a new framework instance with a set of bundles already in the bundle cache, there's nothing that guarantees that the older bundle versions will get lower service IDs, right? > 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; > // ... > } I'd tend to agree, but I did make this point: > 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). In other words, if you're writing code that is expected to work both when running in an OSGi framework and when running on the classpath or module path, you may want/need to abstract over the registration of ImageFormats. In other words, you might want to provide a hypothetical ImageFormatRegistry interface that _both OSGi and non-OSGi consumers_ can make calls into to find image formats (to avoid having to write one code path for OSGi, and one code path for everyone else). Outside of OSGi, the best-practice rules for Java < 9 make multiple registrations of an ImageFormat less likely. The strict Java 9 rules regarding conflicting package exports make multiple registrations impossible, at least when those registrations come from two different versions of the same modular jar. In an OSGi framework, however, the situation is slightly more permissive than the Java < 9 case; multiple installed versions of a bundle are a reality, and complicate the implementation of ImageFormatRegistry class. -- Mark Raynsford | http://www.io7m.com
pgpBwD4wj7x6x.pgp
Description: OpenPGP digital signature
_______________________________________________ OSGi Developer Mail List osgi-dev@mail.osgi.org https://mail.osgi.org/mailman/listinfo/osgi-dev