Wednesday, August 8, 2007

Groovy Plug-ins: Bundle Activation and Extension Point Processing

I faced an issue with the bundle activation last week. Namely, a bundle activator will not be started if the given bundle doesn't contain any classes. I.e. a bundle activator is provided by my plug-in and the contributor should use this class to enable scripting for the activation routines.

I reported this issue to Eclipse Equinox newsgroup, and the feedback was quite positive in sense of the solutions. Tom Watson purposed some options:

  • Have ScriptExtensionProxy activate the contributing bundle using a transient flag when it creates a proxy (i.e. call Bundle.start(Bundle.START_TRANSIENT)). This would take extra work for ScriptExtensionProxy because it should probably read the Eclipse-LazyStart and/or the new Bundle-ActivationPolicy from OSGi R4.1 specification to verify the bundle is actually lazy activated.

  • Make ScriptExtensionProxy abstract and force contributing groovy bundles to extend it with a real class which exists in the contributing bundle. Then when the extension is constructed it will automatically activate the bundle if it has a lazy activation policy.

The 1st option worked, but it smells like a hack. I think that the contributor should never call the Bundle#start() on its own... FWIW, this method could be available only to the framework and not to the user.
I've sticked to the 2nd option, but instead of making the ScriptExtensionProxy abstract I will leave it as it is, so that user may just declare it in plugin.xml if there's no need for activation.
ScriptBundleActivator is just a facade for calling the activation script, which I presume to be called activator.groovy for now. The start() method call just delegates the work to the start() method of the expando object in the script.

The activator would be useful if the contributing plug-in will have the need for extension point processing, as the INVITATION RULE says: whenever possible, let others contribute to your contributions.

Here's the draft Groovy code for extension point processing in the activator:

import org.eclipse.core.runtime.Platform

def expando = new groovy.util.Expando()

expando.start = { bundleContext ->
def registry = Platform.getPluginRegistry()
def extensionPoint =
registry.getExtensionPoint(
"org.eclipse.soc.scripting.contributor.listeners")

def extensions = extensionPoint.getExtensions()
extensions.each( { extension ->
extension.getConfigurationElements().each({
element ->
def object = element.createExecutableExtension("class")
//do something with the object
})
} )
}
expando // this is the script returning object

While shaping the code above I realized what is the real power of such scripting: NO CASTING! Truly, I didn't think about it before.
Now I have the following:

  1. A proxy for declaring the extensions: read here and here

  2. A bundle activator facade.

This is the basic functionality which may be used for groovy plug-in creation (with some limitations). Currently I'm preparing a demo which could demonstrate how these base classes could be used.
Next, I would like to provide some usability enhancements to the core plug-in: it would be cool to modify the script even if it is already packed and deployed.
P.S. I have also blogged about the progress in my own blog.

No comments: