How to Deploy a Grails Application to GlassFish

Posted on March 27th, 2010 by Reiner.
Categories: Grails, English.

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:

13 comments.

Reiner

Comment on March 27th, 2010.

Forgot to mention: The sample app provided uses grails-app/conf/LogFilters to show off logging:

/**
 *** TODO GLASSFISH - Just to show-off that logging is working with GlassFish ***
 *
class LogFilters {
    def filters = {
        logit(controller:"*", action:"*") {
            before = {
                log.info "controllerName=$controllerName actionName=$actionName params=$params"
                true
            }
        }
    }
}

Hauke

Comment on March 29th, 2010.

Great job, Reiner! Thx alot for this solution! Working 100%

Greetings
Hauke

Twitter Trackbacks for Reiner Saddey’s Place » How to Deploy a Grails Application to GlassFish [saddey.net] on Topsy.com

Pingback on March 29th, 2010.

[…] Reiner Saddey’s Place » How to Deploy a Grails Application to GlassFish blog.saddey.net/2010/03/27/how-to-deploy-a-grails-application-to-glassfish – view page – cached Just another WordPress weblog for Reiner Saddey Filter tweets […]

Pascal

Comment on March 29th, 2010.

Nice howto.

Also, how did you draw your diagram? It looks really neat.

Reiner

Comment on March 29th, 2010.

Thanks Pascal (blush)!

The diagram has been prepared using http://yuml.me - see also the links at the very bottom of my post - the orange ones are the links :-)

I really love this site - much more agile and time-saving for day-to-day docs than “real” full-featured and heavy weight UML tools (whose sophisticated symbols tend to remain ornaments for most audiences - and for me, the MDA coach has turned into an unaffordable pumpkin within days).

I think, it offers just the right balance of features and ease-of-use. See real-world http://bit.ly/cgJEap for some more complex examples.

Regards,
Reiner

Pascal

Comment on March 29th, 2010.

Oh sorry! Actually I was quite sleepy when I first read your post so I did miss the link section at the button of your post. Thanks for pointing out.

yuml seems really nice indeed!

Bill

Comment on May 27th, 2010.

Reiner - thanks very much for this! Great post!

ankimal

Comment on May 31st, 2010.

This is a lifesaver. Works 100%. I just added the Events.groovy script in my [app-dir]/scripts directory and it all worked just fine. I wish if there was a way to make logging work for other components as well (EJBs, glassfish’s error messages etc.)

Will Krespan

Comment on August 11th, 2010.

Reiner-

first thanks for the diagram and code which helped with understanding why the logging wasn’t working in glassfish v2 for me.

Using your logic I tried an experiment and simply updated my Grails project (v. 1.1.2) pom file , since I’m using maven to build this project in idea. So I didn’t actually use the Events script or LogFilter but did add the line,

“grails.logging.jul.usebridge = false ” to Config

Then I added these lines to the pom.xml to include new libraries as well as commenting out sl4j-log4j:

        <!–dependency> 
          <groupId>org.slf4j</groupId> 
          <artifactId>slf4j-log4j12</artifactId> 
          <version>1.5.5</version> 
          <scope>runtime</scope> 
        </dependency–> 
        <dependency> 
         <groupId>org.slf4j</groupId> 
          <artifactId>log4j-over-slf4j</artifactId> 
          <version>1.5.5</version> 
          <scope>runtime</scope> 
        </dependency> 
        <dependency> 
          <groupId>org.slf4j</groupId> 
          <artifactId>slf4j-jdk14</artifactId> 
          <version>1.5.5</version> 
          <scope>runtime</scope> 
        </dependency> 
        <dependency> 
          <groupId>log4j</groupId> 
          <artifactId>log4j</artifactId> 
          <version>1.2.14</version> 
        </dependency>
 

Glassfish v2 logging works like a charm with this set of changes, if one wants to use Maven. Just thought someone out there might like to know.

Thanks again for the tutorial.

WillK

Ludovic R.

Comment on January 19th, 2012.

Thanks a lot for sharing theses tips. I modified it a bit because it prevents app from working when launched with “grails run-app” command.
Actually it should only modify the web.xml when building a war.
Here is what i use :

eventCreateWarStart = { warName, stagingDir ->

def webXmlFile = new File(”${stagingDir}/WEB-INF/web.xml”)
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.plugins.log4j.web.util.Log4jConfigListener’
}
log4j.replaceNode {}

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

def writer = new FileWriter(webXmlFile)
writer

Ludovic R.

Comment on January 20th, 2012.

Just noticed my comment has been cut… Here is the end of the closure :

// Delete space between

Ludovic R.

Comment on January 20th, 2012.

Sorry, the comment parser seems to think i am trying to inject HTML tag and i get censored. Last try…
// Replace < by the equivalent char in HTML
writer << new StreamingMarkupBuilder().bind {
mkp.declareNamespace(”": “http://java.sun.com/xml/ns/j2ee”)
mkp.yield(root)
}
writer.close()

}

WORKPLACEMENT

Comment on March 8th, 2012.

Hi thanks for this great tutorial

I have a war that is uploaded and work’s fine in jboss EAP 5

The same waar don’t work in jboss SOA platform , the war if deployed fine but when I want to click sur save I have a error like :

I want to deploy a grails 1.3.7 application to Jboss 5.2 but I have a problem with the JTA transaction :

Stacktrace follows: org.hibernate.HibernateException: Unable to locate current JTA transaction
at xxxx.deploy.DonneeController$_closure4.doCall(DonneeController.groovy:24)
at xxxx.deploy.DonneeController$_closure4.doCall(DonneeController.groovy)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:183)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:95)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at java.lang.Thread.run(Thread.java:662)

The resources.xml groovy file is :

My jboss-web.xml is:

xxxx.DeployIHM:archive=xxxx-Deploy-1.0-SNAPSHOT.war
java2ParentDelegation=false

I guess there is a conflict with jbpm nead help

Thanks in advance

Leave a comment

Comments can contain some xhtml. Names and emails are required (emails aren't displayed), url's are optional.