geronimo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rick McGuire <rick...@gmail.com>
Subject Adding OSGi support to Geronimo spec jars.
Date Fri, 26 Feb 2010 13:35:38 GMT
I've been taking a hard look at what Servicemix had done to the various 
spec jars to make them better behaved in an OSGi environment.  This is 
being done with the intent of adding similar support to the base 
Geronimo spec jars.  I'm taking a fresh approach to this rather than 
necessarily just copying what Servicemix is doing.  I've found a number 
of interesting things during this process, so I thought it would be good 
to do a brain dump of what I've found and how I'm planning on 
implementing this.

The basics of the Servicemix approach is to add an Activator to each of 
the spec bundle that maintains a registry of factory class information.  
Each spec bundle have a listener that tracks bundle activity and will 
check for factory information in the META-INF/services directory of each 
started bundle.  Each started bundle has its own listener and own copy 
of the factory information.  The registry information is used in the 
various places spec code needs to dynamically load provider classes for 
different subsystems.  For example, loading a persistence provider.  All 
classloading is done lazily when a request is made for a matching class 
file.  The spec code retrieves the loaded classes and handles all 
details of creating the instances using the retrieved classes.

Jarek Gawor suggested I might want to take a look at what the Aries 
project had for processing the META-INF/services information.  This test 
implementation, called "spifly", uses the OSGi extender pattern to 
inspect the META-INF/services directories and uses that information to 
automatically register services in the OSGi services registry.  In this 
situation, the classes are eagerly loaded, instances are created (which 
requires a no-argument constructor) and the services are registered in 
the OSGi registry.

So, we have one set of information, but two different interpretations of 
how this information should be used.  The new implementation I was 
working on was using the extender pattern to maintain a single registry 
of this information that could be accessed using a provider registry 
service.  This would have a single listener, with a single version of 
the registry, and each bundle that required the service would just have 
a thin accessor layer to call the registry service if it was available.  
This is essentially combining the approaches used by Servicemix and spifly.

However, I was becoming increasingly concerned about this dual 
interpretation of the META-INF/services information, and started 
researching what conventions were in play with this.  What I found was 
there is a new feature in Java SE 6 called the ServiceLoader:

http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html

The service loader uses the META-INF/services information to create 
mappings between interface classes and concrete implementations of these 
interfaces.  This is similar to the spifly approach, but there are a few 
fundamental differences.  The biggest difference is that each instance 
of the ServiceLoader class will instantiate a new instance of the 
implementation class when needed.  For spifly, there is only ever a 
single instance of the service created.  Both spifly and Servicemix are 
only processing the first line of the services files, while the 
ServiceLoader defines that an individual definition file can define a 
one-to-many interface/implementation mapping.  So, now we're up to 3 
different interpretations of the META-INF/services information.

Looking a little deeper into how Servicemix was using this information, 
I found that it was bending the intent of the META-INF/services 
information a bit.  The ServiceLoader definitions are intended to create 
mappings between interface classes and implementers of a given 
interface.  The service mix lookups were being used to directly resolve 
implementation classes.  To do this, the service definition file would 
need to use the same class as both interface name and implementer 
class.  This has a nice side effect of allowing particular 
implementations to be selectively replaced, but this is a usage that 
could cause problems if the information was picked up by either spifly 
or ServiceLoader.  This violated the fundamental assumption that this 
information defined interface-to-implementation mappings.

In addition, the javamail changes were using this information to define 
protocol-to-provider mappings.  For example, an "smtp" javamail provider 
implementation class.  In this case, the mapping did not even start with 
the name of a Java class.  This definitely conflicted with both spifly 
and ServiceLoader.

A lot of these difficulties go away if I decouple the Servicemix 
semantics by moving the information to a different location so that 
we're not seeing multiple interpretations of what the data in 
META-INF/services means.  The code I'm working on will be looking in 
OSGI-INF/providers, and the mapping information is defined in terms of a 
provider identifier-to-provider class mapping.  This is really is the 
interpretation used by the Servicemix code, but removes the conflicting 
usage.

Rick

Mime
View raw message