How to Deploy a Grails Application to GlassFish

As outlined at How to Deploy a Grails Application to JBoss 5, deploying to JBoss 5 just requires to remove some logging jars and disable Grails logging configuration. With GlassFish however, it is required to supply certain logging jars (e.g. within your war file) in order to use its native logging system.

I’ll give a full source example on how to achieve this, using Grails 1.2.1 and GlassFish v3. The code should as well run a-is with Grails 1.2.2 and GlassFish v2 (and even with Tomcat 6 using its default Java Util Logging configuration). Watch-out: GlassFish currently refuses to deploy Grails 1.2.2 applications – see Links below.

I won’t cover using JNDI data sources here, as their implementation is straight forward and nicely covered by GlassFish’s administration console. You should always use JNDI and JDBC pools provided by GlassFish though, as they offer superior reliability and shield your application from deployment site details.

Note that with GlassFish v3, it may be feasible to deploy skinny wars, i.e. instead of including them within your war, let GlassFish supply the jars required for running a Grails application. This pattern reduces resource usage when running multiple Grails applications within a single GlassFish instance. I haven’t looked into this, as for me the potential gain did not justify the effort when building and keeping track of possibly conflicting Grails versions.

GlassFish uses Java Util Logging as its native logging implementation. Thus your Grails war should delegate its logging to Jul as well in order take advantage of GlassFish built-in web administration and alert features. Components shown in green have to be added to your war and the ones in red are to be removed:

Grails logging stack for GlassFish

How to achieve this? Just supplying an additional Grails configuration file and changing a single configuration attribute will do the trick.

First within scripts/_Events.groovy we’ll remove offending jars, add required jars and disable Grails logging configuration components:

import groovy.xml.StreamingMarkupBuilder

/**
 *** TODO GLASSFISH - Remove log4j configuration stuff (when running with JBoss or GlassFish a.s.o) ***
 */
eventWebXmlEnd = {String tmpfile ->

    def root = new XmlSlurper().parse(webXmlFile)

    // When running with JBoss (or GlassFish a.s.o) remove log4j configuration stuff
    def log4j = root.listener.findAll {node ->
        node.'listener-class'.text() == 'org.codehaus.groovy.grails.web.util.Log4jConfigListener'
    }
    log4j.replaceNode {}

    def log4jFile = root.'context-param'.findAll {node ->
        node.'param-name'.text() == 'log4jConfigLocation'
    }
    log4jFile.replaceNode {}

    webXmlFile.text = new StreamingMarkupBuilder().bind {
        mkp.declareNamespace("": "http://java.sun.com/xml/ns/j2ee")
        mkp.yield(root)
    }
}

/**
 *** TODO GLASSFISH Remove log4j and use jul as used by GlassFish instead ***
 */
eventCreateWarStart = { warName, stagingDir ->

    if (grailsEnv == "production") {

        String log4jVer = "1.2.15"
        String slf4jVer = "1.5.8"

        [
          "lib/log4j-${log4jVer}.jar", // log4j not used with GlassFish
          "classes/log4j.properties", // logging conf done in GlassFish Admin only
          "lib/slf4j-log4j12-${slf4jVer}.jar", // log4j not used with Glassfish
          "lib/jul-to-slf4j-${slf4jVer}.jar", // not required, native JUL with by GlassFish
            // you might want to remove JDBC drivers when using server supplied JNDI...
            //          "lib/hsqldb-1.8.0.10.jar",
        ].each {
            println "*** GLASSFISH *** _Events.groovy removing ${it}"
            Ant.delete(file: "${stagingDir}/WEB-INF/$it")
        }

        // Grails+Ivy (as yet) do not provide war-only dependencies - thus we fetch them manually
        Ant.mkdir(dir: "${basedir}/glassfishlibs") // to this dir (in case your internet breaks down)

        [
          "slf4j-jdk14", // from http://repo1.maven.org/maven2/org/slf4j/slf4j-jdk14/1.5.8/slf4j-jdk14-1.5.8.jar
          "log4j-over-slf4j", // from http://repo1.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.5.8/log4j-over-slf4j-1.5.8.jar
        ].each { artifactId ->
            String fileName = "${artifactId}-${slf4jVer}.jar"

            if (!(new File("${basedir}/glassfishlibs/${fileName}")).file ) {
                println "*** GLASSFISH *** _Events.groovy getting ${fileName}"
                Ant.get(dest: "${basedir}/glassfishlibs/${fileName}",
                        src: "http://repo1.maven.org/maven2/org/slf4j/${artifactId}/${slf4jVer}/${fileName}")
            }

            println "*** GLASSFISH *** _Events.groovy copying ${fileName}"
            Ant.copy(file: "${basedir}/glassfishlibs/${fileName}",
                     tofile: "${stagingDir}/WEB-INF/lib/${fileName}")
        }

    }
}

Unfortunately, I found no way to cause Grails+Ivy dependency resolution to include artifacts solely when building a war (the other way around appears to be feasible though). Thus the script outlined above uses Ant to fetch the required Jars from Maven’s Central repository and saves them to a folder within your project (glassfishlibs) in order to have subsequent project builds succeed, even if there’s no connectivity to the Internet.

Watch out: The jar versions as stated within the script might need to be adopted for Grails versions other than 1.2.1 or 1.2.2.

Next, within grails-app/conf/Config.groovy we’ll instruct Grails not to enable the Jul-to-Slf4j bridge, as this bridge would either alter GlassFishs loggings setup and cause infinite looping or class-not-found errors (as we removed the bridge jar from our war):

// *** TODO GLASSFISH doesn't use jul bridge, as GlassFish uses native jul ***
grails.logging.jul.usebridge = false // instead of true

You are now set to control logging using GlassFish’s excellent Web GUI.

Links:

About Reiner

Born 1954 in Ratisbon (Bavaria, Germany), in 1976 punched cards at Berlin Technical University, caught hacking one of its mainframes by Horst Zuse (son of Konrad Zuse), started studying computer science and soon was offered a job whithin their computer department doing systems programming for IBM VM/370. While studying, jobbed around Germany at various places doing all sorts of things, then returned to Berlin to work at SRZ (computer aided typesetting). Never finished my master degree, but chose to take up self-employed work (which didn't turn me rich nor famous). Now working for a mid-sized software company within a very promising department as head of server software development.
This entry was posted in English, Grails. Bookmark the permalink.

Leave a comment