Hi Jerome, Rob-

I've been thinking about Restlet's osgi deployment issues, and experimenting
with a few things.  (Jerome, please let me know if this sort of post is more
appropriate for the restlet.code list than the restlet.discuss one- I'm happy to
post to either...)

If Restlet is commited to using the ServiceLoader pattern (/META-INF/services/
approach) for it's extension-binding facility, and you don't want to use the
whiteboard pattern in osgi, then I think there may be a better way to handle
osgi deployment, one where you can remove the need for the internal Activator
entirely.

The solution is to make the connector extension bundles into Bundle Fragments. 
This involves only adding an additional Manifest header to the extension bundle
Manifests like so:

  Fragment-Host: org.restlet
  
This declares that the bundle is a fragment, and that its "host" bundle is the
main org.restlet bundle.

Being a fragment means that at runtime the contents of the fragment get added in
to the host, and become effectively part of the host bundle.  All of the
fragment's resources and classes become accessible through the host bundle's
classloader.  This means that when the main restlet's Engine class goes through
its standard discovery process, it will find the extension's
/META-INF/services/Helper resources, and load the extension like normal. 

Getting rid of the org.restlet Activator has the additional benefit of fixing a
nasty bundle-ordering dependency which exists now (where the org.restlet bundle
must not only be installed but also STARTED before any client code can access
it's packages, otherwise the connectors won't be loaded yet).

Any thoughts?  

Does anyone know any reasons why using fragments in this way is a bad idea?

Oh, and by the way, the org.restlet.engine.internal.Activator actually has a bug
with respect to how it iterates over the available bundles (and how it reacts to
Bundle events).  It's algorithm is to ask each bundle whether it contains an
"entry" for a resource name "/META-INF/services/SomeTypeOfHelper", and if it
does it attempts to load the class specified inside that entry.  

This is too permissive- it's important to filter out bundle types/states that
won't work.  In particular, any bundle which is in the INSTALLED state and is
unable to be RESOLVED (due to missing dependencies), or an bundle which is
UNINSTALLED, or any bundle which is a "Fragment" bundle, will throw an exception
when bundle.loadClass() is called on it.

The first few cases can be checked for by looking at the bundle state.  Whether
a bundle is a Fragment can be checked by getting an instance of the PackageAdmin
service (a built-in framework service) and calling
packageAdmin.getBundleType(bundle).

In order for the fragment solution I describe above to work, the activator must
be removed or fixed to not blow up on encountering a fragment...

-Dave

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1346007

Reply via email to