Loading...

Monday, January 23, 2012

Groovy Goodness: Solve Naming Conflicts with Builders

With Groovy we can use for example the MarkupBuilder or JSONBuilder to create XML or JSON content. The builders are a very elegant way to create the content. Most builders in Groovy use the invokeMethod and getProperty and setProperty methods to dynamically build the contents. But this also means that if we have builder node names that are the same as method or property names in the local context of our code running the builder, that we have a naming conflict. Let's see this with a simple sample:

import groovy.xml.*

def body = []

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.message {
    body(contentType: 'plain') {
        text 'Simple message'
    }
}

def contents = writer.toString()
println contents

When we run this code we get an error message:

groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.call() is applicable for argument types: (java.util.LinkedHashMap, xmlmessage$_run_closure1_closure2) values: [[contentType:plain], xmlmessage$_run_closure1_closure2@50502819]
Possible solutions: tail(), wait(), last(), any(), max(), clear()
 at xmlmessage$_run_closure1.doCall(xmlmessage.groovy:7)
 at xmlmessage$_run_closure1.doCall(xmlmessage.groovy)
 at xmlmessage.run(xmlmessage.groovy:6)

Groovy tries to use the ArrayList class of our books variable to execute a call method with two parameters of type LinkedHashMap and closure. So our local variable is found by the builder and the builder tries to use this variable, which results in the shown error.

The following sample shows what happens if we have a local method with the same name as a node in the builder:

import groovy.xml.*

def body(value) {
    println "body contents is $value"
}

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.message {
    body {
        text 'Simple message'
    }
}

def contents = writer.toString()
println contents

We get the following output if we run this script:

body contents is 
<message>
  <text>Simple message</text>
</message>

Our method with the name body has the same signature and name as the body node in the builder. Our local method is invoked and we see the output of the println statement.

To solve this naming conflict we can change the name of our local variable or method. But this is not always possible or desired. Imagine the method or variable is dynamically added to our class than we cannot change the name. But we can also change our builder syntax slightly to get what we want.

To force our builder to use the builder's code to create the contents we can prepend the node name with delegate. Delegate is the closure context of our builder. This way our builder will not use any already defined variable or method names to create the content.

import groovy.xml.*

def body = []

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.message {
    delegate.body(contentType: 'plain') {
        text 'Simple message'
    }
}

def contents = writer.toString()
println contents

When we run the script we get the following output:

<message>
  <body contentType='plain'>
    <text>Simple message</text>
  </body>
</message>

And that is the output we want.

If we are using Grails and use the render method to create XML or JSON we must be aware that methods are also dynamically available in a controller. For example the message method from the Grails tag libraries is a method in a controller:

package builder.naming

class SampleController {

    def index() {
        render(contenType: 'text/xml') {
            message {
                content 'Contents'
            }
        }
    }
}

If we invoke this controller we get the following XML output:

<content>Contents</content>

But if we change the code to:

package builder.naming

class SampleController {

    def index() {
        render(contenType: 'text/xml') {
            delegate.message {
                content 'Contents'
            }
        }
    }
}

We get the following output:

<message><content>Contents</content></message>

Thursday, January 12, 2012

Grails Goodness: Generate Links Outside Controllers or Tag Libraries

In Grails we can create a link to a controller with the link() method. This works in the context of a request, like in a controller, tag library or Groovy Server Page (GSP). But since Grails 2.0 we can also generate links in services or any other Spring bean in our project. To create a link we need to inject the grailsLinkGenerator bean into our class. The grailsLinkGenerator bean has a link() method with the same argument list as we are already used to. We can define for example the controller, action and other parameters and the method will return a correct link.

We can also create the link for a resource with the resource() method. And to get the context path and server base URL we use the methods getContextPath() and getServerBaseURL().

The following service uses the link generator to create links in a Grails service.

// File: grails-app/service/link/generator/LinkService.groovy
package link.generator

import org.codehaus.groovy.grails.web.mapping.LinkGenerator

class LinkService {

    // Inject link generator
    LinkGenerator grailsLinkGenerator

    String generate() {
        // Generate: http://localhost:8080/link-generator/sample/show/100
        grailsLinkGenerator.link(controller: 'sample', action: 'show', id: 100, absolute: true)
    }

    String resource() {
        // Generate: /link-generator/css/main.css
        grailsLinkGenerator.resource(dir: 'css', file: 'main.css')
    }

    String contextPath() {
        // Generate: /link-generator
        grailsLinkGenerator.contextPath
    }

    String serverUrl() {
        // Generate: http://localhost:8080/link-generator
        grailsLinkGenerator.serverBaseURL
    }
}

Wednesday, January 11, 2012

Grails Goodness: Date Request Parameter Value Conversions

Grails has great support for type conversion on request parameters. And since Grails 2.0 the support has been extended to include dates. In our controller we can use the date() method on the params object to get a date value. The value of a request parameter is a String, so the String value is parsed to a Date object.

The default expected date format is yyyy-MM-dd HH:mm:ss.S. If we don't specify a specific date format in the date() method then this format is used. Or we can add a format to our messages.properties with the key date.<param-name>.format. Grails will first try the default format, but if the request parameter cannot be parsed to a valid Date object then Grails will do a lookup of the date format in messages.properties. Technically Grails uses the MessageSource bean to get the format, so we even can define the format per language or country.

Alternatively we can pass a date format or multiple date formats to the date() method. Grails will use these date formats to parse the request parameter into a valid Date object.

Let's show the different options we have in a simple sample controller:

// File: grails-app/controllers/param/date/SampleController.groovy
package param.date

class SampleController {

    final def dateFormats = ['yyyy-MM-dd', 'yyyyMMdd']

    def index() {
        [
                defaultFormatDate: defaultFormatDate,
                defaultFormatNameDate: defaultFormatNameDate,
                singleFormatDate: singleFormatDate,
                multipleFormatsDate1: multipleFormatsDate1,
                multipleFormatsDate2: multipleFormatsDate2
        ]
    }

    private Date getDefaultFormatDate() {
        // Use default format yyyy-MM-dd HH:mm:ss.S
        params.date 'defaultFormatDate'
    }

    private Date getDefaultFormatNameDate() {
        // Lookup format with key date.defaultFormatNameDate.format
        // in messages.properties: yyyy-MM-dd
        params.date 'defaultFormatNameDate'
    }

    private Date getSingleFormatDate() {
        params.date 'singleFormatDate', 'yyyyMMdd'
    }

    private Date getMultipleFormatsDate1() {
        params.date 'multipleFormatsDate1', dateFormats
    }

    private Date getMultipleFormatsDate2() {
        params.date 'multipleFormatsDate2', dateFormats
    }

}

In messages.properties we define the format for the request parameter defaultFormatNameDate:

# File: grails-app/i18n/messages.properties
...
date.defaultFormatNameDate.format=yyyy-MM-dd
...

To show that the date parsing works we write a little integration test. We need this to be an integration test, because then the lookup of the key via the MessageSource bean works.

package param.date

import org.junit.Test

class SampleControllerTests extends GroovyTestCase {

    @Test
    void testDateParameters() {
        def controller = new SampleController()

        // Set request parameters.
        def params = [
                defaultFormatDate: inputDateTime.format('yyyy-MM-dd HH:mm:ss.S'),
                defaultFormatNameDate: inputDateTime.format('yyyy-MM-dd'),
                singleFormatDate: inputDateTime.format('yyyyMMdd'),
                multipleFormatsDate1: inputDateTime.format('yyyy-MM-dd'),
                multipleFormatsDate2: inputDateTime.format('yyyyMMdd')
        ]
        controller.request.parameters = params

        def model = controller.index()

        assertDates inputDateTime, model.defaultFormatDate
        assertDates inputDate, model.defaultFormatNameDate
        assertDates inputDate, model.singleFormatDate
        assertDates inputDate, model.multipleFormatsDate1
        assertDates inputDate, model.multipleFormatsDate2
    }

    private void assertDates(final Date expected, final Date controllerDate) {
        assertEquals expected.toGMTString(), controllerDate.toGMTString()
    }

    /**
     * Create Date object for January 10, 2012 14:12:01.120
     */
    private Date getInputDateTime() {
        final Calendar cal = Calendar.instance
        cal.updated(year: 2012, month: Calendar.JANUARY, date: 10, 
                    hours: 14, minutes: 12, seconds: 1, milliSeconds: 120)
        cal.time
    }

    private Date getInputDate() {
        final Date inputDateTime = inputDateTime
        inputDateTime.clearTime()
        inputDateTime
    }
}

Monday, January 2, 2012

Happy New Year and a Groovy 2012

I wish everyone a happy, healthy and Groovy 2012!

Today is my first working day at my new employer JDriven. Here I will work on Grails and Spring related projects together with 10 very enthusiastic, eager-to-learn, skilled and friendly colleagues. At JDriven we focus on SpringSource technologies and for me Groovy and Grails are (of course) very important. I am eager to start and really looking forward to a great year filled with fun at work by doing great projects with great technologies.

Oh, the perceptive reader might have seen the color change in the haki logo. Instead of black and white colors of the JDriven colors are used to celebrate my new job.

Tuesday, December 27, 2011

Grails Goodness: Customize the URL Format

Starting from Grails 2.0 we can change the URL format in our application. Default a camel case convention is used for the URLs. For example a controller SampleAppController with an action showSamplePage results in the following URL /sampleApp/showSamplePage.

We can change this convention by creating a new class that implements the grails.web.UrlConverter interface. Grails already provides the custom UrlConverter grails.web.HyphenatedUrlConverter. This converter will add hyphens to the URL where there are uppercase characters and the uppercase character is converted to lowercase. Our sample controller and action result in the following URL with the HyphenatedUrlConverter: /sample-app/show-sample-page.

Because Grails already provides this UrlConverter it is very easy to configure. We only need to change our configuration in grails-app/conf/Config.groovy. We add the key grails.web.url.converter with the value hyphenated:

// File: grails-app/conf/Config.groovy
...
grails.web.url.converter = 'hyphenated'
...

But we can implement our own class with the grails.web.UrlConverter interface to define our own URL format to be used in the Grails application. The interface only has one method String toUrlElement(String) we need to implement. The input argument is the name of the controller or action that needs to be converted. We cannot see if the value is a controller or action value, the conversion rules will be applied to both controller and action values. The following class is a sample implementation. The controller or action name is first converted to lowercase. Next we add the extension -grails to the controller or action. We make sure the conversion is not already done by checking if the extension is not already in place. This check is necessary because Grails will invoke our UrlConverter several times to map it to the correct controller and action names. And without the check the extension would be added again and again and again, resulting in a 404 page not found error.

// File: src/groovy/customize/url/format/CustomUrlConverter.groovy
package customize.url.format

import grails.web.UrlConverter
import org.apache.commons.lang.StringUtils

class CustomUrlConverter implements UrlConverter {
    private static final String GRAILS_EXTENSION = '-grails'

    String toUrlElement(String propertyOrClassName) {
        if (StringUtils.isBlank(propertyOrClassName)) {
            propertyOrClassName
        } else {
            String lowerPropertyOrClassName = propertyOrClassName.toLowerCase()
            String extendedPropertyOrClassName = addGrailsExtension(lowerPropertyOrClassName)
            extendedPropertyOrClassName
        }
    }

    private String addGrailsExtension(String propertyOrClassName) {
        if (propertyOrClassName.endsWith(GRAILS_EXTENSION)) {
            propertyOrClassName
        } else {
            propertyOrClassName + GRAILS_EXTENSION
        }
    }
}

We have our custom UrlConverter. Now we need to configure our Grails application to use it. This time we don't change the configuration grails-app/conf/Config.groovy, but we add our custom implementation to the Spring configuration in grails-app/conf/spring/resources.groovy. If we use the name with the value of the constant grails.web.UrlConverter.BEAN_NAME for our implementation then Grails will use our custom UrlConverter. We can remove any grails.web.url.converter from Config.groovy, because it will not be used.

// File: grails-app/conf/spring/resources.groovy
import static grails.web.UrlConverter.BEAN_NAME as UrlConverterBean

beans = {
...
    "${UrlConverterBean}"(customize.url.format.CustomUrlConverter)
...
}

We are done. If we start our application then we use the URL /sampleapp-grails/showsamplepage-grails to access the controller SampleAppController and the method showSamplePage() in the controller.

Friday, December 16, 2011

Alfresco 4 and Web Quick Start Page Not Found Errors

After installing Alfresco 4.0.b with the Web Quick Start module and setting up the demo site following the instructions I got "Page not found" errors. With the Alfresco 3.x release I never experienced these problems. It turns out to be a problem with the new Solr search engine that is used. The workaround for now is to revert back to the Lucene search mechanism. The Alfresco forum has a topic with a description of the workaround.

We need to change the file $ALFRESCO_HOME/tomcat/shared/classes/alfresco-global.properties. The key index.subsystem.name needs to be changed to lucene instead of solr. Also we must add an extra key index.recovery.mode with the value FULL. After the changes we must restart Alfresco and then the Web Quick Start demo site works as expected.

# File: $ALFRESCO_HOME/tomcat/shared/classes/alfresco-global.properties
...
### Solr indexing ###
#index.subsystem.name=solr
index.subsystem.name=lucene
index.recovery.mode=FULL
...

Sunday, December 11, 2011

Some Groovy Love :-)

Our 2 year old son plays with his Lego Duplo Cars set and already experiences some Groovy love. ;-)


Monday, November 28, 2011

Grails Goodness: Get GrailsApplication and ApplicationContext in GSP

Several variables are injected to Groovy Server Pages (GSP) in a Grails application. Two of them are the ApplicationContext and GrailsApplication objects. They are bound to the variables applicationContext and grailsApplication.

When we have access to the ApplicationContext we could for example load resources or get references to beans in the context. Via the grailsApplication variable we have access to for example the configuration values and metadata of the application.

<%-- File: grails-app/views/view/index.gsp --%>
<html>
    <head>
        <title>GSP Sample</title>
    </head>
    <body>
        <h1>ApplicationContext</h1>

        <dl>
            <dt>applicationContext</dt>
            <dd>${applicationContext}</dd>
            <dt># beans</dt>
            <dd>${applicationContext.beanDefinitionCount}</dd>
            <dt>beans</dt>
            <dd>${applicationContext.beanDefinitionNames.join(', ')}</dd>
        </dl>

        <h1>GrailsApplication</h1>

        <dl>
            <dt>grailsApplication</dt>
            <dd>${grailsApplication}</dd>
            <dt>configuration</dt>
            <dd>${grailsApplication.config}</dd>
            <dt>metadata</dt>
            <dd>${grailsApplication.metadata}</dd>
        </dl>
    </body>
</html>

When we open this GSP in our browser we get the following output:


Friday, November 25, 2011

Grails Goodness: Access Action and Controller Name in GSP

In our GSP views we can see the name of the action and controller that resulted in the view. We can use this for example to show or hide certain information based on the values for the action and controller name. Grails injects the variables actionName and controllerName automatically and sets the values based on the action and controller.

// File: grails-app/controller/com/mrhaki/sample/ViewController.groovy
package com.mrhaki.sample

class ViewController {

    def index = {}
}
<%-- File: grails-app/views/view/index.gsp --%>
<html>
    <head>
        <title>GSP Sample</title>
    </head>
    <body>
        <h1>Action and Controller Name</h1>

        <ul>
            <li>controllerName: <strong>${controllerName}</strong></li>
            <li>actionName: <strong>${actionName}</strong></li>
        </ul>
    </body>
</html>

When we open the GSP we get the following output:


Wednesday, November 23, 2011

Groovy Goodness: Magic Package to Add Custom MetaClass

Groovy is very dynamic. We can add methods to classes at runtime that don't exist at compile time. We can add our own custom MetaClass at startup time of our application if we follow the magic package naming convention. The naming convention is groovy.runtime.metaclass.[package].[class]MetaClass. For example if we want to change the behavior of the java.lang.String class, then we must write a custom MetaClass with the package name groovy.runtime.metaclass.java.lang and class name StringMetaClass. We can do the same for classes we create ourselves. For example if we have a class myapp.RunApp than the custom metaclass implementation RunAppMetaClass would be in package groovy.runtime.metaclass.myapp.

Our custom MetaClass is extended from DelegatingMetaClass and besides the name of the class and the package we can write our code the way we want.

We must first compile the custom MetaClass and then we must put it in the classpath of the application code that is going to use the MetaClass.

// File: StringMetaClass.groovy
package groovy.runtime.metaclass.java.lang

class StringMetaClass extends DelegatingMetaClass {

    StringMetaClass(MetaClass meta) {
        super(meta)
    }

    Object invokeMethod(Object object, String method, Object[] arguments) {
        if (method == 'hasGroovy') {
            object ==~ /.*[Gg]roovy.*/
        } else {
            super.invokeMethod object, method, arguments
        }
    }
}

The code that will use the delegating metaclass implementation:

// File: StringDelegateSample.groovy

// Original methods are still invoked.
assert 'mrhaki'.toUpperCase() == 'MRHAKI'

// Invoke 'hasGroovy' method we added via the DelegatingMetaClass.
assert !'Java'.hasGroovy()
assert 'mrhaki loves Groovy'.hasGroovy()
assert 'Groovy'.toLowerCase().hasGroovy()

First we compile our StringMetaClass:
$ groovyc StringMetaClass.groovy.

Next we can run the StringDelegateSample.groovy file if we put the generated class file in our classpath:
$ groovy -cp . StringDelegateSample