On 5/24/2010 8:06 PM, David Blevins wrote:
On May 24, 2010, at 3:49 PM, David Jencks wrote:
On May 24, 2010, at 2:18 PM, David Blevins wrote:
1. Using EJB as an example, how does one say "I am a provider". There is no "i am
the EJB container" interface to implement so what exactly are we looking for?
EJB is not an example. the provider stuff works for 2 situations:
The activator and locator were added to the EJB spec jar. Was that a mistake?
I don't believe it was. There are two sides to this generally. The first
side is the role played by the specs, which generally need to locate a
provider. Typically, the specification defines a search path that
generally searches for 1) a META-INF/services definition, 2) a class
defined in a properties file, and 3) a system property. Depending on the
age of the specification, the order in which these 3 are searched will
vary, and the newest java ee components only define step 1. Generally,
this search order will resolve to the name of a provider class that the
API code will then instantiate to create the provider instance.
The second role is that of the provider class itself. Typically, a
provider jar would use the META-INF/services mechanism to advertise its
availability. The java EE defined mechanism for locating the provider is
to search the classpath for an appropriate META-INF/services file and
load the first definition it locates.
In an OSGi environment, there are a number of problems associated with
the "search the classpath" step, so the ProviderLocator was created.
There are two pieces to this:
1) A provider registry. This is an extender that watches new bundles
being activated, and if the bundle contains the appropriate metadata,
then then the services it exports are made part of a framework-wide
registry.
2) The ProviderLocator. This is how APIs that need to resolve providers
access the registry information. The provider registry is an OSGi
service, so the ProviderLocator needs a bundle context instance to
resolve the service instance. The Activator manages obtaining the bundle
context at activation and setting up a service tracker to give access to
the registry service. The ProviderLocator code manages the details of
locating a loading a service instance and will revert to classic
classpath behavior if used outside of an OSGi environment.
There are two different models in play here for locating a provider
instance. In the first model, the API has been handed the name of the
desired provider directly as a class name. The API could would then
attempt to instantiate that class directly (typically by using the
thread context classloader). In the second model, an appropriate
META-INF/services definition is located using the interface that the
provider is expected to implement as the search key. The services
definition file provides a mapping to the provider class name, which is
then loaded and instantiated. In terms of my search paths defined in the
first paragraph above, 1) is the META-INF/services mode, and 2) and 3)
are the first mode of direct loading.
The provider registry can handle either of these locator modes. If your
provider is already using a META-INF/services model, then the registry
then generally all you need to do is add an SPI-Provider header to your
jar file. Openejb should have this already, but the EJB3 spec code is
not strictly following the EJB specification for locating the provider,
so it is possible it is not.
If your provider needs to be located via a direct load mechanism where
the class name is provided, then you can use an Export-Service-Provider
header to advertise your provider class so the ProviderLocator code can
locate it by name.
So, what should the openejb code be doing? The best solution would be to
create the META-INF/services file that maps EJBContainerProvider to your
implementation class and add the SPI-Provider header. Unfortunately,
there is a gotcha here, in the form of this Jira:
https://issues.apache.org/jira/browse/GERONIMO-5186
The EJB specification says the EJBContainerProvider lookup mechanism
should use only the META-INF/services mechanism, and for each definition
if finds, it should instantiate the service instance and call
createEJBContainer() passing the property bundle that was passed to
EJBContainer.createEJBContainer(). The provider instance is then
responsible for determining if it is the appropriate provider by
examining the provider name in the properties bundle. Here's the wording
from the spec:
The EJBContainer bootstrap class will locate all of the container
providers by their provider configuration files and call
EJBContainerProvider.createEJBContainer(Map<?, ?>) on them in turn until
an appropriate backing provider returns an EJBContainer. A provider may
deem itself as appropriate for the embeddable application if any of the
following are true :
•The javax.ejb.embeddable.provider property was included in the Map
passed to createEJBContainer and the value of the property is the
provider's implementation class.
•No javax.ejb.embeddable.provider property was specified.
If a provider does not qualify as the provider for the embeddable
application, it must return null when createEJBContainer is invoked on it.
Unfortunately, the search mechanism in the Geronimo EJBContainer class
short-cuts this mechanism and checks the provider property directly and
uses that information to directly load the provider class rather than
using the META-INF/services mechanism. I'm guessing this is the normal
mode of operation for openejb. In that case, you need to be using the
Export-Service-Provider header.
I would really like to fix this Jira, but this requires a bit of rework
in the EJBContainer.createEJBContainer() method. Rework that would break
OpenEJB as it exists in its current state. I think the issues in OpenEJB
need to be fixed first, then the spec behavior can be fixed. Here's what
I think needs to be done in OpenEJB:
1) Add the META-INF/services definition mapping the EJBContainerProvider
to the implementation class.
2) Add the SPI-Provider header to opt in to the services registry for
this definition.
3) Add the Export-Service-Provider header to the bundle to also export
the provider class explicitly.
4) Ensure that the implementation of createEJBContainer() properly
implements the behavior of returning null if it is not the correct
provider for the provided configuration.
Assuming this is done, then the spec class can be changed to be
compliant without breaking openejb. During the transitional period, the
Export-ServiceProvider header will allow the provider class to be loaded
using the current spec implementation, and after the Jira is fixed,
META-INF/services mapping will allow it to revert to the specified
mechanism.
Rick
-David