Java DateFormat: Do use FastDateFormat or clone() to achieve Thread-Safety

Which pattern should you use to cope with DateFormat (and all of its siblings deriving from java.text.Format) not being thread-safe?

TL;DR: Use Apache Commons Lang FastDateFormat (“a fast and thread-safe version of SimpleDateFormat). Use DateFormat.clone() if you can’t use FastDateFormat.

  1. Use synchronized singleton – thread contention!
  2. Always create a new instance – expensive!
  3. Use clone of singleton – does it perform?
  4. Use pre-fabricated pool of instances – cumbersome to use and scale!
  5. Use Apache FastDateFormat –  does it live up to its name?
  6. Your idea here…

7 years ago, Software Monkey’s Tech Site – Cyclic Pool for Shared Objects has done performance tests comparing the first 4, then available, choices. As the title may suggest, pool turned out to be the winner, albeit by a narrow margin.

But as Java VMs get smarter and common hardware now uses more and even more CPUs, the very same performance test now reveals quite a different picture.

And there is a new kid on the block as well: Apache Commons FastDateFormat.

The new winner is: FastDateFormat. It’s really fast and does away with all threading issues as well.

Test run on my MacBook Pro (Early 2011, 4 CPUs, Java 8u144 with G1GC enabled):

2018-04-15 20:35:33.411 : Threads=10, Iterations=1,000,000
2018-04-15 20:36:33.661 : Test 3:
2018-04-15 20:36:43.956 : Sync : 10,295 ms
2018-04-15 20:36:50.186 : Create : 5,161 ms
2018-04-15 20:36:54.327 : Clone : 2,993 ms
2018-04-15 20:36:58.323 : Pool : 2,811 ms
2018-04-15 20:37:01.070 : Fast : 1,618 ms

2018-04-15 20:38:24.188 : Threads=4, Iterations=1,000,000
2018-04-15 20:38:57.665 : Test 3:
2018-04-15 20:39:01.809 : Sync : 4,143 ms
2018-04-15 20:39:05.287 : Create : 2,407 ms
2018-04-15 20:39:07.789 : Clone : 1,349 ms
2018-04-15 20:39:10.366 : Pool : 1,487 ms
2018-04-15 20:39:12.265 : Fast : 806 ms

And if you cannot use FastDateFormat, e.g. your format is not a SimpleDateFormat or uses certain time zone / year patterns: Use DateFormat.clone().

Unfortunately the author of Software Monkey’s Tech Site chose to delete my findings, but here they are:

Thank you for examining the (wildly ignored) clone pattern!

I may have a clue regarding the “why does a single thread test behave that differently?”. Well, Java VMs may be smart enough to account for the situation, that there is just a single runnable thread and none of the blocked threads (i.e. the main thread) own any monitor (i.e. synchronized), thus effectively temporally turning all synchronizeds to nops. This optimization most likely has been implemented for ages, because the semantics of synchronized are VERY expensive and do propagate down to the hardware level: Though synchronized has just a single Object parameter, it enforces a memory barrier on ALL values within the cache of a CPU, resulting in a complete commit of the CPU-local cache to shared main memory.

Another explanation would be the fact, that, when there’s just a single runnable thread, there are no thread switches at all: It just keeps running. Thread switches may be, IMHO ARE expensive (unless the VM uses “green” threads).

I ran your tests on my MacBook Pro (4 CPUs) using Java 8u144 with G1GC enabled (-XX:+UseG1GC):
2018-04-14 22:29:51.431 : Threads=10, Iterations=1,000,000
2018-04-14 22:29:51.432 : Test 1:
2018-04-14 22:30:03.394 : Sync : 11,961 ms
2018-04-14 22:30:10.216 : Create : 5,751 ms
2018-04-14 22:30:14.232 : Clone : 2,931 ms
2018-04-14 22:30:17.982 : Pool : 2,641 ms
2018-04-14 22:30:19.101 : Test 2:
2018-04-14 22:30:29.067 : Sync : 9,966 ms
2018-04-14 22:30:35.078 : Create : 4,939 ms
2018-04-14 22:30:39.092 : Clone : 2,868 ms
2018-04-14 22:30:42.774 : Pool : 2,583 ms
2018-04-14 22:30:43.904 : Test 3:
2018-04-14 22:30:53.328 : Sync : 9,424 ms
2018-04-14 22:30:59.357 : Create : 4,962 ms
2018-04-14 22:31:03.303 : Clone : 2,809 ms
2018-04-14 22:31:06.892 : Pool : 2,382 ms

Well, my MacBook has less power (aka CPUs / Threads). Let’s repeat the tests using MAXTHREADS = number of “real” CPUs (leaving some CPU power to the garbage collector and other background tasks) in order to better resemble an adequate production environment:
2018-04-14 22:33:06.407 : Threads=4, Iterations=1,000,000
2018-04-14 22:33:06.407 : Test 1:
2018-04-14 22:33:12.530 : Sync : 6,121 ms
2018-04-14 22:33:16.345 : Create : 2,708 ms
2018-04-14 22:33:18.713 : Clone : 1,289 ms
2018-04-14 22:33:21.215 : Pool : 1,338 ms
2018-04-14 22:33:22.306 : Test 2:
2018-04-14 22:33:26.217 : Sync : 3,911 ms
2018-04-14 22:33:29.544 : Create : 2,255 ms
2018-04-14 22:33:31.940 : Clone : 1,204 ms
2018-04-14 22:33:34.639 : Pool : 1,604 ms
2018-04-14 22:33:35.707 : Test 3:
2018-04-14 22:33:39.694 : Sync : 3,986 ms
2018-04-14 22:33:43.061 : Create : 2,294 ms
2018-04-14 22:33:45.462 : Clone : 1,226 ms
2018-04-14 22:33:47.902 : Pool : 1,350 ms

Thus, I have no other verdict, than to recommend using clone at large: It’s simple, easily understood, and may turn out to give most favorable results, assuming actual concurrent usage of DateFormat.format does not exceed hardware resources. i.e. number of usable CPUs.

Regards,
Reiner

My sources (Eclipse stand-alone project), with FastDateFormat added, at: DateFormatTest.zip

Always look forward, never look back!

Posted in Carano, Computers, English, Java | Leave a comment

Looking for great Ionic 2 example apps – Ionic 2 Conference Application by Ionic

One of the best ways to learn is from well-done examples. That’s not quite easy, when you’re up to Ionic 2, Angular 2 and TypeScript. These are state-of-the-art technologies, whose final release are imminent within days, but yet to come.

Most of the few apps you’ll find googling for Ionic 2 example either are trivial or they suffer from various defects.

Here is an Ionic 2 example app that immediately shows its mastership, both when sampling its appearance and when inspecting its code. This does not come as a surprise, as its creators are indeed the masters of Ionic themselves. What most impresses me, is that it works out-of-the box as a web site. Little remains to be done to turn it into a true Progressive Web App.

This is not a “real” app. Its contents are fictitious, there is no backend and it’s a work in progress. It just shows how to build a well designed Ionic 2 application.

You’ll find the sources and docs at https://github.com/driftyco/ionic-conference-app. Do poke around this repo to find many other Ionic 2 examples.

Have a sneak peek at what it looks like at https://service.saddey.net/ionic-conference-app/index.html (master branch as of 20-aug-16).

Posted in Angular.js, Computers, English, Ionic | 1 Comment

Using Docker to create Ionic 2 PWA developer environment

I want to create a simple Progressive Web Application (PWA) user registration dialog, which runs on mobile devices, accepts user data and saves them to some backend.

I chose Ionic 2 (ignoring its capabilities to create native apps), because it’s based on Angular 2. It’s like sliced bread. And it uses TypeScript as its (preferred) language. If you’re new to Angular  (as I am), head over to Code School’s Accellerating through Angular 2.

Before installing Ionic 2, you’ll need Node.js because it’s required by Ionic 2.

Node.js

Refusing to infect my MacBook with all sorts of beginner’s (and beta) garbage, I chose to confine my developer environment within a Docker container, avoiding both homebrew and the irreversible native installer as well.

This will give you a virtual environment to take with you, hand over to colleagues, or even publish for anyone to start using within a couple of minutes.

Continue reading

Posted in Angular.js, Computers, Docker, English, Ionic, Mac OS X | 8 Comments

OS X: Why takes Panic’s Transmit so much longer to transfer a text file via SFTP than Cyberduck? Compression!

I do love Transmit for its smart Finder integration, e.g. mounting remote hosts as “disks” within Finder or quickly opening connections saved as droplets directly from Spotlight.

But… I was quite shocked to find it takes Transmit 10 times longer than Cyberduck to transfer text files when using SFTP – 2 minutes instead of 12 seconds for a 20+ MB server.log via a 2 Mbit line (I know it’s slow, it’s not mine…) 😡

Why? Compression?

It took some time of fiddling to uncover Transmit uses OS X standard ssh configuration settings as defined within ~/.ssh/config or /etc/ssh/ssh_config.

Thus I created ~/.ssh/config containing

Host *
Compression yes
CompressionLevel 9

et voilà, Transmit now compresses files on-the-fly as well 😀

Posted in Apple, Mac OS X | Leave a comment

How to restore an EBS based Amazon EC2 Windows instance from a snapshot

This mail showed up this afternoon within my inbox:

Dear REINER SADDEY,

Your volume experienced a failure due to multiple failures of the underlying hardware components and we were unable to recover it.
Although EBS volumes are designed for reliability, backed by multiple physical drives, we are still exposed to durability risks caused by concurrent hardware failures of multiple components, before our systems are able to restore the redundancy. We publish our durability expectations on the EBS detail page here (http://aws.amazon.com/ebs).
Sincerely,
EBS Support

While it might raise your pulse, it didn’t raise mine: It’s now been just two weeks after having set up an Amazon EC2 instance – for the very first time in my life and mainly just for wetting my feet.  72 instance hours in total.

I thus considered the failure both an important warning and a welcome opportunity to practice how to restore an EBS based EC2 instance.

Starting to google for this particular task, I soon suspected it to be a c(o)urse of frustration: From next-to-impossible to contradicting statements and stories (you must create an Ami, no, you have to launch a new instance, this only works for Linux, a.s.o.), anything can be found, but no definite, convincing and authoritative recipe for restoring a Windows EC2 instance from a snapshot.

After having made up my mind to abandon further outside help, I chose to proceed exactly as I would like a restore to be performed in the first place. This is what worked for me targeting a single volume (boot-only) instance:

  1. Detached the failing volume from the EC2 instance
  2. Deleted the failing volume
  3. Created a new volume (within the same availability zone as my EC2 instance) from my snapshot
  4. Attached this volume to the EC2 instance using device name /dev/sda1
  5. Started the instance
  6. Retrieved my Administrator password (the cryptic one, must have changed it after taking the snapshot)

After having logged-in using RDP, I found all and everything exactly the same as at the time the snapshot was taken 🙂

Posted in at other Locations, Computers, English | Tagged , , | 3 Comments

Grails and Microsoft SQL Server – Not so painless when using Unique Constraints – A Pragmatic Work-Around

When porting your Grails application from just about any database to MS SQL Server, four areas come to my mind that require your immediate attention:

  • Primary key generation strategy (not covered here)
  • Case sensitivity and collation issues (not covered here)
  • Storage and retrieval of Unicode data (not covered here)
  • Handling of unique constraints on columns that allow nulls

With MS SQL Server you’ll notice your unique constraints defined within Grails domain classes may no longer work as expected if null values are allowed (either explicitly or when using table per hierarchy inheritance).

Today I’ll present a work-around for MS SQL Server 2008 that does not require any manual intervention.

When using unique clauses within the constraints sections of your domain classes, Grails will do both:

  • Perform lookups on every insert or update in order to be able to create meaningful messages within the errors collection, and
  • by virtue of Hibernate hbm2ddl, create unique constraints within your database to enforce uniqueness even when validation is bypassed.

What’s so special about MS SQL Server?

Microsoft SQL Server has always been special when it comes to null values. There are several options (suspiciously named ANSI_xxx) controlling the handling of null values, e.g. whether null = null yields true a.s.o., but all those fail to take any effect on unique constraints.

With Microsoft SQL Server unique constraints treat null values just as if they were ordinary values – a uniquely constrained column does at most allow for a single row to have the value null. This appears to be in violation of ANSI SQL standards and there are (as yet futile) requests to (optionally) alter MS SQL Server behavior.

Depending on your business rules, not-null properties (e.g. nullable:false, blank:false, unique:true) may be appropriate. But watch out for object inheritance when using table-per-hierarchy mapping (Grails default). As a single table is used to store different kinds of objects, a property defined as nullable:false within a sub class must be mapped to a nullable table column as other sub classes do not share this property (i.e. they have no value for this particular column at all). And if such a property has been constrained by unique:true, your application is bound to fail with SQL Server, as it will at most allow a single row where the value of this property is null.

There are several work-arounds in the wild, most of them exceedingly awkward to handle and maintain – with one notable exception: Starting with MS SQL Server 2008 indexes can be filtered, i.e. a (simple) where clause can be applied to the definition of an index. Thus a unique index that ignores null values can be used in place of a unique constraint to enforce uniqueness of non-null values.

What you’ll need to run or use the Grails MsSqlConstraints project sample code

  • The Grails demo project MsSqlConstraints.zip.
  • MS SQL Server 2008 (express edition will do, I used 2008 R2) allowing SQL Server authentication (i.e. user and password). The demo project accesses a database named demo at your local SQL Server using demo for both login and password. Best to have a look at DataSource.groovy first.
  • Grails 1.3.7
  • Java 6 – Java 6 Update 29 has a bug that prevents it to connect to MS SQL Server 2008 R2. Either upgrade to Java 6 Update 30 or replace jsse.jar with the one included in Update 30 (as I had to because Update 30 was not yet available from Apple).
  • Springsource Tool Suite 2.8+ or IntelliJ 10+ (not really required, but allow attached demo project to be run out-of-the-box).
  • Disclaimer: Note that the demo project is provided as is without any warranty or obligation and (to give you a head start) as well includes a copy of the Microsoft JDBC Type 4 Driver Version 3 which is to be used with this demo project only and whose use is restricted as explained in MICROSOFT SQL SERVER JDBC DRIVER REDISTRIBUTION LICENSE.

How to change unique constraints to unique indexes?

Alter database DDL within BootStrap.groovy

  • Having looked into Hibernate 3.3.1 code (as used by Grails 1.3.7) it appears hard if not impossible to change the DDL generated by Hibernate’s hbm2ddl routines. Thus I resorted to altering table definitions within the BootStrap.groovy code. Please note that the code has been hacked away in a hurry and might fail with advanced usage patterns such as tables belonging to different owners a.s.o. For us it worked out-of-the-box, but use at your own risk.
  • The code within BootStrap.groovy is straight forward. It queries constraint data from MS SQL Server information schema and replaces unique constraints that encompass nullable columns with unique filtered indexes.

Supply Hibernate dialect for MS SQL Server 2008

  • When a unique index violation occurs, an Exception different from the one when violating a unique constraint will be thrown. MinimalSQLServer2008Dialect contains code to map unique index violations to DataIntegrityViolationExceptions just as if a constraint violation had occurred.
  • The demo project has been implemented using Microsoft JDBC Type 4 Driver for SQL Server. This driver returns JDBC type codes (e.g. NVARCHAR for certain information schema columns) Hibernate 3.3 fails to understand. Thus the MinimalSQLServer2008Dialect supplied with this demo project as well provides minimal type declarations in order to successfully query SQL Server information schemas. Another post within this blog will focus on both how to store Unicode strings and how to take advantage of MS SQL Server BIT and xxx(MAX) columns using an enhanced Hibernate dialect.
  • The code referenced from DataSource.groovy is contained within class demo.MinimalSQLServer2008Dialect which derives from org.hibernate.dialect.SQLServerDialect. It defines NCHAR and NVARCHAR data types and translates unique index violations to (Spring) ConstraintViolationExceptions.

How to run the code?

Have fun,
Reiner

Posted in English, Grails, Hibernate | 1 Comment

Episodes from the Life of a Mac Convert – How to install Apache?

Yes, I shout it out to all my fellow brothers – after having led a sinful life of Windows miseries, I now have become a true and humble Apple believer 🙂

I wanted to install a web server on my Snow Leopard MacBook Pro in order to hand out some documents and thus ventured into googling for mac install apache. I was quite dissatisfied most articles appeared to be rather involved, requiring to either install by source or mandating other system wide packages to be fetched.

It was no sooner than half an hour I discovered that all that was required is just a single tick within a System Preferences Panel:

  1. Open Sharing from System Preferences
  2. Tick Web Sharing

Apache is included off-the-shelf and started immediately after Web Sharing has been enabled 🙂

MacMost has a video that includes PHP as well:

Posted in English, Mac OS X | Leave a comment

Mac OS X (Snow Leopard): 1-2-3 Minimal Tomcat Install for Developers

This will install Tomcat for developer use – i.e. within your user home path, using your login, not as a service:

  1. Get the tar.gz for Tomcat Core from Apache Tomcat
  2. Change to your private Library: cd ~/Library
  3. Unpack Tomcat, e.g. tar xvfz ~/Downloads/apache-tomcat-6.0.32.tar.gz
  4. Create symbolic link to remain stable even when upgrading: ln -s apache-tomcat-6.0.32 Tomcat

Then:

  • Start Tomcat: ~/Library/Tomcat/bin/startup.sh
  • Stop Tomcat: ~/Library/Tomcat/bin/shutdown.sh

Configure at your leasure, e.g. look here for enabling Tomcat Manager Login: http://www.mkyong.com/tomcat/tomcat-default-administrator-password/

Posted in Java, Mac OS X | Leave a comment

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:

Posted in English, Grails | Leave a comment

How to Deploy a Grails Application to JBoss 5

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:

Posted in English, Grails | 7 Comments