Simple plugin system
Gaelyk sports a plugin system which helps you modularize your applications and enable you to share commonalities between Gaelyk applications.
This page is about creating new plugins. The list of existing plugins can be found in the Plugins section.
What a plugin can do for you
A plugin lets you:
- provide additional groovlets and templates
- contribute new URL routes
- add new categories to enhance existing classes (like third-party libraries)
- define and bind new variables in the binding (the "global" variables available in groovlets and templates)
- provide any kind of static content, such as JavaScript, HTML, images, etc.
- add new libraries (ie. additional JARs)
- and more generally, let you do any initialization at the startup of your application
Possible examples of plugins can:
- provide a "groovy-fied" integration of a third-party library, like nicer JSON support
- create a reusable CRUD administration interface on top of the datastore to easily edit content of all your Gaelyk applications
- install a shopping cart solution or payment system
- setup a lightweight CMS for editing rich content in a rich-media application
- define a bridge with Web 2.0 applications (Facebook Connect, Twitter authentication)
- and more...
Anatomy of a Gaelyk plugin
A plugin is actually just some content you'll drop in your war/ folder, at the root of your Gaelyk application!
This is why you can add all kind of static content, as well as groovlets and templates, or additional JARs in WEB-INF/lib.
Furthermore, plugins don't even need to be external plugins that you install in your applications,
but you can just customize your application by using the conventions and capabilities offered by the plugin system.
Then, you really just need to have /WEB-INF/plugins.groovy referencing
/WEB-INF/plugins/myPluginDescriptor.groovy, your plugin descriptor.
In addition to that, you'll have to create a plugin descriptor will allow you to define new binding variables,
new routes, new categories, and any initialization code your plugin may need on application startup.
This plugin descriptor should be placed in WEB-INF/plugins and will be a normal groovy script.
From this script, you can even access the Google App Engine services, which are available in the binding of the script --
hence available somehow as pseudo global variables inside your scripts.
Also, this plugin descriptor script should be referenced in the plugins.groovy script in WEB-INF/
Hierarchy
As hinted above, the content of a plugin would look something like the following hierarchy:
/
+-- war
|
+-- someTemplate.gtpl // your templates
|
+-- css
+-- images // your static content
+-- js
|
+-- WEB-INF
|
+-- plugins.groovy // the list of plugins
| // descriptors to be installed
+-- plugins
| |
| +-- myPluginDescriptor.groovy // your plugin descriptor
|
+-- groovy
| |
| +-- myGroovlet.groovy // your groovlets
|
+-- includes
| |
| +-- someInclude.gtpl // your includes
|
+-- classes // compiled classes
| // like categories
+-- lib
|
+-- my-additional-dependency.jar // your JARs
We'll look at the plugin descriptor in a moment, but otherwise, all the content you have in your plugin
is actually following the same usual web application conventions in terms of structure,
and the ones usually used by Gaelyk applications (ie. includes, groovlets, etc).
The bare minimum to have a plugin in your application is to have a plugin descriptor,
like /WEB-INF/plugins/myPluginDescriptor.groovy in this example,
that is referenced in /WEB-INF/plugins.groovy.
Developing a plugin is just like developing a normal Gaelyk web application. Follow the usual conventions and describe your plugin in the plugin descriptor. Then afterwards, package it, share it, and install it in your applications.
The plugin descriptor
The plugin descriptor is where you'll be able to tell the Gaelyk runtime to:
- add new variables in the binding of groovlets and templates
- add new routes to the URL routing system
- define new categories to be applied to enrich APIs (GAE, third-party or your own)
- define before / after request actions
- and do any initialization you may need
Here's what a plugin descriptor can look like:
// add imports you need in your descriptor
import net.sf.json.*
import net.sf.json.groovy.*
// add new variables in the binding
binding {
// a simple string variable
jsonLibVersion = "2.3"
// an instance of a class of a third-party JAR
json = new JsonGroovyBuilder()
}
// add new routes with the usual routing system format
routes {
get "/json", forward: "/json.groovy"
}
before {
log.info "Visiting ${request.requestURI}"
binding.uri = request.requestURI
request.message = "Hello"
}
after {
log.info "Exiting ${request.requestURI}"
}
// install a category you've developped
categories jsonlib.JsonlibCategory
// any other initialization code you'd need
// ...
Inside the binding closure block, you just assign a value to a variable.
And this variable will actually be available within your groovlets and templates as implicit variables.
So you can reference them with ${myVar}} in a template,
or use myVar directly inside a groovlet, without having to declare or retrieve it in any way.
Note: a plugin may overwrite the default Gaelyk variable binding, or variable bindings defined by the previous plugin in the initialization chain. In the plugin usage section, you'll learn how to influence the order of loading of plugins.Inside the
routes closure block, you'll put the URL routes following the same syntax
as the one we explained in the URL routing section.
Note: Contrary to binding variables or categories, the first route that matches is the one which is chosen. This means a plugin cannot overwrite the existing application routes, or routes defined by previous plugins in the chain.
Important: If your plugins contribute routes, make sure your application has also configured the routes filter,
as well as defined a WEB-INF/routes.groovy script, otherwise no plugin routes will be present.
In the before and after blocks,
you can access the request, response, log, and binding variables.
The logger name is of the form gaelyk.plugins.myPluginName.
The binding variables allows you to update the variables
that are put in the binding of Groovlets and templates.
The categories method call takes a list of classes
which are Groovy categories.
It's actually just a varargs method taking as many classes as you want.
Wherever in your plugin descriptor, you can put any initialization code you may need in your plugin.
Important: The plugins are loaded once, as soon as the first request is served. So your initialization code, adding binding variables, categories and routes, will only be done once per application load. Knowing that Google App Engine can load and unload apps depending on traffic, this is important to keep in mind as well.
Using a plugin
If you recall, we mentioned the plugins.groovy script.
This is a new script since Gaelyk 0.4, that lives alongside the routes.groovy script
(if you have one) in /WEB-INF.
If you don't have a plugins.groovy script, obviously, no plugin will be installed —
or at least none of the initialization and configuration done in the various plugin descriptors will ever get run.
This plugins.groovy configuration file just lists the plugins you have installed and want to use.
An example will illustrate how you reference a plugin:
install jsonPlugin
Note: For each plugin, you'll have aninstallmethod call, taking as parameter the name of the plugin. This name is actually just the plugin descriptor script name. In this example, this means Gaelyk will loadWEB-INF/plugins/jsonPlugin.groovy.
As mentioned previously while talking about the precedence rules, the order with which the plugins are loaded may have an impact on your application or other plugins previously installed and initialized. But hopefully, such conflicts shouldn't happen too often, and this should be resolved easily, as you have full control over the code you're installing through these plugins to make the necessary amendments should there be any.
When you are using two plugins with before / after request actions,
the order of execution of these actions also depends on the order in which you installed your plugins.
For example, if you have installed pluginOne first and pluginTwo second,
here's the order of execution of the actions and of the Groovlet or template:
- pluginOne's before action
- pluginTwo's before action
- execution of the request
- pluginTwo's after action
- pluginOne's after action
How to distribute and deploy a plugin
If you want to share a plugin you've worked on, you just need to zip everything that constitutes the plugin.
Then you can share this zip, and someone who wishes to install it on his application will just need to unzip it
and pickup the various files of that archive and stick them up in the appropriate directories
in his/her Gaelyk war/ folder, and reference that plugin, as explained in the previous section.
The best way how to share your plugin is by using the plugin catalogue. Fill the form and wait until the plugin is approved.
