Fork me on GitHub

LD.

Music, software, life… and stuff.

[ Twitter ] [ GitHub ] [ Linked In ]

Using Grails tags where you can’t use Grails tags

Sometimes in a Grails app, you need to call a tag where you can’t call a tag. This is usually indicative of a bad design in your application so do use the following with caution, but should you absolutely need to… the following is how you can.

In this example, we are going to add the ability to call tags to a filter to workaround GRAILS-6814. We want to call the createLink tag.

Note that GRAILS-6814 has been resolved for Grails 1.4, so this workaround for redirects to a different domain only applies to Grails 1.3 and earlier

import org.codehaus.groovy.grails.web.pages.GroovyPage
import org.springframework.web.context.request.RequestContextHolder

class HttpsOnlyFilter {

    def gspTagLibraryLookup // need this autowired

    def filters = {
        redirectToHttps(controller: "*", action: "*") {
            before = {
                if (!request.secure && isSecurePage(controllerName, actionName)) {
                    def link = invokeTag("createLink", [
                        controller: controllerName, 
                        action: actionName, 
                        params: params, 
                        base: "https://secure.domain.com"
                    ]).toString()
                    response.status = 301
                    response.setHeader("Location", link)
                    false
                }
            }
        }
    }

    def invokeTag(name, attrs = [:], body = null) {
        def namespace
        def tagName

        if (name.contains(":")) {
            def split = name.split(":", 2)
            namespace = split[0]
            tagName = split[1]
        } else {
            namespace = GroovyPage.DEFAULT_NAMESPACE
            tagName = name
        }

        GroovyPage.captureTagOutput(gspTagLibraryLookup, namespace, tagName, attrs, body, RequestContextHolder.currentRequestAttributes())
    }

}

The invokeTag method takes; the name of a tag, a map of attributes, and an option body closure and returns a StreamCharBuffer (so if you want the content as a String you new to toString() the return). Inside the body closure, you can write to the out stream just like in a tag implementation.

If the tag name given to invokeTag() doesn’t include a namespace, the default g namespace is used. To invoke a tag in a different namespace, you can use…

invokeTag("someNamespace:someTag", [param1: 1])

Remember, requiring tags outside of the view layer can be indicative of a design problem so do think long and hard about whether you really need to before using the above. Also, the above will only work in a request environment so if you try to use the above on a background thread were a fake request environment hasn’t been established it will blow up due to RequestContextHolder.currentRequestAttributes() returning null. If you need to setup a fake request environment, you can use GrailsWebUtil.bindMockWebRequest() to do so.

Posted: May 11th, 2011 @ 11:40 am

Tags: #software  #grails  

Comments

Always developing Grails apps with https and testing against the WAR

In response to a number of bugs creeping through to production due to classpath differences and ssl issues, I went about setting up my culprit grails app to always functionally test as a war and with https in both development and testing. Here’s how to do it.

It turns out that there are two bugs/issues with the current grails tomcat plugin that get in the way of this objective, so you’ll have to install the 1.3.7.1 version of the tomcat plugin which fixes GRAILS-6688 and GRAILS-7488 for Grails 1.3.x (these issues will be fixed for Grails 1.4).

Always support https

This is quite simple, but perhaps a little tricky to work out. Simply put the following in your scripts/_Events.groovy

eventParseArgumentsEnd = {
    argsMap.https = true
}

That’s the only suitable hook that I have found that can be used to force https to be used all the time (i.e. run-app and test-app). It’s a little heavy, but I’m yet to find a situation where it causes an issue.

Always functionally testing with a WAR

Again, this is simple. The following goes in scripts/_Events.groovy

eventAllTestsStart = {
    testOptions.war = true
}

This is equivalent to always passing the -war argument to test-app.

Functional tests and SSL (trust)

Depending on how you are functionally testing (and you know you should be using Geb + Spock) you may have issues with the certificate that Grails will generate for you to serve https. Namely, you might need to go and configure trust settings in all of your functional test browsers etc. If you have multiple CI builds then you are going to have to do this for a lot of certs. Even worse, the cert that Grails generates is stored in the work dir so can be wiped out at any time.

You can minimise this pain by generating your own cert and having Grails use that when serving https instead of creating one on demand. To do this, you need the following two settings in BuildConfig.groovy

grails.tomcat.keystorePath = "${basedir}/grails-app/conf/httpsKeystore"
grails.tomcat.keystorePassword = "secret"

You of course need to create this keystore with a cert in it, which you can do (in grails-app/conf) via…

keytool -genkey -alias localhost -dname CN=localhost,OU=Test,O=Test,C=US -keyalg RSA -validity 365 -storepass key -keystore httpsKeystore -storepass secret -keypass secret

You now only need to make sure the browser trusts this cert.

Why bother?

In my case, we were hitting some dependency issues that were due to the development and production classpaths being different so running functional tests against a war minimises this risk because the app is then run in a separate JVM without the Grails build time classpath, making it more production like.

The application that we were having problems with uses mixed http and https and is also reasonably AJAX heavy. Several issues had crept through with AJAX requests being made on secure pages to non secure pages (which will blow up due to the browser not being willing to compromise security by making the unsecure request).

These two relatively simple steps get you closer to a production environment if you don’t have the resourcing, manpower, will etc. to setup an elaborate QA environment for automated testing.

Posted: May 6th, 2011 @ 1:54 pm

Tags: #software  #grails  

Comments

Decorating Constructors with Groovy

I recently put out a new plugin for Grails that brings something like view models to Grails applications. An interesting feature of this plugin is that it supports direct object instantiation with implicit autowiring. You might think that Grails already support this, but it doesn’t. Currently, you can directly instantiate domain objects and get autowiring but you can’t write a constructor and use it here.

Groovy has had the ability to fiddle with a class’s constructors via EMC for a while.

class Thing {
    def i
    Thing() { i = 1 }
}

assert new Thing().i == 1
Thing.metaClass.constructor = { -> i = 2 }
assert new Thing().i == 2

Trying to augment existing constructors is a bit trickier though. Using the standard EMC API of setting a constructor property on the meta class, there is no way to access the constructor that is being replaced. To do this you have to dig a bit deeper.

For the view models plugin I needed to invoke the real constructor, then do some stuff to the new instance. My solution revolves around the registerInstanceMethod(groovy.lang.MetaMethod method) method of ExpandoMetaClass. After some digging through Groovy, I found that the technique above of setting a constructor property on the meta class boils down to just attaching an instance MetaMethod with a method name of <init> which is the name Groovy uses for constructors. So what we can do is subclass groovy.lang.MetaMethod to get our custom behaviour, which looks like this…

package grails.plugin.viewmodels.constructor;

import java.lang.InstantiationException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import groovy.lang.MetaMethod;
import org.codehaus.groovy.reflection.CachedClass;
import org.codehaus.groovy.reflection.ReflectionCache;

public class DecoratingMetaConstructor<T> extends MetaMethod {

    final private Constructor<T> constructor;
    final private ConstructionDecorator<T> decorator;

    public DecoratingMetaConstructor(Constructor<T> constructor, ConstructionDecorator<T> decorator) {
        super(decorator.getSignature(constructor));

        this.constructor = constructor;
        this.decorator = decorator;
    }

    public Constructor<T> getConstructor() {
        return constructor;
    }

    public int getModifiers() {
        return constructor.getModifiers();
    }

    public String getName() {
        return "<init>";
    }

    public Class<T> getReturnType() {
        return constructor.getDeclaringClass();
    }

    public CachedClass getDeclaringClass() {
        return ReflectionCache.getCachedClass(constructor.getDeclaringClass());
    }

    public Object invoke(Object object, Object[] arguments) {
        Object[] transformedArgs = decorator.transformArgs(arguments);
        T instance = instantiate(transformedArgs);
        decorator.decorate(instance, arguments, transformedArgs);
        return instance;
    }

    protected T instantiate(Object[] arguments) {
        try {
            return decorator.transformConstructor(constructor).newInstance(arguments);
        } catch (InstantiationException e) {
            throw new RuntimeException("Failed to invoke constructor " + constructor + " with args: " + arguments, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to invoke constructor " + constructor + " with args: " + arguments, e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Failed to invoke constructor " + constructor + " with args: " + arguments, e);
        }
    }

}

A lot of that is just satisfying the MetaMethod methods. What’s of interest to us is that we take a constructor object, and a decorator which is an interface that we provide…

package grails.plugin.viewmodels.constructor;

import java.lang.reflect.Constructor;

public interface ConstructionDecorator<T> {

    public Object[] transformArgs(Object[] args);

    public void decorate(T instance, Object[] originalArgs, Object[] transformedArgs);

    public Class<?>[] getSignature(Constructor<T> constructor);

    public Constructor<T> transformConstructor(Constructor<T> constructor);
}

The decorator can supply a different set of args for the actual Constructor to those that were given to the invocation, supply a different Constructor instance to use at instantiation time and/or do something with the instance after it has been created.

We can use this mechanism to write a construction decorator that performs autowiring…

package grails.plugin.viewmodels.constructor;

import java.lang.reflect.Constructor;
import org.springframework.context.ApplicationContext;

public class AutowiringConstructionDecorator<T> extends ConstructionDecoratorSupport<T> {

    final private Autowirer autowirer;

    public AutowiringConstructionDecorator(ApplicationContext applicationContext) {
        this(new Autowirer(applicationContext));
    }

    public AutowiringConstructionDecorator(Autowirer autowirer) {
        this.autowirer = autowirer;
    }

    public void decorate(T instance, Object[] givenArgs, Object[] transformedArgs) {
        autowirer.autowire(instance);
    }

}

The Autowirer takes care of the actual autowiring details, which aren’t of much interest here (see the class here if you want).

So we can now take a class, and make all of it’s constructors implicitly perform autowiring by doing something like this…

def autowiringDecorator = new AutowiringConstructionDecorator(grailsApplication.mainContext)

for (constructor in MyThing.constructors) {
    MyThing.metaClass.registerInstanceMethod(new DecoratingMetaConstructor(constructor, autowiringDecorator))
}

Interestingly, I was able to use the same decoration mechanism to enable hot reloading support by obtaining the newest version of the constructor from the class loader in the Grails application that has the newest version of the class…

package grails.plugin.viewmodels.constructor;

import java.lang.reflect.Constructor;

class ReloadCapableConstructionDecorator<T> extends ConstructionDecoratorSupport<T> {

    private final ClassLoader classLoader;

    public ReloadCapableConstructionDecorator(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public Constructor<T> transformConstructor(Constructor<T> constructor) {
        try {
            Class<T> originalClassVersion = constructor.getDeclaringClass();
            Class<T> newestClassVersion = (Class<T>)classLoader.loadClass(originalClassVersion.getName());

            return newestClassVersion.getConstructor(constructor.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return constructor;
        } catch (ClassNotFoundException e) {
            return constructor;
        }
    }

}

The details of why this is needed isn’t worth going into now, what’s important is the fact that you could do some rather interesting stuff here.

If you find you have the need to decorate existing constructors as opposed to completely replacing them, it’s probably worth taking a look at what’s in the view-models plugin and either stealing it verbatim or adapting to your own purposes.

The relavant code and gory details can be found here.

Posted: Mar 4th, 2011 @ 3:54 pm

Tags: #software  #grails  #groovy  

Comments

Disabling Grails plugin upgrade confirmation

Quick one…

If you want to permanently disable plugin version change confirmations (e.g. when another developer has changed a plugin version in BuildConfig.groovy), simply add this to your scripts/_Events.groovy:

def resolveDependenciesWasInteractive = false
eventResolveDependenciesStart = {
    resolveDependenciesWasInteractive = isInteractive
    isInteractive = false
}

eventResolveDependenciesEnd = {
    isInteractive = resolveDependenciesWasInteractive
}

Annoying messages be gone.

Posted: Jan 6th, 2011 @ 12:44 pm

Tags: #grails  #software  

Comments

Archive · RSS · Theme by Autumn