How to Deploy a Grails Application to JBoss 5

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

As outlined at Grails - How to Use Native Server Logging Configuration (e.g. Tomcat GlassFish JBoss), it may be advisable to remove any conflicting logging implementation when deploying a Grails application into a production environment. I’ll give a full source example on how to achieve this and how to work-around an issue which prevents a Grails 1.2.0 and 1.2.1 applications from starting.

Unfortunately, each server provides a distinct set of logging frameworks. Still worse, servers can be reconfigured to use alternate logging frameworks (e.g. JBoss can be configured to use Java Logging instead of its default Log4J implementation and Tomcat 6 can be configured to use Log4J instead of its default Java Logging implementation).

Thus you either have to prepare a war which has been set-up for a specific target environment or completely remove any logging implementation from your Grails war and add missing jars to the lib directory of your target server instead. Which one to choose may depend on whether access to the server configuration is permitted (e.g. its lib directory), how many different servers your application is to be deployed to and how hard it is for your build process to reliably produce variants specifically tailored for a particular deployment site.

Before presenting the code for a deployment to JBoss 5.1.0GA, let’s have a look at Grails’ logging architecture. In its infancy Grails just used Apache Commons Logging (JCL) to provide an abstraction level and Log4J to implement the actual logging. Although even now, all log instances injected into Grails applications still implement org.appache.commons.logging.Log, Grails no longer uses JCL, but meanwhile has moved on to SLF4J:

Grails logging architecture

Starting with Grails 1.2, an additional bridge jul-to-slf4j which delegates Java Logging (Jul) to Slf4j is enabled by setting grails.logging.jul.usebridge = true. Be warned though, that for performance reasons this bridge should not be used when expecting heavy logging.

Now for the good news: With JBoss 5, all of the above (but excluding jul-to-slf4j) has already been integrated into the server configuration and libraries. In order to deploy a Grails application to JBoss 5, we’ll just need to get rid of the jars within your war and prevent Grails from trying to configure the logging. How to achieve this?

Within grails-app/conf/BuildConfig.groovy we’ll remove offending jars when building the war:

// TODO JBOSS - Remove own log4j and use the one supplied by JBoss instead
grails.war.resources = {stagingDir ->
    def toRemove = [
          "$stagingDir/WEB-INF/lib/log4j-1.2.14.jar", // log4j supplied by JBoss
          "$stagingDir/WEB-INF/lib/log4j-1.2.15.jar", // log4j supplied by JBoss
          "$stagingDir/WEB-INF/classes/log4j.properties", // logging conf done in JBoss only
          "$stagingDir/WEB-INF/lib/slf4j-api-1.5.6.jar", // slf4j supplied by JBoss 5+
          "$stagingDir/WEB-INF/lib/slf4j-api-1.5.8.jar", // slf4j supplied by JBoss 5+
          "$stagingDir/WEB-INF/lib/slf4j-log4j12-1.5.6.jar", // slf4j supplied by JBoss 5+
          "$stagingDir/WEB-INF/lib/slf4j-log4j12-1.5.8.jar", // slf4j supplied by JBoss 5+
          "$stagingDir/WEB-INF/lib/jcl-over-slf4j-1.5.6.jar", // jcl supplied by JBoss as well
          "$stagingDir/WEB-INF/lib/jcl-over-slf4j-1.5.8.jar", // jcl supplied by JBoss as well
        // see also Config.grails.logging.jul.usebridge - shouldn't be used
        //     http://www.slf4j.org/legacy.html#jul-to-slf4j
        //          "$stagingDir/WEB-INF/lib/jul-to-slf4j-1.5.6.jar",
        //          "$stagingDir/WEB-INF/lib/jul-to-slf4j-1.5.8.jar",
        // you might want to remove JDBC drivers when using server supplied JNDI...
        //          "$stagingDir/WEB-INF/lib/hsqldb-1.8.0.5.jar",
    ].each {
        delete(file: it)
    }
}

Within scripts/_Events.groovy we’ll disable Grails logging configuration components:

import groovy.xml.StreamingMarkupBuilder

/**
 * TODO JBOSS - 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)
    }
}

You are now set to control logging within JBoss jboss-log4j.xml.

If you’re using Grails 1.2.0 or 1.2.1, JBoss still refuses to deploy your war. This is caused by version conflicts within Hibernate jars (used to be work-arounded by deleting all Hibernate jars from JBoss lib directory) and they have been fixed by GRAILS-5606 for (not yet released) Grails 1.2.2.

Graeme Rocher as well supplies a work-around for 1.2.x:

Fixed in latest hibernate plugin 1.3.0.BUILD-SNAPSHOT

It seems in order to use the latest version of Hibernate on JBoss you must include Hibernate validator otherwise you run into this classloading error. This means the hibernate plugin is forced to include hibernate-validator as a dependency even if we don’t use it which is a pretty annoying.

Anyway you can fix this yourselves in 1.2.x by adding the following dependency to BuildConfig.groovy:

runtime('org.hibernate:hibernate-validator:3.1.0.GA') {
    excludes 'sl4j-api', 'hibernate.core',
             'hibernate-commons-annotations', 'hibernate-entitymanager'
    }

Be sure to uncomment the jboss maven repository so the dependency resolvers

This work-around is included within sample sources. Just search for TODO tags.

Links:

7 comments.

Graeme Rocher

Comment on March 8th, 2010.

You should raise a JIRA to make all of this configuration easier

Reiner

Comment on March 9th, 2010.

Will do so - and might suggest to bundle all logging related aspects within one plugin. There’s already a logging plugin, but it just handles automagic log injects and the jul-bridge.

Hauke

Comment on March 25th, 2010.

Thx for this blog entry! Though it seems, you solution does not work for Glassfish 3 - am I correct? Do you know what else I have to change there to get my grails 1.2.1 app running?

Reiner

Comment on March 26th, 2010.

Hi Hauke,

yes, you’re right - this setup won’t work for GlassFish.

JBoss defaults to Log4J and GlassFish uses Java Util Logging.

Thus the approach is similar, but the actual jars to ex- and include have to account for the logging provided by the GlassFish container.

I’ll post configuration details for GlassFish and a tiny ready-to-deploy war including sources this weekend.

Regards,
Reiner

Reiner Saddey’s Place » How to Deploy a Grails Application to GlassFish

Pingback on March 27th, 2010.

[…] 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 […]

Ibon urrutia

Comment on April 23rd, 2010.

Thank you very much! You save my week ;-)
But after deploying with your indications, I am wondering why you don’t use provided scope dependencies. We use maven with grails project, and when we do a clean install, grails scripts can’t found provided scope dependencies. I am using a similar approach to yours: setting those dependencies with compile scope, and removing them from war.
Are you experiencing the same problem?
Regards

J Sherlock

Comment on July 1st, 2010.

Hi Reiner/Graeme.

I ran into difficulty deploying a simple grails app (i.e. grails create-app) on jboss 5/6 yesterday. Reiner, your solution here didn’t work for me as the problem was Hibernate related, not logging. However, Graeme’s solution in this JIRA issue did work… http://jira.codehaus.org/browse/GRAILS-5606. Just adding this here in case anyone else is having similar problems.

Grails version: 1.3.1
Jboss: AS 5 or 6

Now to get it running on Glassfish… uuuugh :(

Cheers, J :)

Leave a comment

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