Mastering Grails

Creating a custom plug-in

Sharing functionality among Grails applications


Content series:

This content is part # of # in the series: Mastering Grails

Stay tuned for additional content in this series.

This content is part of the series:Mastering Grails

Stay tuned for additional content in this series.

Many articles in the Mastering Grails series have focused on intelligent code reuse. If you find yourself copying and pasting the same snippet of GroovyServer Pages (GSP) code in multiple places, you can create a partial template or a custom TagLib. If you find a method or two that are common among multiple controllers or domain classes, you can create an abstract parent class to extend or graft the methods on directly, using the ExpandoMetaClass. If you have some shared application functionality, you can refactor it out into a service or a custom codec.

But all of that is at the micro level. What if you have some shared functionality at the macro level: something that requires the combined, coordinated effort of controllers and domain classes, services and codecs, and all of the other pieces of a typical Grails application? What I've just described is a plug-in.

In "Mastering Grails: Understanding plug-ins," you explored an existing plug-in: Searchable. More than 250 Grails plug-ins are available at the Grails Plugins portal (see Related topics). That number keeps growing because extending your existing Grails application through plug-ins is an idea that is baked into the core of Grails. In this article, you'll learn how to build your own custom plug-in. The source code for the example plug-in is available for download.

Introducing the ShortenUrl plug-in

In this era of and cell-phone text messaging, the many long URLs that don't fit within the 140-character limit placed on messages can be a hassle. Thankfully, a number of URL-shortening Web services are out there practically begging to be integrated with Grails as a custom plug-in.

To create a custom plug-in, you must change your Grails routine slightly. Instead of typing grails create-app as you would normally, you must type grails create-plugin, as shown in Listing 1. (Be sure to type this command in a new, empty directory, not in an existing Grails directory. You'll learn how to integrate this new plug-in with an existing Grails application at the end of this article.)

Listing 1. Creating a custom plug-in
$ grails create-plugin shortenurl

The resulting directory structure is identical to a typical Grails application. However, in the root directory you'll see one new file that identifies this project as a plug-in: ShortenurlGrailsPlugin.groovy. Listing 2 shows a snippet:

Listing 2. The plug-in configuration file
class ShortenurlGrailsPlugin {
    // the plugin version
    def version = "0.1"
    // the version or versions of Grails the plugin is designed for
    def grailsVersion = "1.1.1 > *"
    // the other plugins this plugin depends on
    def dependsOn = [:]
    // resources that are excluded from plugin packaging
    def pluginExcludes = [

    // TODO Fill in these fields
    def author = "Your name"
    def authorEmail = ""
    def title = "Plugin summary/headline"
    def description = '''\\
Brief description of the plugin.


This file contains the metadata for your plug-in: the version number, the version of Grails your plug-in depends on, any other plug-ins that your plug-in depends on, and so forth. (Full details on configuration files are in the online documentation; see Related topics.)

If you want to make this a public plug-in that other developers can download from the Plugins portal, you should fill in the author details and give it a compelling description. The file's contents are read and automatically displayed on the Grails Web site every time you check your plug-in into the public Subversion repository. (For more information on publishing your plug-in, see Related topics.) In this article, you'll keep this a private plug-in, so filling in the author details is less important than it would be otherwise.

Even though the ShortenUrl plug-in doesn't require any changes to ShortenurlGrailsPlugin.groovy, that doesn't mean that you are finished. Now that you have the directory structure scaffolded out, the next step is to write the implementation.

Create the TinyUrl class is a popular URL-shortening service. Once one person submits a long URL for shortening, it is saved behind the scenes as the official shortened URL for all subsequent requests. For example, visit the site, type in, and click the Make TinyURL! button. The resulting shortened URL — — is half the length of the original, as you can see in Figure 1:

Figure 1. shortening a URL shortening a URL shortening a URL

Now that you know how works, it's time to focus on integrating the site's underlying service with the ShortenUrl plug-in. Type the following into your Web browser:

This spartan Web service interface returns only the shortened URL — not the HTML — for the specified page.

The next step is to encapsulate your newfound knowledge in a Groovy class. This class is a Plain Old Groovy Object (POGO) in the truest sense of the word — it's not a service, a controller, or any other special-purpose Grails component. Therefore, the best place to put it is in src/groovy. Create an org/grails/shortenurl directory under src/groovy. Then create TinyUrl.groovy and add the code in Listing 3:

Listing 3. The TinyUrl utility class
package org.grails.shortenurl

class TinyUrl{
  static String shorten(String longUrl){
    def addr = "${longUrl}"
    return addr.toURL().text

Testing the TinyUrl class

Before you put any code into production, it really should have a corresponding test, don't you think? Because you are making a live Web call, this should be an integration test. Create the same org/grails/shortenurl directory structure you created earlier under test/integration. Create TinyUrlTests.groovy and add the code in Listing 4. (Yes, I appreciate the irony that in this simple case the allegedly tiny URL is longer than the original URL it is encoding.)

Listing 4. Testing the TinyUrl class
package org.grails.shortenurl

class TinyUrlTests extends GroovyTestCase{
  def transactional = false

  void testShorten(){    
    def shortUrl = TinyUrl.shorten("")
    assertEquals "", shortUrl

Note the def transactional = false line in the integration test. If you leave it out, you will be greeted with the nasty error message shown in Listing 5:

Listing 5. What happens if your test doesn't set def transactional = false
Error running integration tests: java.lang.RuntimeException: 
There is no test TransactionManager defined 
and integration test ${} does not set transactional = false

Grails tries to wrap each test in a database transaction. In a normal Grails application, this is not an issue. But because you are in a plug-in instead of a full Grails application, you cannot assume that a database will be in place. You could install the Hibernate plug-in, or do as the error message tells you and set def transactional = false in your integration test.

Type grails test-app and verify that your test passes.

I'll implement one more URL-shortening service here, just to give the user of this plug-in a choice of services.

Creating the IsGd class

The Is.Gd (pronounced is good) service boasts a shorter domain name and shorter encoded URLs than Visit to experiment with the Web interface.

In another nod to irony, I'll take this opportunity to show you a longer implementation of the two-line method I used in TinyUrl.groovy (see Listing 3). This implementation gives you a bit more information to react to if the call to the service fails. Create IsGd.groovy, shown in Listing 6, in src/groovy/org/grails/shortenurl:

Listing 6. The IsGd utility class
package org.grails.shortenurl

class IsGd{
  static String shorten(String longUrl){
    def addr = "${longUrl}"
    def url = addr.toURL()
    def urlConnection = url.openConnection()
    if(urlConnection.responseCode == 200){
      return urlConnection.content.text
      return "An error occurred: ${addr}\n" + 
      "${urlConnection.responseCode} : ${urlConnection.responseMessage}"

As you can see, you explicitly verify that the response code is 200 — the HTTP response code for OK. (See Related topics for more on HTTP response codes.) For the sake of simplicity, I just return the error message if the call fails. But with this extended structure in place, you could make the method more robust by retrying the call a few more times or failing over to another URL-shortening service.

Create the corresponding IsGdTests.groovy file, shown in Listing 7, in the test/integration/org/grails/shortenurl directory. Type grails test-app and confirm that the IsGd class works as expected.

Listing 7. Testing the IsGd class
package org.grails.shortenurl

class IsGdTests extends GroovyTestCase{
  def transactional = false
  void testShorten(){
    def shortUrl = IsGd.shorten("")
    assertEquals "", shortUrl        
  void testBadUrl(){
    def shortUrl = IsGd.shorten("IAmNotAValidUrl")
    println shortUrl
    assertTrue shortUrl.startsWith("An error occurred:")

To see the details of exactly how the IsGd service fails when you pass in IAmNotAValidUrl, I recommend getting out to a command line and using curl, as shown in Listing 8. (The cURL utility is native on UNIX®/Linux®/Mac OS X, and downloadable for Windows®; see Related topics.) Testing the bad URL in the browser allows you to see the error message, but not the error code. Using cURL, you can clearly see that the Web service returns a 500 code instead of the expected 200.

Listing 8. Using curl to see the details of the failed Web service class
$ curl --verbose ""
* About to connect() to port 80 (#0)
*   Trying connected
* Connected to ( port 80 (#0)
> GET /api.php?longurl=IAmNotAValidUrl HTTP/1.1
> User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3
                 OpenSSL/0.9.7l zlib/1.2.3
> Host:
> Accept: */*
< HTTP/1.1 500 Internal Server Error
< X-Powered-By: PHP/5.2.6
< Content-type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 19 Aug 2009 17:33:04 GMT
< Server: lighttpd/1.4.22
* Connection #0 to host left intact
* Closing connection #0
Error: The URL entered was not valid.

Now that the plug-in's core functionality is implemented and tested, you should create a convenience service that exposes the two utility classes in a Grails-friendly way.

Creating the ShortenUrl service

To create a service, type grails create-service ShortenUrl. Add the code in Listing 9 to grails-app/services/ShortenUrlService.groovy:

Listing 9. The ShortenUrl service
import org.grails.shortenurl.*

class ShortenUrlService {
    boolean transactional = false

    def tinyurl(String longUrl) {
      return TinyUrl.shorten(longUrl)

    def isgd(String longUrl) {
      def shortUrl = IsGd.shorten(longUrl)
      return shortUrl

As with the previous integration tests, be sure to set the transactional flag to false. No database is involved in these calls, so there is no need to wrap them in a transaction.

Note that the isgd() method logs any attempt to shorten an invalid URL. All Grails artifacts are injected with a log object at run time. You can call methods on the log object that correspond to the desired log level: debug, info, error, and so on. (See Related topics for more information on logging.) As you'll see in just a moment, dealing with this injected log object when writing unit tests requires an extra step.

When Grails created the service for you, it added the corresponding test to the test/unit directory. Normally I'd have you move ShortenUrlServiceTests.groovy to the test/integration directory, because it is semantically an integration test instead of a unit test — testing the service relies on external resources. Instead, leave it in the test/unit directory so that I can show you a couple of unit-testing tricks. Add the code in Listing 10 to ShortenUrlServiceTests.groovy:

Listing 10. Testing the ShortenUrl service
import grails.test.*

class ShortenUrlServiceTests extends GrailsUnitTestCase {
    def transactional = false
    def shortenUrlService
    protected void setUp() {
        shortenUrlService = new ShortenUrlService()

    protected void tearDown() {

    void testTinyUrl() {
      def shortUrl = shortenUrlService.tinyurl("")
      assertEquals "", shortUrl

    void testIsGd() {
      def shortUrl = shortenUrlService.isgd("")
      assertEquals "", shortUrl        

    void testIsGdWithBadUrl() {
      def shortUrl = shortenUrlService.isgd("IAmNotAValidUrl")
      assertTrue shortUrl.startsWith("An error occurred:")

Notice that after you set the transactional flag to false, you declare the shortenUrlService variable. You then initialize the service in the setUp() method. The setUp() and tearDown() methods are called for each test.

If this were an integration test, it would run without errors. But because it's a unit test, The testIsGdWithBadUrl() method fails with: No such property: log for class: ShortenUrlService. Open test/reports/html/index.html in your Web browser to see the error message shown in Figure 2:

Figure 2. Unit-test failure resulting from the injected log object
Unit-test failure resulting from the injected log object
Unit-test failure resulting from the injected log object

As it turns out, the log object doesn't get injected into the service for unit testing. (Remember: Unit tests are meant to run in complete isolation.) Thankfully, you can get around this by adding a single line — mockLogging(ShortenUrlService) — to the setUp() method, as shown in Listing 11:

Listing 11. Mocking the injected log object
protected void setUp() {
    shortenUrlService = new ShortenUrlService()

The mockLogging() method injects a mock log object into the service. This mock logger sends its output to System.out instead of to any of the defined log4j appenders. To see the output (shown in Figure 3), type grails test-app once again and click on the System.out link at the bottom of the HTML report page for ShortenUrlServiceTests.

Figure 3. Mock-logger output
Mock-logger output
Mock-logger output

You could bundle plenty of other Grails artifacts with this plug-in — a custom TagLib to shorten URLs in GSPs, a custom codec — but you've done enough already to get the idea of what a plug-in can offer. Next, you'll package this plug-in as it stands now and integrate it with another Grails project.

Packaging and deploying the plug-in

To prepare a full Grails application for deployment, you normally type grails war. For plug-ins, you type grails package-plugin instead. You should end up with a file in your project's root directory.

Recall from "Mastering Grails: Understanding Plug-ins" that all Grails plug-ins are distributed as ZIP files. If you look in the .grails/1.1.1/plugins directory in your home directory, you should see similarly named plug-ins, such as and

If ShortenUrl were a public plug-in, you could type grails release-plugin to push your changes to the Grails Plugins portal. Anyone could then type grails install-plugin shortenurl to integrate it with their project. But you can install private plug-ins locally just as easily: all you need to do is supply the full path to the ZIP file on your local file system.

To test this out, create a new, empty directory outside of the shortenurl directory. Type grails create-app foo to create a simple application. Change to the foo directory and type grails install-plugin /local/path/to/, of course substituting the real path to the plug-in. You should see something similar to the output shown in Listing 12:

Listing 12. Installing a local plug-in
$ grails install-plugin /code/
Welcome to Grails 1.1.1 -
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grails

Base Directory: /code/foo
Running script /opt/grails/scripts/InstallPlugin.groovy
Environment set to development
     [copy] Copying 1 file to /Users/sdavis/.grails/1.1.1/plugins
     Installing plug-in shortenurl-0.1
     [mkdir] Created dir: 
     [unzip] Expanding: 
     /Users/sdavis/.grails/1.1.1/plugins/ into 
Executing shortenurl-0.1 plugin post-install script ...
Plugin shortenurl-0.1 installed

As you can see, the plug-in life cycle for local, private plug-ins is identical to that of public plug-ins.

Open the foo/ file in a text editor. Verify that plugins.shortenurl is listed, as shown in Listing 13:

Listing 13. Verifying that the plug-in appears in
#Wed Aug 19 14:38:24 MDT 2009

Now that the plug-in is installed, you should verify that it works as expected. Type grails create-controller test. Open grails-app/controllers/TestController.groovy and add the code in Listing 14:

Listing 14. Injecting the service into a controller
class TestController {
    def shortenUrlService

    def index = { 
      render "This is a test for the ShortenUrl plug-in 
" + "Type test/tinyurl?q= to try it out." } def tinyurl = { render shortenUrlService.tinyurl(params.q) } }

Notice that def shortenUrlService injects the service into the controller. Type grails run-app to start the application. Visit http://localhost:9090/foo/test/tinyurl?q= in your Web browser. You should see results as shown in Figure 4:

Figure 4. Verifying successful plug-in installation
Verifying successful plug-in installation
Verifying successful plug-in installation

And if you go to, sure enough you'll find yourself at


As you can see, creating a Grails plug-in is not much different from creating a typical Grails application. Instead of typing grails create-app, you type grails create-plugin. Instead of typing grails war, you type grails package-plugin. And with the exception of adding the salient details to the GrailsPlugin.groovy descriptor file, all of the steps in between (creating services, writing tests, and so on) are identical.

In this article, I briefly touched on the mocking capabilities of Grails unit tests with the mockLogging() method. Next time, I'll demonstrate many other incredibly valuable mock methods: mockDomain(), mockForConstraintsTests(), and more. Until then, have fun mastering Grails.

Downloadable resources

Related topics

  • Mastering Grails: Read more in this series to gain a further understanding of Grails and all you can do with it.
  • Grails: Visit the Grails Web site.
  • Grails Plugins: Visit the Grails plug-in portal for information about the latest plug-ins available for the Grails framework.
  • The Plug-in Developers Guide: Here's the online documentation for Grails plug-in developers.
  • Creating Plugins: Get more information on creating, distributing, and installing Grails plug-ins.
  • TinyURL: Read Wikipedia's article on TinyURL.
  • HTTP status codes: Wikipedia has the full list of HTTP status codes.
  • Groovy Recipes (Scott Davis, Pragmatic Programmers, 2008): Learn more about Groovy and Grails in Scott Davis' latest book.
  • Practically Groovy: This developerWorks series is dedicated to exploring the practical uses of Groovy and teaching you when and how to apply them successfully.
  • cURL: cURL is installed by default on most UNIX, Linux(r), and Mac OS X systems. You can download a version for Windows and virtually every other OS.


Sign in or register to add and subscribe to comments.

Zone=Java development, Web development, Open source
ArticleTitle=Mastering Grails: Creating a custom plug-in