Loading...

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


Thursday, November 17, 2011

Groovy Goodness: Create Simple Builders with Closures

In Groovy we can use pre-defined builders like the JsonBuilder or MarkupBuilder to create data or text structures. It is very easy to create our own builder simply with closures. A node in the builder is simply a method and we can use a closure as the argument of the method to create a new level in the builder hierarchy.

We can use pre-defined method names in our builder syntax, but can also use dynamic or unkown method names by implementing the methodMissing method. The same goes for properties we can implement with real property methods or by implementing the propertyMissing method.

In our example we create a new builder to create a Reservation object for a travel flight. In the builder we can define a list of passengers, the destination airport, the departing airport and if the flight is a two-way flight.

// Builder syntax to create a reservation with passengers,
// departing and destination airport and make it a 2-way flight.
def reservation = new ReservationBuilder().make {
    passengers {
        name 'mrhaki'
        name 'Hubert A. Klein Ikkink'
    }
    from 'Schiphol, Amsterdam'
    to 'Kastrup, Copenhagen'
    retourFlight
}

assert reservation.flight.from == new Airport(name: 'Schiphol', city: 'Amsterdam')
assert reservation.flight.to == new Airport(name: 'Kastrup', city: 'Copenhagen')
assert reservation.passengers.size() == 2
assert reservation.passengers == [new Person(name: 'mrhaki'), new Person(name: 'Hubert A. Klein Ikkink')]
assert reservation.retourFlight


// ----------------------------------------------
// Builder implementation and supporting classes.
// ----------------------------------------------
import groovy.transform.*

@Canonical
class Reservation {
    Flight flight = new Flight()
    List<Person> passengers = []
    Boolean retourFlight = false
}

@Canonical
class Person { String name }

@Canonical
class Airport { String name, city }

@Canonical
class Flight { Airport from, to }

// The actual builder for reservations.
class ReservationBuilder {
    // Reservation to make and fill with property values.
    Reservation reservation

    private Boolean passengersMode = false

    Reservation make(Closure definition) {
        reservation = new Reservation()

        runClosure definition

        reservation
    }

    void passengers(Closure names) {
        passengersMode = true

        runClosure names

        passengersMode = false
    }

    void name(String personName) {
        if (passengersMode) {
            reservation.passengers << new Person(name: personName)
        } else {
            throw new IllegalStateException("name() only allowed in passengers context.")
        }
    }

    def methodMissing(String name, arguments) {
        // to and from method calls will set flight properties
        // with Airport objects.
        if (name in ['to', 'from']) {
            def airport = arguments[0].split(',')
            def airPortname = airport[0].trim()
            def city = airport[1].trim()
            reservation.flight."$name" = new Airport(name: airPortname, city: city)
        }
    }

    def propertyMissing(String name) {
        // Property access of retourFlight sets reservation
        // property retourFlight to true.
        if (name == 'retourFlight') {
            reservation.retourFlight = true
        }
    }

    private runClosure(Closure runClosure) {
        // Create clone of closure for threading access.
        Closure runClone = runClosure.clone()

        // Set delegate of closure to this builder.
        runClone.delegate = this

        // And only use this builder as the closure delegate.
        runClone.resolveStrategy = Closure.DELEGATE_ONLY

        // Run closure code.
        runClone()
    }

}

Groovy Goodness: Create Our Own Script Class

Groovy is a great language to write DSL implementations. The Groovy syntax allows for example to leave out parenthesis or semi colons, which results in better readable DSL (which is actually Groovy code).

To run a DSL script we can use the GroovyShell class and evaluate the script. By default the script is evaluated with an instance of groovy.lang.Script class. But we can extends this Script class and write our DSL allowed methods, which can then be used by the DSL script. We pass our own Script class to the GroovyShell with an CompilerConfiguration object. The CompilerConfiguration allows us to set a new base script class to be used.

The following sample is a simple DSL to change the state of a Car object. Notice we implicitly access the Car object that is passed to the GroovyShell via a binding. The custom CarScript class can access the car object via the binding and change it's state.

import org.codehaus.groovy.control.CompilerConfiguration

// Simple Car class to save state and distance.
class Car {
    String state
    Long distance = 0
}

// Custom Script with methods that change the Car's state.
// The Car object is passed via the binding.
abstract class CarScript extends Script {
    def start() {
        this.binding.car.state = 'started'
    }

    def stop() {
        this.binding.car.state = 'stopped'
    }

    def drive(distance) {
        this.binding.car.distance += distance
    }
}


// Use custom CarScript.
def compilerConfiguration = new CompilerConfiguration()
compilerConfiguration.scriptBaseClass = CarScript.class.name

// Define Car object here, so we can use it in assertions later on.
def car = new Car()
// Add to script binding (CarScript references this.binding.car).
def binding = new Binding(car: car)

// Configure the GroovyShell.
def shell = new GroovyShell(this.class.classLoader, binding, compilerConfiguration)

// Simple DSL to start, drive and stop the car.
// The methods are defined in the CarScript class.
def carDsl = '''
start()
drive 20
stop()
'''

// Run DSL script.
shell.evaluate carDsl

// Checks to see that Car object has changed.
assert car.distance == 20
assert car.state == 'stopped'

Monday, November 14, 2011

Grails Goodness: Internationalize Javascript Messages with JAWR Plugin

Grails has great builtin support for internationalization (i18n). The underlying Spring support for i18n is used. We can easily change for example text on views based on the user's locale. But this only applies for the server side of our code. So we can generate the correct messages and labels based on the user's locale on the server, but not in our Javascript code. What if we want to display a localized message in a bit of Javascript code, that is not created on the server? Why do I add this extra information 'not created on the server'? Because we can still generate Javascript code in a view or use the gsp-resources plugin to create Javascript on the server. This code can contain the output of a localized message and can be used in Javascript. But that is not what we want for this blog post. Here we are going to reference our i18n messages from plain, non-generated Javascript code.

We can achieve this with the JAWR plugin. The plugin provides roughly the same functionality as the resources plugin for bundling resources efficiently in a Grails application. We are not interested in that part, but the JAWR library used by the plugin also has a i18n messages generator. And we are going to use that in our Grails application to get localized Javascript messages.

First we must install the JAWR plugin: $ grails install-plugin jawr. Next we can configure the plugin. We open our grails-app/conf/Config.groovy file and add:

// File: grails-app/conf/Config.groovy
...

jawr {
    js {
        // Specific mapping to disable resource handling by plugin.
        mapping = '/jawr/'

        bundle {
            lib {
                // Bundle id is used in views.
                id = '/i18n/messages.js'

                // Tell which messages need to localized in Javascript.
                mappings = 'messages:grails-app.i18n.messages'
            }
        }
    }
    locale {
        // Define resolver so ?lang= Grails functionality works with controllers.
        resolver = 'net.jawr.web.resource.bundle.locale.SpringLocaleResolver'
    }
}

...

At line 6 we define a mapping. If we don't define a mapping the JAWR plugin will also act as a resource and bundling plugin, but for this example we only want to use the i18n messages generator.

Line 14 defines which resource in the classpath contains the messages that need to be accessible in Javascript. For our Grails application we want the messages from messages.properties (and the locale specific versions) so we define grails-app.i18n.messages.

With Grails it is easy to switch to a specific user locale by adding the request parameter lang to a request. At line 20 we add a resolver that will use the Grails locale resolver to determine a user's locale.

It it time to see our Javascript in action. First we create two new message labels in messages.properties. One without variables and one with a variable placeholder to show how the JAWR plugin supports this:

// File: grails-app/i18n/messages.properties
js.sample.hello.message=Hello
js.sample.hello.user.message=Hello {0}

Let's add a Dutch version of these messages in grails-app/i18n/messages_nl.properties:

// File: grails-app/i18n/messages_nl.properties
js.sample.hello.message=Hallo
js.sample.hello.user.message=Hallo {0}

Now it is time to create a GSP view with a simple controller (only request through a controller will be able to use the locale resolver we defined in our configuration).

// File: grails-app/controller/grails/js/i18n/SampleController.groovy
package grails.js.i18n

class SampleController {
    def index = {
        // render 'sample/index.gsp'
    }
}
%{-- File: grails-app/views/sample/index.gsp --}%
<html>
    <head>
        <meta name="layout" content="main"/>
        <jawr:script src="/i18n/messages.js"/>
        <g:javascript library="application"/>
    </head>
    <body>
        <h1>Simple message</h1>

        <input type="button" onclick="showAlertHello();" value="Hello"/>

        <hr/>

        <h1>Message with variable placeholder</h1>

        Username: <input type="text" id="username" size="30"/>

        <input type="button" onclick="showAlertUsername();" value="Hello"/>

    </body>
</html>

At line 4 we inlude the Javascript i18n messages generated by the JAWR plugin. And at line 5 we include an external Javascript file that will use the generated messages:

// File: web-app/js/application.js

function showAlertHello() {
    var alertMessage = messages.js.sample.hello.message();
    alert(alertMessage);
}

function showAlertUsername() {
    var usernameValue = document.getElementById("username").value;
    var alertMessage = messages.js.sample.hello.username.message(usernameValue);
    alert(alertMessage);
}

Notice how we can access the i18n messages in Javascript. The plugin will convert the messages to Javascript functions to return the message. And even variable substitution is supported (see line 9).

The following screenshots show the alert messages for the default locale and for a request with the Dutch locale:






With the current configuration of the JAWR plugin all messages in the messages.properties (and locale versions) will be exported to Javascript messages. But maybe this is too much and we only want to include a subset of the messages in the generated Javascript. In the configuration we can define a prefix for the messages to be exported or we can even define a separate properties file with only messages necessary for Javascript:

// File: grails-app/conf/Config.groovy
...
// Only filter messages starting with js.
jawr.js.bundle.lib.mappings=messages:grails-app.i18n.messages[js]
...
// File: grails-app/conf/Config.groovy
...
// Use a different properties file: jsmessages.properties (jsmessages_nl.properties, ...).
jawr.js.bundle.lib.mappings=messages:grails-app.i18n.jsmessages
...

In our Javascript we reference the messages by prefixing messages. to the message properties. We can change this as well in our JAWR plugin configuration. If for example we want to use i18n we must define our plugin as follows:

// File: grails-app/conf/Config.groovy
...
// Define custom namespace for reference in Javascript.
jawr.js.bundle.lib.mappings=messages:grails-app.i18n.messages(i18n)
...

With the use of the JAWR plugin and the i18n messages generator we can easily use localized messages in our Javascript code.

Thursday, November 10, 2011

Groovy Goodness: Parse Date.toString() Value

With Groovy 1.8.4 we can parse the output of the Date.toString() method back to a Date. For example we get the string value of a Date from an external source and want to parse it to a Date object. The format of the string must have the pattern "EEE MMM dd HH:mm:ss zzz yyyy" with the US Locale. This is used by the toString() method of the Date class.

import static java.util.Calendar.*

// Create date 10 November 2011.
def cal = Calendar.getInstance(TimeZone.getTimeZone('Europe/Amsterdam'))
def date = cal.time
date.clearTime()
date[YEAR] = 2011
date[MONTH] = NOVEMBER
date[DATE] = 10

// Get toString() value.
def dateToString = date.toString()
assert dateToString == 'Thu Nov 10 00:00:00 CET 2011'

// Replace Nov for Dec in string and 10 for 24.
dateString = dateToString.replace('Nov', 'Dec').replace('10', '24')

// Use parseToStringDate to get new Date.
def newDate = Date.parseToStringDate(dateString)
assert newDate[MONTH] == DECEMBER
assert newDate[DATE] == 24
assert newDate[YEAR] == 2011

Monday, November 7, 2011

Groovy Goodness: Find Non-Null Results After Transformation in a Collection

Since Groovy 1.8.1 we can use the findResults method and pass a closure to transform elements in a collection and get all non-null elements after transformation. We also have the findResult method to return the first non-null transformed element, but with findResults we get all non-null elements.

def stuff = ['Groovy', 'Griffon', 'Gradle', 'Spock', 'Grails', 'GContracts']
def stuffResult = stuff.findResults { it.size() == 6 ? "$it has 6 characters" : null }

assert stuffResult == ['Groovy has 6 characters', 
                       'Gradle has 6 characters',
                       'Grails has 6 characters']
                        
def map = [what: 'Finish blog post', priority: 1, when: new Date()]
def mapResult = map.findResults { it.value instanceof String ? "Key $it.key is of type String" : null }

assert mapResult == ['Key what is of type String']

Friday, November 4, 2011

Source Code, PDF and Presentation about Groovy 1.8 from JFall 2011

For those that attended the Dutch Java User Group conference JFall 2011 I have posted the slides (not that many, because of live coding ;-) ), the code from the session and an extensive PDF with content on Github.

Tuesday, November 1, 2011

Grassroots Groovy: Reading JSON with JsonSlurper

We can introduce Groovy into our Java projects at grassroots level. In this post we see how we can use the JsonSlurper class in our Java code to read JSON data. Once we have included the Groovy libraries in our project, for example by adding a dependency in a Maven POM file, we can use Groovy classes in our Java applications. And once we have Groovy in our project we might extend the use of Groovy further...

The JsonSlurper class has a parseText() and parse() method to read in JSON data. We get back a Map with values from the JSON structure. Let's see how we can use it in a simple Java application:

package com.mrhaki.sample;

import groovy.json.JsonSlurper;

import java.util.List;
import java.util.Map;

public class JsonParser {

    public static void main(String[] args) {
        String jsonText = "{\"user\":{\"name\":\"mrhaki\",\"age\":38,\"interests\":[\"Groovy\",\"Grails\"]}}";
        JsonSlurper jsonSlurper = new JsonSlurper();
        Object result = jsonSlurper.parseText(jsonText);

        Map jsonResult = (Map) result;
        Map user = (Map) jsonResult.get("user");
        String name = (String) user.get("name");
        Integer age = (Integer) user.get("age");
        List interests = (List) user.get("interests");

        assert name.equals("mrhaki");
        assert age == 38;
        assert interests.size() == 2;
        assert interests.get(0).equals("Groovy");
        assert interests.get(1).equals("Grails");
    }

}

Or use a URL with JSON content:

package com.mrhaki.sample;

import groovy.json.JsonSlurper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;

public class JsonUrlParser {

    private static final String JSON_URL = "http://www.mrhaki.com/samples/sample.json";

    public static void main(String[] args) throws IOException, MalformedURLException {
        URL url = new URL(JSON_URL);
        InputStream urlStream = null;
        try {
            urlStream = url.openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlStream));
            JsonSlurper jsonSlurper = new JsonSlurper();
            Object result = jsonSlurper.parse(reader);

            Map jsonResult = (Map) result;
            Map user = (Map) jsonResult.get("user");
            String name = (String) user.get("name");
            Integer age = (Integer) user.get("age");
            List interests = (List) user.get("interests");

            assert name.equals("mrhaki");
            assert age == 38;
            assert interests.size() == 2;
            assert interests.get(0).equals("Groovy");
            assert interests.get(1).equals("Grails");

        } finally {
            if (urlStream != null) {
                urlStream.close();
            }
        }

    }
}

Once we have the Groovy libraries in our classpath we can run the Java application with $ java -ea com.mrhaki.sample.JsonParser and the assertions should be okay.