The Service Layer

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
    }
}

Code written with Grails 2.0.

Original blog post written on January 12, 2012.

Render GSP Views And Templates Outside Controllers

In a Grails application we use Groovy Server Pages (GSP) views and templates to create content we want to display in the web browser. Since Grails 2 we can use the groovyPageRenderer instance to render GSP views and templates outside a controller. For example we can render content in a service or other classes outside the scope of a web request.

The groovyPageRenderer instance is of type grails.gsp.PageRenderer and has a render() method like we use in a controller. We can pass a view or template name together with a model of data to be used in the GSP. The result is a String value.
The class also contains a renderTo() method that can be used to generate output to a Writer object. For example we can generate files with the output of the GSP rendering by passing a FileWriter instance to this method.

In the following sample we create a GSP view confirm.gsp and a GSP template _welcome.gsp. We also create a Grails service with two methods to use the GSP view and template.

%{-- File: grails-app/views/email/_welcome.gsp --}%
Hi, ${username}


%{-- File: grails-app/views/email/confirm.gsp --}%
<!doctype html>
<head>
    <title>Confirmation</title>
</head>

<body>

<h2><g:render template="/email/welcome" model="[username: username]"/></h2>

<p>
    Thank you for your registration.
</p>

</body>
</html>


// File: grails-app/services/page/renderer/RenderService.groovy
package page.renderer

import grails.gsp.PageRenderer

class RenderService {

    /**
     * Use the variable name groovyPageRenderer to enable
     * automatic Spring bean binding. Notice the variable
     * starts with groovy..., could be cause of confusing because
     * the type is PageRenderer without prefix Groovy....
     */
    PageRenderer groovyPageRenderer

    String createConfirmMessage() {
        groovyPageRenderer.render view: '/email/confirm', 
                                  model: [username: findUsername()]
    }

    String createWelcomeMessage() {
        groovyPageRenderer.render template: '/email/welcome', 
                                  model: [username: findUsername()]
    }

    private String findUsername() {
        // Lookup username, for this example we return a
        // simple String value.
        'mrhaki'
    }
}

Next we create a integration test to see if our content is rendered correctly:

// File: test/integration/page/renderer/RenderOutputTests.groovy
package page.renderer

import org.junit.Assert
import org.junit.Test

class RenderOutputTests {

    RenderService renderService

    @Test
    void welcomeMessage() {
        Assert.assertEquals 'Hi, mrhaki', renderService.createWelcomeMessage().trim()
    }

    @Test
    void confirmMessage() {
        final String expectedOutput = '''
        <!doctype html>
        <head>
            <title>Confirmation</title>
        </head>

        <body>

        <h2>
        Hi, mrhaki</h2>

        <p>
            Thank you for your registration.
        </p>

        </body>
        </html>'''

        Assert.assertEquals expectedOutput.stripIndent(), 
                            renderService.createConfirmMessage()
    }
}

We can run our test and everything is okay:

$ grails test-app RenderOutputTests
| Completed 2 integration tests, 0 failed in 1051ms
| Tests PASSED - view reports in target/test-reports

We can use tags from tag libraries in our GSP views and templates. The Sitemesh layouts cannot be used. The PageRenderer works outside of the request scope, which is necessary for the Sitemesh layouts. Because we are outside of the web request scope we cannot generate absolute links in the GSP view directly. If we change the confirm GSP view and add a tag to create an absolute link we get an UnsupportedOperationExeption with the message You cannot read the server port in non-request rendering operations.

%{-- File: grails-app/views/email/confirm.gsp --}%
<!doctype html>
<head>
    <title>Confirmation</title>
</head>

<body>

<h2><g:render template="/email/welcome" model="[username: username]"/></h2>

<p>
    Thank you for your registration.
</p>

<p>
    To use the application can you directly go to the
    <g:link absolute="true" controller="index">home page</g:link>.
</p>

</body>
</html>

But we can simply workaround this issue. Remember that since Grails 2 we can use the grailsLinkGenerator to generate links in for example a service. So we create our absolute link with the grailsLinkGenerator and pass it as a model attribute to our GPS view.

package page.renderer

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

class RenderService {

    PageRenderer groovyPageRenderer

    LinkGenerator grailsLinkGenerator

    String createConfirmMessage() {
        final String homePageLink = grailsLinkGenerator.link(controller: 'index', 
                                                             absolute: true)
        groovyPageRenderer.render(view: '/email/confirm', 
                                  model: [link: homePageLink, 
                                          username: findUsername()])
    }

    String createWelcomeMessage() {
        groovyPageRenderer.render template: '/email/welcome', 
                                  model: [username: findUsername()]
    }

    private String findUsername() {
        // Lookup username, for this example we return a
        // simple String value.
        'mrhaki'
    }
}
%{-- File: grails-app/views/email/confirm.gsp --}%
<!doctype html>
<head>
    <title>Confirmation</title>
</head>

<body>

<h2><g:render template="/email/welcome" model="[username: username]"/></h2>

<p>
    Thank you for your registration.
</p>

<p>
    To use the application can you directly go to the
    <a href="${link}">home page</a>.
</p>

</body>
</html>

Code written with Grails 2.0.

Original blog post written on March 05, 2012.

Accessing Resources with Resource and ResourceLocator

Grails uses Spring and we can piggyback on the Spring support for resource loading to find for examples files in the classpath of our application. We can use the Spring org.springframework.core.io.Resource or org.springframework.core.io.ResourceLoader interface to find resources in our application.

And since Grails 2.0 we can also use the org.codehaus.groovy.grails.core.io.ResourceLocator interface. In our code we can use the grailsResourceLocator service which implements the ResourceLocator interface. We must inject the grailsResourceLocator service into our code and we use the method findResourceForURI(String) to find a resource. The advantage of the grailsResourceLocator service is that it knows about a Grails application. For example resources in plugins can also be accessed.

First we look at a sample Grails service with a Resource property with the name template. In our code we get the actual resource using the getURL() method. The value of the Resource property we set in grails-app/conf/Config.groovy. We rely on the automatic conversion of properties of Spring so we can use a value like classpath:filename.txt and it will be converted to a Resource implementation.

// File: grails-app/services/com/mrhaki/templates/MessageService.groovy
package com.mrhaki.templates

import groovy.text.SimpleTemplateEngine
import org.springframework.core.io.Resource

class MessageService {

    Resource template

    String followUpMessage(final String user, final String subject) {
        final Map binding = [user: user, subject: subject]
        final SimpleTemplateEngine templateEngine = new SimpleTemplateEngine()
        templateEngine.createTemplate(template.URL).make(binding)
    }
}

In grails-app/conf/Config.groovy we define:

...
beans {
    messageService {
        template = 'classpath:/com/mrhaki/templates/mail.template'
    }
}
...

If we use the grailsResourceLocator we get the following service implementation:

// File: grails-app/services/com/mrhaki/templates/MessageService.groovy
package com.mrhaki.templates

import groovy.text.SimpleTemplateEngine

class MessageService {

    def grailsResourceLocator

    String template

    String followUpMessage(final String user, final String subject) {
        final Resource template = grailsResourceLocator.findResourceForURI(template)
        final Map binding = [user: user, subject: subject]
        final SimpleTemplateEngine templateEngine = new SimpleTemplateEngine()
        templateEngine.createTemplate(template.URL).make(binding)
    }
}

Code written with Grails 2.2.4

Original blog post written on September 04, 2013.