Chapter 16. Plugin development


In this chapter

  • How plugins work
  • Writing your own plugins
  • Managing plugin repositories

We looked at build integration and project management in the previous chapter, so now we’ll look at a way to modularize and extend your application by developing your own plugins. We introduced you to the Grails plugin system back in chapter 8, and you saw then how useful plugins can be. They’re a fundamental and powerful part of the Grails infrastructure, and even if you never need to write your own plugins, understanding how the system works will set you in good stead for the future.

When might you need or want to create your own plugin? We don’t want to limit your thinking on this, but here are three common uses:

  • Integrating an existing library or tool into Grails
  • Providing a specific feature
  • Modularizing an application

You’ve already seen many examples of the first use, such as Searchable (which integrates Compass), Spring Security, and others. The Authentication and Functional Test plugins are examples of the second use, providing access control and functional testing respectively. The difference between those two uses is more technical than practical, so it’s not necessarily worth distinguishing between them.

The last common use we listed relates to breaking an application into modules. This doesn’t make sense for a small application like Hubbub, but large applications can easily become difficult to maintain and understand if they remain monolithic. Breaking the application’s functionality into individual plugins helps counter those problems, and you can then reuse those plugins in other applications. This approach works particularly well if you maintain a separation of concerns. For example, imagine you have a business application that handles invoicing, payroll, business tax, and so on. Each of these “features” could be implemented using plugins, which you could then install into a single project to create the application. The plugins could even be developed by separate teams.

Now that you know why you might want to develop a plugin, it’s time to jump into the deep end and look at how to do it. In this chapter, we’ll use the example of writing a security plugin for our Hubbub application. This may seem like a stupid idea, because we already have the Spring Security plugin in place, but bear with us. It’s a useful way of demonstrating all the important features we want to discuss.

16.1. Creating your first plugin

You always have to start somewhere, and developing a Grails plugin is no different. In this section, we’ll create a project for our security plugin and lay the first bricks. In this case, that means adding some artifacts, much as we do when creating a new Grails application.

16.1.1. Are you sure it’s not an application?

So how do we go about creating a plugin project? That’s easy—we start with a magic incantation:

grails create-plugin security

This will create a directory named security and populate it with the skeleton of a plugin project, as shown in figure 16.1. It’s no coincidence that the project looks a lot like a Grails application. You can run it like one using the regular run-app command—useful for testing.

Figure 16.1. The directory structure of a plugin project. Note how it’s almost identical to the structure of a Grails application. The plugin descriptor is highlighted.

The most visible difference between a plugin and an application is the presence of a plugin descriptor, the SecurityGrailsPlugin.groovy file (highlighted in figure 16.1). The descriptor not only contains information about the plugin, such as the author and a description of what it does, but it also contains the code that allows you to hook into Grails and modify the behavior of applications at runtime.

The name of the plugin descriptor class is important, because it determines the official plugin name. Rather than store the name in a field of the class, Grails infers it by chopping off the “GrailsPlugin” suffix, converting uppercase letters to lowercase, and separating words with a hyphen. For example, SecurityGrailsPlugin becomes security and MyTagsGrailsPlugin becomes my-tags.

Now let’s take a look at the descriptor we just created. Listing 16.1 contains a slightly condensed version of its initial contents.

Listing 16.1. Initial plugin descriptor

We start with the version and dependency information for the plugin . The version field contains the plugin’s current version. Although the initial value is a number, you can also use a string. That means “0.1-SNAPSHOT” and “merlin” are also valid versions. That said, Grails expects plugins to use a major.minor.patch numbering convention, where each part is an integer and the final patch number is optional. For example, both 1.0.4 and 2.1 follow the convention. Appending a “-SNAPSHOT” suffix is common when releasing a development version, such as when you want to solicit feedback on changes to a plugin.

The grailsVersion field indicates which versions of Grails the plugin works with. This can either be a single version or a range of the form:

lowerBound > upperBound

You should read this as “any version from lowerBound up to upperBound, inclusive.” You can also use the wildcard (*) for either bound. This means “any version up to and including 1.1”:

* > 1.1

This one means “any version from 1.0 upwards”:

1.0 > *

These ranges also work in the dependsOn field, which is a map of plugin names to versions (or version ranges). For example, if a plugin depends on the Quartz and Remoting plugins, it might include this line:

def dependsOn = [ quartz: "0.4", remoting: "0.3 > *" ]

Note that there is no equivalent range syntax using the < symbol.

Next we have the pluginExcludes field . Grails packages the files that make up a plugin into a zip file. You may not want some of those files packaged, particularly if they’re only used for testing, and you can exclude them by adding their paths to the pluginExcludes field. We’ll look further at packaging a plugin in section 16.2.

The plugin information specified in is mainly for the benefit of end users. The list-plugins command will display the plugin name and its title, and plugin-info will display all the fields.

As for the documentation field , that’s a URL pointing to whatever documentation the plugin has. Most plugins in the central Grails repository have one or more pages on the Grails web site.

After the documentation field, things get more interesting. Those doWith* and on* closures are the hooks that allow our plugin to influence the runtime behavior of the application. These are key to providing smooth integration with Grails, such as that provided by GORM. Table 16.1 briefly describes what each of the hooks allows you to do and lists the arguments Grails passes to the associated closure. The first three are shown in the order in which Grails invokes them on application startup.

Table 16.1. The hooks that allow a plugin to integrate closely with a Grails application

Property

Arguments

Description

doWithSpring

none

This closure allows you to define and configure Spring beans.

doWithDynamicMethods

applicationContext

This closure allows you to add dynamic properties and methods to classes and artifacts. Its sole argument is the fully configured Spring application context.

doWithApplicationContext

applicationContext

This closure allows you to work with the fully configured Spring application context. You can only manipulate bean instances, not bean definitions.

doWithWebDescriptor

webXml

This closure allows you to modify the application’s web descriptor. It is passed a GPathResult object (created by XmlSlurper) that you can use to insert elements, such as servlet and filter definitions.

onChange

event

This closure allows you to react to changes to any artifacts that the plugin is watching.

onConfigChange

event

This closure allows you to react to changes to the application’s Config.groovy file.

onShutdown

event

This closure allows you to react when the application shuts down. The Spring application context is still available at this point

Note that all of the hooks are closures; if you try to use a method instead, it won’t be executed. We’ll come back to these hooks in the next section, but they’re only part of the story. We’ll first look at how to provide ready-made domain models and web pages.

16.1.2. Controllers, views, and other artifacts

The easiest way to enhance an application is to provide ready-made artifacts with your plugin, such as domain classes and controllers. Consider our security plugin: we want to assign roles to users and store that information, so some domain classes might come in handy. Also, logging into an application is pretty standard stuff, so why don’t we provide our own controller and views to handle that? Finally, we could do with some tags that show parts of a web page only if the user has a particular role or is logged in. For example, a Remove Post button for Hubbub should only be visible to administrators.


Holy artifacts, Batman!

You’ll see the term “artifact” used throughout the rest of this chapter, but what does it mean? Some types of classes are given special treatment by Grails, such as domain classes, controllers, and tag libraries. These are collectively known as “artifacts” and reside under the grails-app directory of a project.


Most Grails artifacts that you’ve seen so far can be included in a plugin, and we’ll start by looking at the domain classes our security plugin might provide.

Domain Classes

Because we want to assign users to roles, it makes sense that we need one domain class to represent our users and another for the roles.

Our Role class is going to be simple, consisting of just a name:

class Role {
String name

static constraints = {
name(blank: false, unique: true)
}
}

The given constraints ensure that every role has a unique name. The other required domain class poses a problem: Hubbub already has a User class, but it contains fields that are inappropriate for plain access control, such as signupDate and followers. These are specific to Hubbub, so they shouldn’t be included in the plugin’s domain class.

This situation cries out for domain class inheritance: we can factor out the userId and password fields into a new class and modify the existing User class to extend it. The new class, which we’ll call Account, can happily be incorporated into the plugin, whereas User remains in the application. The new arrangement looks like this:

// In plugin
class Account {
String userId
String password

static hasMany = [ roles: Role ]

static constraints = {
// Same constraints for userId and password as before
...
}
}
// In application
class User extends Account {
...
}

We now have Account.groovy and Role.groovy files under security/grails-app/domain and User.groovy under hubbub/grails-app/domain. This now means that Hubbub won’t compile unless our security plugin is installed.

Domain classes provided by a plugin materially affect the domain model of any project that the plugin is installed into. The user has no way of disabling, modifying, or removing them without editing the plugin files directly, so be careful what domain classes you package with your plugin.

In our case, the plugin depends on the Account and Role domain classes, so it makes sense to provide them as is. An alternative approach is to copy the behavior of the various create-* and generate-* commands and provide scripts to create the domain model. You saw this technique used by the Spring Security plugin with its generate-manager command. We’ll explain how to implement it in section 16.3.5.

The next step is to provide users with a means to log into the application.

Controllers

All we want to do is accept a username and password and check those against the values stored in the database. If the login is successful, we’ll place the relevant User instance in the session; otherwise we’ll redirect back to the login page. That means we need a login page, an action for performing the login, and an action for logging out. Because we support roles, we’ll also include an action that users will be redirected to if they don’t have permission to access a particular page—an “access denied” page. Here’s the outline of our LoginController:

package com.grailsinsaction.security

class LoginController {
def index = {}
def signIn = { ... }
def signOut = { ... }
def unauthorized = { ... }
}

The implementations of these actions are immaterial to the discussion, but you can see them in the chapter’s example source code.

The key point is that we can place this controller under the plugin’s grails-app /controllers directory and its associated views under grails-app/views/login. Once the plugin is installed in an application, the controller and views behave as if they were part of the application. In the case of Hubbub, for example, you could point your browser at http://localhost:8080/hubbub/login/index, and it would show the login page provided by the plugin. You don’t have to do any configuration whatsoever.

Once the plugin is installed, you can override the controller and views in your application. For example, if you don’t like the look of the standard login page, you can place your own index.gsp file under the application’s grails-app/views/login directory. Alternatively, you can change the login behavior completely by providing your own LoginController implementation. The one thing you can’t do is override just the controller and use the plugin’s views with it. Only plugin controllers have access to the plugin’s views.


Under the hood

To make overriding the controller easy, we put it in a package. So long as the overriding controller has the same name as the one provided by the plugin, it all works smoothly.

But beware: all artifacts in both the application and installed plugins are compiled to the same directory, so classes with the same name and package will conflict.


Tag Libraries

Tag libraries work much like controllers and are common in the plugin world. We strongly recommend that any plugin tag libraries you provide use a namespace that’s likely to be unique for the plugin. For example, we use a namespace of hsec for our security plugin (an unoriginal combination of “h” from “Hubbub” and “sec” from “security”). There’s no guarantee that some other plugin won’t use the same namespace, but a careful choice will help minimize the risk.

Why would a plugin provide tags? Custom tags provide an easy way to access a plugin’s functionality from GSP views. This may not be useful for all plugins, but our security plugin, for example, provides tags that display or hide their contents based on whether the user is logged in.

Views

We quickly mentioned views in conjunction with controllers, and they work like any other views. The one complication is when a tag refers to another resource in the plugin. When you execute the run-app command from within the plugin project, the path to the plugin’s resources (such as JavaScript and CSS files) is different compared to when the plugin is installed in an application. In the latter case, the path includes the plugin name to avoid name clashes between plugins.

Making sure that the appropriate path is used requires a little bit of magic. Imagine that our plugin provides a JavaScript file, and we include it from one of the views. You should construct the path to the JavaScript file using the dynamic pluginContextPath property:

<g:resource dir="${pluginContextPath}/js" file="security.js" />

The generated link will look like /myapp/js/security.js when running the plugin directly, or /myapp/plugins/security-0.1/js/security.js if it’s installed in an application.

If your views refer to templates, you need to use a different technique. The render tag accepts a plugin attribute that does what we need:

<g:render template="roleList" plugin="security"/>

This will render the security plugin’s roleList template, regardless of whether the tag is used in an application or a plugin view.

You can see in figure 16.2 where the artifacts are stored in the plugin—they’re in exactly the same places as they would be in an application. Grails does all the work required to make those artifacts available to the applications that the plugin is installed into.

Figure 16.2. The artifacts provided by the security plugin

We have a domain model and sign in and out functionality now, but no mechanism for controlling access to an application’s pages. You’ll see how to add that in section 16.3, but now would be a good time to practice publishing our plugin.

16.2. Publishing your plugin

A plugin in isolation is a sad thing. Without an application to host it, it has no meaning. You saw how to resolve this unhappy state of affairs back in chapter 8, which explained how you could install a plugin into an application either from a zip file or from the central Grails plugin repository. You’ll now see how that zip is created and how the plugin is added to the central repository.

The first step to publishing a plugin is to make sure that it works properly. It’s time to get our testing tools out again.

16.2.1. Testing plugins

A plugin has an almost identical structure to an application, which means that the unit and integration testing you’re already familiar with applies to plugins as well. Both types of testing are useful for checking that the artifacts work correctly, and you write the tests exactly the same as you would for an application, putting them in the plugin’s test/unit and test/integration directories. What neither unit nor integration tests do is make it easy to test the hooks in the plugin descriptor.

That means functional testing is critical to ensuring that a plugin works as expected once it’s installed in an application. It’s the only type of testing in which the plugin is exercised in something close to its final environment. Grails provides two approaches: running the functional tests as if the plugin were an application, or creating separate projects and testing those with the plugin installed.

Testing the Plugin as an Application

With the first approach, you install a functional testing plugin directly into the project, and then create your tests as usual. The question is, what do you test? In the case of the security plugin, we need some pages that we can configure for access control and then test. The plugin doesn’t have any likely candidates, though, so we have to add some test controllers and views, and maybe some domain classes as well. The trick is to make sure that those extra artifacts don’t get packaged with the plugin.

Imagine that we’ve added Post and User domain classes to the plugin. We can exclude them from the “official” plugin package by using the pluginExcludes property of the plugin descriptor:

pluginExcludes = [
"grails-app/domain/Post.groovy",
"grails-app/domain/User.groovy"
]

This simple technique will ensure that users won’t unexpectedly find their application creating Post and User tables when they install our plugin.

Testing the plugin as an application is fine as long as that list of excludes stays short, but thorough testing is likely to see the list balloon in size. It’s also difficult to test different configuration settings, because you can only use one setting value per project. That’s where the second approach we mentioned comes in.

Using Multiple Test Applications

Creating test applications for the plugin allows you to create a thorough suite of tests. For example, you could have each application use different configuration settings for the plugin. The problem is that the whole package and install process is too clunky to be useful. Every time you want to test a change to the plugin, you have to package it up and install it in an application. Fortunately, there’s another way: you can configure an application to load a plugin from its (the plugin’s) project directory. Simply add a line like this to the application’s BuildConfig:

grails.plugin.location.security = "/path/to/plugin/dir"

Any changes you make to the plugin’s source files will be seen by the application the next time you start it. Note that if you use this setting, don’t install the plugin as well.

Figure 16.3 illustrates the typical setup with an application containing two installed plugins and referencing the project directory of our security plugin.

Figure 16.3. A Grails application referencing an in-place plugin (security-plugin) with two other plugins installed normally. The security-plugin directory contains the plugin source code.

You can now set up as many test projects as you need to test all the features of your plugin. We like to keep them in a test/projects directory alongside test/unit, with each project containing this setting in its BuildConfig.groovy file:

grails.plugin.location.security = "../../.."

Anyone can then check out the plugin source and run the functional tests inside each test project.

Once you have some solid tests behind you, you can start thinking about packaging and releasing the plugin.

16.2.2. Releasing the plugin into the wild

In order to make a plugin available for public use, you must first package it into a zip file that can be used by the install-plugin command. You can then publish the plugin to either the central Grails plugin repository or a custom repository, so that users can easily install it. We’ll look at the publishing mechanism shortly, but let’s look at the packaging first.

Packaging the Plugin

Packaging is an essential part of software distribution, whether it involves creating an executable JAR file, a WAR file, or something else. In the case of a Grails plugin, the package is a simple zip file, and Grails comes with a dedicated command for creating it:

grails package-plugin

This command will create a zip file with the name grails-<name>-<version>.zip, where <name> and <version> are the name and version of the plugin.

You can put this file on a shared filesystem, on a web server, or distribute it as you deem fit. Users can then get hold of the zip file and install it:

grails install-plugin grails-security-0.1.zip


Under the hood

When you package a plugin, Grails creates a plugin.xml file that contains the meta-information (such as version, author, and so on) and a list of the artifacts and other resources provided by the plugin. This file is added to the zip and is later used by Grails when installing the plugin and running the application.

Why do we mention this? Because the plugin will break Grails (in sometimes mysterious ways) if the plugin.xml file is either corrupted or inconsistent with the resources packaged in the plugin. We don’t expect that you’ll ever have to worry about the file, but we also realize that sometimes stuff happens.


Don’t worry, the package-plugin command will only include the files that are necessary to use the plugin. All the tests, configuration files, and anything declared in the descriptor’s pluginExcludes field will be excluded. You can find out exactly which files are included and excluded by looking at the pluginIncludes and pluginExcludes script variables in the _GrailsDev.groovy script.

Although this approach to installing plugins is functional, it isn’t as user-friendly as this method:

grails install-plugin security

For this command to work, the security plugin must be published to the central Grails plugin repository.

Publishing to the Central Repository

The central repository is implemented using Subversion (which is a version-control system), as are all plugin repositories. You can’t do this without the appropriate privileges, but you can request permission by following the steps described here: http://www.grails.org/Creating+Plugins. Once you have developer privileges, you’re one step away from sending your plugin into the public spotlight. From the root directory of the project, run this command:

grails release-plugin

This will add your plugin project to the central repository and then check out a copy of the source code to a different directory. For example, if your plugin source is in the .../dev/projects/grails-security directory, the fresh Subversion working copy will be in .../dev/projects/checkout/grails-security.

We recommend that you replace your old project directory with the newly checked out one. Once the plugin source has been added to the repository, the release-plugin command expects to run from a Subversion working copy (see the sidebar for a qualification). Next time you run the command (such as when you have version 0.2 ready), it will update your working copy with any changes that have been committed to the repository by others, commit your own changes, and then release the new version.


Don’t like Subversion?

Although the release-plugin command is geared toward Subversion, you can use other clients like Git and Bazaar as well. You just have to manually commit your changes to the Subversion repository before running the command.


Publishing to Custom Repositories

The procedure we’ve described so far will release your plugin to the central plugin repository, but what if you want to publish it to a custom repository? For example, maybe your plugin is private to your company, so it should only be published to an internal repository. In that case, you need to take these steps:

1.  

Assign the repository URL to an alias.

2.  

Pass a --repository=<alias> argument to the release-plugin command.

The first step involves adding the appropriate lines to your plugin’s BuildConfig.groovy file. For example, add these lines to configure a repository with the alias internalRepository:

grails.plugin.repos.discovery.internalRepository =
"http://.../grails-plugins/trunk"
grails.plugin.repos.distribution.internalRepository =
"https://.../grails-plugins/trunk"

Note that you’ll need to configure URLs for both the discovery and distribution options. Once you have those lines in your BuildConfig.groovy file, run this command to publish your plugin internally:

grails release-plugin --repository=internalRepository

You can then check that everything went OK by attempting to install it in a project:

grails install-plugin --repository=internalRepository security

The --repository argument in this case is optional. If it’s not there, Grails will search all configured repositories, including the central one.

Custom repositories can be used to keep your own plugins private or to manage customized versions of public plugins. They can even be used to control which versions of public plugins are installed by default by your team. If you choose to create a custom repository, you can find out how in the Grails user guide.

You now know how to publish the security plugin, but it isn’t quite in a state for publication yet. We have a domain model and login and logout functionality, but we have no access control. To add that, we have to start using those plugin hooks we mentioned earlier.

16.3. Integrating with Grails

Packaging and running a Grails application involves a fair bit of work under the hood that you don’t often see as an application developer. As a plugin developer, you need to become familiar with the basic processes if you want your plugins to integrate seamlessly with Grails.

In this section, you’ll learn how to do the following:

  • Add your own dynamic methods, like the core Grails plugins do
  • Handle reloading of classes at runtime
  • Configure your own Spring beans
  • Add entries to the application’s web descriptor
  • Implement extra commands

All of these, except the last, are done through the special plugin descriptor hooks that we listed in table 16.1. Without further ado, let’s start by working some dynamic magic.

16.3.1. Enhancing artifacts with dynamic methods

To control access to an application’s functionality, there has to be a gatekeeper. Our security plugin should fulfill that role, but how it does that depends on what you want to secure. It could be access to particular domain classes or service methods, but for simplicity our security plugin will only control access to URLs. The ideal place to do this is in Grails filters because you can prevent access by returning false from a before interceptor.

This raises an important question: how will the developer tell the plugin which URLs require a logged-in user and which require the user to have specific roles? It would be nice to have something like this:

class SecurityFilters {
def filters = {
all(controller: "*", action: "*") {
before = {
authcRequired()
}
}

posts(controller: "post", action: "*") {
before = {
roleRequired("user")
}
}
}
}

The idea here is to only allow authenticated users (ones that have logged in) to access the pages of the application. In addition, only users with the “user” role should be allowed to access any of the pages served by the post controller. The preceding format is concise, wonderfully clutter-free, and informative. Can we implement this, and if so how?

One option would be to provide authcRequired() and roleRequired() methods on an abstract filters class. Any class extending it could then call those methods, like our SecurityFilters class we just saw. There are several problems with this approach, though. First, both Groovy and Java allow only single inheritance of classes, so you immediately force developers to extend your class, limiting their room to maneuver. Second, there’s now an explicit dependency on your plugin, which means that the filters class won’t compile if the plugin is uninstalled. This is an intrusive technique.

Are there no other choices? Of course there are! Remember that filters classes are written in Groovy, so we can make use of that nonintrusive technique you’ve seen already: dynamic method injection. We can inject the authcRequired() and roleRequired() methods into all filters classes without the developer changing a line of code.

Grails encourages this technique by providing a special hook for plugins where they can add any dynamic methods and properties to any classes they choose. All your plugin needs to do is implement the doWithDynamicMethods closure. You need to know how to add such methods, or your closure will be pretty useless.

Now would be a good time to read the section in chapter 2 on dynamic methods if you haven’t done so already. It will give you some background as to what this dynamic business is all about and smooth the way. In the case of the doWithDynamicMethods closure, dynamic methods and properties are added via a technique called metaclass programming.

Metaclass Programming

In Groovy, every class has an associated metaclass that determines the runtime behavior of that class. When a method is called from Groovy, it’s the metaclass that performs the method dispatch. That’s why you add dynamic methods to the metaclass rather than the real class, and it’s also why you can extend the JDK classes. This side of things is normally invisible to you as a programmer, but it comes to the fore when you enter the world of metaclass programming.

That’s enough of the background—let’s try it out! The syntax is straightforward:

You start with the class that you want to add the method to. In this example, we’re using a class literal, but it could equally be a variable referencing a class. You then get hold of the metaclass via the metaClass property and add the method definition using a closure.

Adding a property is similar because you do it via getter and setter methods:

MyClass.metaClass.getMyProp = {-> ... }
MyClass.metaClass.setMyProp = { String newValue -> ... }

Although you can provide a setter, you have to store the new value somewhere, preferably somewhere thread-safe. You can’t add a field directly to the class, so this can be quite tricky. For this reason, dynamic properties are often read-only—only the getter is defined.

Note that the getter closure explicitly has zero arguments. The following will not work as a property:

MyClass.metaClass.getMyProp = { ... }

In this case, you’ll end up with a getMyProp() method that takes a single optional argument.

By now you might be wondering how to access the object instance that your dynamic method is called on. Say you have a class that contains a collection of items, and you want to add a property that returns how many there are. Somehow, your method implementation needs to get hold of that list. As you would expect, this is already taken care of in Groovy: the closure has access to a delegate property that’s a reference to the host object. The method implementation might look like this:

MyClass.metaClass.getTotal = {-> return delegate.items.size() }

In fact, all closures have a delegate property, but what it contains depends on the context.

Those are pretty much the basics. All that remains is to show you a couple of variations on the metaclass syntax that you might find useful:

MyClass.metaClass.static.myMethod = { ... }
MyClass.metaClass.myMethod << { ... }

The first of these allows you to add static methods to the class. In this case, the delegate in the closure is a reference to the class itself. The second form uses the left-shift operator (<<) rather than =. It does the same thing, but if the method already exists, Grails throws an exception. If you’re planning to override an existing method, use =; otherwise, prefer << so that the user is aware of naming conflicts when the application starts.

As you can see, the basics of metaclass programming are quite simple. That said, the method implementations can be tricky, particularly when it comes to name resolution. On the whole, anything that you expect to work will work, but if you do a lot of metaclass programming, you’ll almost certainly come across some sticky issues. If that’s the case, it’s probably worth getting a book dedicated to Groovy that covers the ins and outs of Groovy’s name resolution, particularly with regard to closures.

When you first start using metaclass programming, the temptation is to use it everywhere. It’s novel, exciting, and as the saying goes, “when you have a hammer, everything looks like a nail.” Some restraint is in order. As we mentioned in chapter 2, the dynamic features of Groovy can be awkward to debug, and they also make life difficult for IDEs. Remember, there are alternatives: static utility methods, Grails services, inheritance, and so on. But if you think the benefits of cleaner and easier to understand (and write) code outweigh the drawbacks, then go dynamic.


Warning

Be careful about modifying the standard JDK classes and other common classes, particularly if you plan to override existing methods or properties. The changes will be visible to all Groovy code in all threads, so a subtle change in behavior can have undesirable consequences in other parts of the code, and those bugs can be difficult to track down.


You now know how to implement dynamic methods, but what classes should you be adding them to? For our security plugin, we want to add them to all the filters in an application, but how do we do that? We don’t know in advance what filters classes are in the application.

Finding out about Application Artifacts

Think about what happens when a plugin is installed in a Grails application. When you write it, you only know about the classes provided by the plugin itself, but as soon as you install it into an application, the plugin suddenly finds itself in an environment containing more classes than it’s used to—classes that are provided by other installed plugins and classes that are part of the application. There must be some way to find out what’s out there without resorting to querying the class loader, right? Thankfully there is.

The code you write in any of the hooks listed in table 16.1 has access to a property called application. This is the Grails application instance, and we can use it to find out what artifacts are available. Remember the GORM dynamic finders? The application instance has a similar set of dynamic methods and properties, but in this case they’re based on the types of artifacts available rather than the fields in a domain class.

Say you wanted to get all the controllers in the application. It’s easy:

application.controllerClasses

You could also retrieve all the services via application.serviceClasses. In fact, you can do something similar for all types of artifacts—table 16.2 lists the available methods and properties.

Table 16.2. Querying the application about artifacts

Method template

Description

<artifact>Classes

Returns all the artifact descriptors in the application of type <artifact>. Note that the artifact type should start with a lowercase letter because it’s a property.

get<Artifact>Class(String
artifactName)

Returns the artifact descriptor of type <Artifact> for the artifact with a name of artifactName. For example, getControllerClass("LoginController") would return the artifact descriptor for LoginController. Note that artifactName must be a full class name, including the package if there is one.

is<Artifact>Class(Class
artifactClass)

Returns true if the class is of type <Artifact>, otherwise false. For example, isControllerClass(LoginController) would return true.

You’ll see that we talk about artifact descriptors in table 16.2. Each artifact in the application has an associated descriptor that provides extra information about it, the key properties of which you can find in table 16.3.

Table 16.3. Artifact descriptor properties

Property

Type

Description

Example

clazz

Class

The class of the artifact

org.example.
LoginController

metaClass

MetaClass

A shortcut to the artifact’s metaclass; same as clazz.metaClass

N/A

name

String

The name of the artifact, minus any suffix or package

Login

shortName

String

The name of the artifact minus any package

LoginController

propertyName

String

The short name of the artifact in property form

loginController


Under the hood

The dynamic artifact methods are implemented by the DefaultGrailsApplication class using invokeMethod(). They map to physical methods like getArtefacts(), which means that you can access the same information from Java if you wish.

The artifact descriptors are instances of the GrailsClass interface. It’s well worth becoming familiar with its methods for more advanced plugin work.


Back to the security plugin. We said that we wanted to add a couple of dynamic methods to filters, but filters are a special case. So first we’ll show you how to add a hasRole() method to all the controllers in an application. In fact, we’ll spice it up a little by only adding the method if the controller defines a static property called secure with a value of true. The result can be seen in listing 16.2.

Listing 16.2. Injecting a method into controllers

GrailsClassUtils is a useful class for plugin authors, and we use it here to read the value of the static secure property . Once we have that value, we check it and only add the hasRole() method to that particular controller if the value is true. This dynamic method will return true only if the user has the named role.

That was easy enough, so what about adding methods to filters? Unlike most other artifacts, the filter instance isn’t of the same type as the *Filters class that you add the definitions to. For example, a post controller is an instance of PostController, but a security filter isn’t an instance of SecurityFilters. Instead, all filters are instances of a FilterConfig class, so adding dynamic methods to them is this simple:

import org.codehaus.groovy.grails.plugins.web.filters.FilterConfig
...
FilterConfig.metaClass.authcRequired = {-> session.user != null }

The preceding line should go inside the doWithDynamicMethods closure—we’ve left out the rest of the class to avoid unnecessary clutter.

The security plugin can now block access to an application’s pages in a user-friendly fashion (see the chapter 16 source code for the implementation). And with so few lines of code!

We’re almost done here, but there is one more thing that we need to take care of. What happens when the developer changes a controller class while the application is running?

16.3.2. Dealing with class reloading

Grails’ ability to reload changes to application files on the fly is a major benefit for users. Unfortunately for plugin writers, users expect plugins to play well with this feature and take advantage of it themselves. As one example, any dynamic methods on a controller will disappear when that controller is reloaded—it’s up to the plugin to restore the methods that it originally added. This is where the onChange and onConfigChange closures come in.

Grails maintains lists of what it calls watched resources, which are filepath patterns similar to the ones you may have used with the Ant build tool. Whenever a file that matches one of the patterns is modified, Grails first reloads it (if it contains a Groovy class or script) and then notifies interested plugins by calling their onChange closures.


Core plugins and their names

Much of Grails’ functionality is provided as plugins that are packaged in the framework’s JAR files. We refer to these as core plugins. There is also a plugin named core, but if we ever refer to it we’ll make that clear. Examples of core plugins are controllers, domainClass, i18n, and services.


Obviously the first step for your plugin is to register an interest in such changes. There are two approaches you can take: “observe” an existing plugin or specify a list of watched resources. Let’s say you want Grails to notify you when any controllers are modified. Because the core controllers plugin already watches for changes to controllers, observing it will mean that your plugin will also be notified of those changes. In fact, your plugin will receive exactly the same notifications as the observed plugin, so be aware of what those might be—the controllers plugin also watches tag libraries, for example.

Observing a plugin is as simple as adding an observe property to the plugin descriptor, like so:

def observe = ["controllers"]

Each entry in the list is the name of a plugin you want to observe. If any of those plugins isn’t installed in the current application, they’re quietly ignored. Table 16.4 shows some of the more useful plugins and the resources that they watch.

Table 16.4. The files watched by some of the core plugins

Plugin name

Resources watched

controllers

Controllers and tag libraries

services

Services

filters

Filter classes

urlMappings

URL mappings

hibernate

Hibernate configuration files

i18n

I18n bundles (messages.properties, for example)

The other approach you can use is to specify a watchedResources property that contains one or more file patterns that match the files you’re interested in. For example, to watch controllers, we could use this,

def watchedResources = "file:./grails-app/**/*Controller.groovy"

or this,

def watchedResources = ["file:./grails-app/**/*Controller.groovy"]

Before we move on to dealing with the change notifications themselves, let’s take a quick look at the example file pattern.

The scheme is optional and determines how to access the file. The second part is the filepath pattern, which follows Ant’s conventions. A double-asterisk (**) wildcard matches any number of nested directories (or none at all), whereas a single asterisk (*) can be used to match a single directory level or any part of a file or directory name. For example, the preceding pattern would match ./grails-app/MyController.groovy and ./grails-app/org/example/MyOtherController.groovy, amongst others.

If you do use the watchedResources property, we recommend that you always use the file: scheme and start the filepaths with ./. For more information on these filepaths, read the section on resources in the Spring reference manual.

Now that you know how to register for change notifications, how do you deal with them? Your onChange closure will be passed an event object with the following properties:

  • sourceThe file or artifact that changed. If a class changed, the source will be the class instance (java.lang.Class); otherwise, it will be a Spring resource (org.springframework.core.io.Resource).
  • applicationThe Grails application instance, which is useful for getting information about artifacts. This is redundant because the onChange closure has access to an application dynamic property.
  • ctxThe Spring application context, from which you can access any beans you might need.
  • managerThe plugin manager.
  • pluginThe plugin descriptor instance.

Of these, source is the most useful. Armed with this information, you can do whatever is necessary to ensure that the plugin continues working as it should.

In listing 16.3, we return to the security plugin and make sure that we add the has-Role() dynamic method back to any controller that has changed, because the dynamic properties and methods are lost when a class is reloaded.

Listing 16.3. Responding to controller modifications

Here we’re observing the controllers plugin, so we have to ignore changes to tag libraries. We do this by using the Grails application object to determine what type of artifact has been modified . The isControllerClass() method is dynamic, so there are similar methods for all registered artifact types. For example, you could also use isDomainClass().

This example is a simple one, but you’re in good shape to deal with class and file reloading in the most common cases. One thing to be aware of is that the onChange closure is called when a new artifact is created, not just when artifacts are modified. This typically has no impact on your code, but you should be aware of it in case.

We’ve covered how to deal with changes to artifacts, but what about configuration changes? Fortunately, this is pretty easy. All you need to do is add an onConfigChange closure that takes an event as an argument. That’s it—you don’t even have to set up any watched resources or observe a particular plugin. The main difference is that the event’s source property is the new configuration object, which you can use to access whatever settings you need in the normal way.

So when should you add reloading support to your plugin? You definitely should if you add dynamic methods or properties to artifacts; otherwise, those methods will disappear in a puff of smoke after a reload. Another common case is when your plugin reads values from an artifact, such as from a property. The developer may change that value, so your plugin should ensure that the new value takes effect. Other than that, there are no hard and fast rules. It comes down to whether changes to artifacts affect the behavior of the plugin.

We already have a functional security plugin that can control access to an application’s pages, yet we’ve only used a fraction of the features that are available to a plugin. You don’t need to implement everything just because you can, and in practice most plugins don’t need or use all the integration points. That said, we need to go through the remaining features, so let’s extend our plugin with some extra functionality.

16.3.3. Leveraging Spring

Remember how we configured Spring beans via the resources.* files back in chapte 14? You can do something similar with plugins too. Consider how the plugin stores passwords at the moment: it’s hard-coded to hash the plain-text passwords using the SHA-1 algorithm. It would be nice if instead we could allow users to pick a hashing algorithm, but to do that we need to tackle both storing the password and comparing passwords during authentication.

In a typical Java application, an appropriate solution would be to create an interface that deals with storing and comparing passwords. Different implementations of that interface could use different hash algorithms. Here’s an example of what it might look like:

public interface PasswordHandler {
String encode(String plain)
boolean passwordsMatch(String plain, String encoded)
}

The encode() method converts a plain-text password to its hashed form and passwordsMatch() compares a plain password to an encoded one.

All we need now is a way to set up a default password handler with a default hashing algorithm. That’s where the doWithSpring closure comes in. You can define beans inside it using the Spring DSL, as demonstrated in listing 16.4.

Listing 16.4. Simple example of the Spring DSL

In this example, we define the password-handler bean (passwordHandler) and configure it to use an SHA-1 hashing algorithm to encode passwords. So how does the user override the hashing algorithm with this example?


Under the hood

You can use the Spring DSL because the delegate for the doWithSpring closure is an instance of grails.spring.BeanBuilder. All the other hooks (like doWithDynamicMethods) are executed with a delegate of:

org.codehaus.groovy.grails.plugins.DefaultGrailsPlugin.

When Grails starts up, it processes all doWithSpring closures provided by the installed plugins and populates the application context with those bean definitions. Only once all the plugins have been processed does Grails then load the bean definitions from resources.xml and resources.groovy. To use a different hashing algorithm, all the user needs to do is define a bean named hashMachine in one of those files. For example, it could be defined in resources.groovy:

beans = {
hashMachine(security.Md5Hasher)
}

As long as the bean that the user defines has the same name as the one in the doWithSpring closure, the former will override the latter. Easy!

We’re almost done here, but we still need to explain what the doWithApplicationContext closure is for. This is called by Grails after all the plugins have had a chance to add their bean definitions and the application context has been configured. The sole argument to the closure is the application context itself, fully initialized and ready for use. The closure isn’t often implemented by plugins, but if you ever need to do some work with the application context or its beans (rather than the bean definitions), this is the hook you want.

The last of the plugin hooks takes us away from Spring and into the world of servlets and servlet filters, which are important aspects of a web application.

16.3.4. Playing with servlets and filters

Grails is heavily geared towards web application development, and although it’s easy to write a Grails application without thinking about the traditional web descriptor, it should definitely not be forgotten. Remember, this is the only way you can configure servlets and servlet filters.

The security plugin we’ve been developing in this chapter has no need to configure servlets or servlet filters, so we’ll borrow an existing Grails plugin to demonstrate. The JSecurity plugin provides access control for Grails applications, and it just so happens that it needs to set up a servlet filter. We could force the user to manually configure this filter, but the plugin would quickly lose friends if it tried that approach. It has to configure the filter itself.

Reading the XML, modifying it, and then writing it out again would be quite tedious, so you’ll be glad to hear that you don’t have to. Instead, you implement the doWithWebDescriptor closure and modify an in-memory representation of the web descriptor. How does it work? Grails starts by parsing a template web descriptor using XmlSlurper, the result of which is passed to the plugin’s doWithWebDescriptor closure as an argument. With that, we can modify the web descriptor.

We know that the argument passed to the doWithWebDescriptor closure is the slurper result from parsing the template web descriptor. We also know how to use that object to extract information that we might need. But how do we modify the XML? We have to do that somehow if we’re going to configure a servlet filter. The XML slurper provides the one facility for doing this, and listing 16.5 shows you exactly how to configure the JSecurity filter.

Listing 16.5. Configuring a servlet filter at runtime

The order of filter definitions doesn’t matter, so the JSecurity one is added immediately after the last context-param element and . See how the element name is in quotes ? This is because method and property names may not contain hyphens, so we take advantage of Groovy’s freedom to use strings instead. The contextParam variable represents a list of elements, so we use the array access syntax to get hold of the last element. Why don’t we use an index of -1? For some reason, this doesn’t work with XmlSlurper, so we have to do it the old-fashioned way instead.

The key to modifying the XML is the next bit. Once we have an element that we want to insert content after, we can use the plus (+) operator with a closure . The content of the closure is pretty self-explanatory if you’re familiar with the web descriptor syntax for filter definitions. Each method name corresponds to the name of an element, and a new closure marks the start of nested elements. In practice, it’s equivalent to this:

<filter>
<filter-name>securityContextFilter</filter-name>
<filter-class>org.jsecurity.spring.SpringJSecurityFilter</filter-class>
<init-param>
<param-name>securityManagerBeanName</param-name>
<param-value>jsecSecurityManager</param-value>
</init-param>
</filter>

Although filter is in quotes in the listing, the quotes aren’t strictly necessary. They’re mainly there so that all the elements look consistent.

We said that the order of the filter definitions doesn’t matter, but it’s a different kettle of fish when it comes to the filter mappings. The order in which they’re defined is the order in which they’re executed. For this reason, you need to be a bit more careful about where your mappings are inserted. In we look for the filter mapping for the charEncodingFilter, which is pretty much guaranteed to be there. Almost all filters should come after this one, and that’s what the code in the listing does with the JSecurity filter mapping. The only time that this approach won’t work is when the user has customized the template web descriptor and removed the charEncodingFilter mapping. In such cases, it’s best to fall back to inserting your filter mapping at the front (index 0).


Where are the other filters?

Grails provides a few servlet filters itself. There is one for URL mappings and another that adds extra information to the request, among others. Try as you might, though, you won’t find the definitions in the web descriptor passed to your closure. Anything added by a plugin isn’t visible to plugins loaded later.

This somewhat limits your ability to control where filters go in the filter chain, but all isn’t lost. With judicious use of the loadAfter property, you can still make sure that your filter comes after some of the core ones. Unfortunately, there is currently no way to insert an element before another one.


Once you’re comfortable with the syntax for the XML slurper, you’ve effectively mastered the doWithWebDescriptor closure. There isn’t any more to it than that. You’ll be able to add context parameters, set session timeouts, configure servlets—anything supported by the web descriptor.

We’ve now covered all the plugin descriptor integration points. There aren’t many, but they’re powerful, and hopefully you can envision some of the many possibilities they offer. The last integration point we’ll look at is the scripts directory.

16.3.5. Augmenting the available Grails commands

So far we’ve looked at the ways in which a plugin can affect the runtime behavior of a Grails application, but what about at development time? You saw in the previous chapter that you can extend the Grails command set by writing scripts for your application, and you can do the same for your plugin. Grails packages those scripts with the plugin so that when it’s installed, the corresponding commands become available to the application.

What kind of commands do plugins implement? Almost anything under the sun. There are commands for running tests, performing database migrations, creating application files from templates, performing special compilations, and more. Listing 16.6, for example, shows a script that creates the controllers and views for a user-management UI that works with our security plugin.

Listing 16.6. A script that creates a user-management UI for the security plugin

There’s no rocket science here. The script copies controller and view templates from the plugin to the application. One crucial aspect is how the location of the templates is derived . Grails adds a variable named <pluginName>PluginDir to the script binding for every plugin that’s installed in an application. It contains the absolute location of the unpacked plugin, so we could use securityPluginDir to locate the templates. You could even get the location of a different plugin if you wanted, although this is less common.

In addition to your own scripts, every plugin is created with three internal ones all ready and waiting to go: _Install.groovy, _Uninstall.groovy, and _Upgrade.groovy. The first is automatically called when the plugin is installed into an application; the second is called when the plugin is uninstalled; and the last is invoked when an application is upgraded from one version of Grails to another via the grails upgrade command. This last one is pretty redundant because it has nothing to do with upgrading the plugin. Scripts are an integral part of plugin development and can make life considerably easier for the users of a plugin. Because one of those users may be you, it’s worth investing a bit of time in thinking up some script ideas and implementing them.

We’ve now introduced all the main features of plugins and shown how you can utilize them to extend and customize the Grails platform. It’s been a tough ride, but you’ve made it. It’s time to catch your breath while we do a quick recap.

16.4. Summary and best practices

Plugins are a complex topic because they can feasibly interact with almost every aspect of Grails. Yet they’re such a fundamental part of the Grails platform that you need to understand them if you want to harness its full potential. Even the most trivial of applications will almost certainly use one or more plugins.

You’ve seen numerous plugins throughout the book, and these form only a fraction of the publicly available ones. The sheer variety demonstrates how flexible and powerful the plugin system is. The public plugins can also serve as a source of inspiration and ideas.

Whether you use plugins to modularize your application or package up self-contained features, they can dramatically simplify development for the plugins’ users and promote reuse of code. This chapter has shown you how easy it is to get started in plugin development, but it has also given you the tools to take that development further.

You can also use existing plugins as learning material. For example, the JSecurity plugin has a significant plugin descriptor with implementations for many of the hooks. It also has a few scripts that you can look at. The GWT plugin has a good selection of scripts that use more advanced techniques than JSecurity’s.

To finish off, here are some guidelines for designing and developing your own plugins:

.  

Keep it simple. Use only the minimum number of features and hooks that you need to implement your plugins. For example, if it doesn’t make sense to add dynamic properties or methods, then don’t.

It’s also important to realize that plugins don’t have to be hulking, complex beasts. They can be very simple indeed, and the cost of building such plugins is quite low. Remember, a plugin is always an option for code that’s self-contained or shared between projects, no matter how trivial.

.  

Implement onChange when necessary. If your plugin adds dynamic methods or properties, make sure that it also implements the onChange hook, so that those methods and properties are retained after a reload. Users get quite attached to the reloading feature, so plugins that break it become unpopular.

.  

Use local plugin repositories for teams. Local plugin repositories serve several purposes. First, they allow you to control which versions of plugins are installed by your team by default. Second, they allow you to customize public plugins for your own purposes. Last, they can be useful for modularizing applications.

.  

Modularize large or complex applications. The Separation of Concerns pattern is powerful, and plugins allow you to apply it to your Grails applications. You can either use the in-place plugin mechanism (via the grails.plugin.location.* configuration setting) or a local plugin repository to manage the modularization.

.  

Write functional tests for your plugins. For plugins to be reliable, you should write functional tests. The in-place plugin mechanism is particularly useful for this, allowing you to create multiple test projects that load the plugin from source.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset