logo

Grails, Jetty, Glassfish and JNDI Data Sources

logo

Today I’ve moved a bunch of my Grails apps over to JNDI Data Sources, and while it’s fresh in my mind, I thought I’d document a few of the tips and tricks involved.

First of all, why would you even want to use JNDI data sources? A few good reasons:

  • Most importantly, your app server can probably manage your database connections a lot better than you can
  • You don’t have to embed your username/password data in config files, and then end up committing them to public repos (this has led to several password changes for me in the past… the shame!)
  • Developers can call their local databases whatever they want (and they can be whatever type of database server they like) – just map the JNDI reference to whichever server and database floats your boat.
  • Does away with the need to ship db-specific drivers with your app (well.. in theory.. if you’re using Jetty for your DEV work , this may well not be true)

So what changes have I had to make? Just a few tiny ones to DataSource.groovy. Here’s the new one for groovyblogs:

dataSource {
    pooled = false // JNDI, baby. All the way...
}

// environment specific settings
environments {
    development {
        dataSource {
            // check out /web-app/WEB-INF/jetty-env.xml for the details
            dbCreate = "update"
            jndiName = "java:comp/env/jdbc/groovyblogs"
        }
    }
    test {
        dataSource {
            dbCreate = "update"
            url = "jdbc:hsqldb:mem:testDb"
            driverClassName = "org.hsqldb.jdbcDriver"
            username = "sa"
            password = ""
        }
    }
    production {
        dataSource {
            dbCreate = "update"
            jndiName = "jdbc/groovyblogs"
        }
    }
}

First of all, I need to turn pooling off, since the container will now handle all of that for me. But how come the settings are different for DEV and PROD? The answer lies in how containers handle JNDI referencing.

In the DEV example above, I’m running Jetty to do all of my local PC dev work (ie. the standard container that ships with Grails). Embedded Jetty needs to have JNDI references specified using ENC naming (java:comp/env/jdbc/blah), which is resolves against a container specific file to find out the “real” underlying database settings. Enter our friend /web-app/WEB-INF/jetty-env.xml. For groovyblogs, that looks something like:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
     "http://jetty.mortbay.org/configure.dtd">

<Configure class="org.mortbay.jetty.webapp.WebAppContext">

  <New id="domainDb" class="org.mortbay.jetty.plus.naming.Resource">
    <Arg>jdbc/groovyblogs</Arg>
    <Arg>
     <New class="org.postgresql.ds.PGSimpleDataSource">
		<Set name="user">username</Set>
		<Set name="password">password</Set>
		<Set name="databaseName">groovyblogs</Set></New>
    </Arg>
   </New>

</Configure>

As you can see, because of the way the JNDI resource gets resolved in Jetty, I still need to bundle my postgresql driver in /lib. Alas, but I can at least still test things out locally. Notice that in my DataSource I specify things as java:comp/env/jdbc/groovyblogs, but in jetty-env.xml it needs to be jdbc/groovyblogs. You’ve been warned.

But what about production settings? In my case, I’m deploying to glassfish, so I just need to setup my jdbc connection pool and connection under the “Resources” section of the Glassfish Web Admin tool and I’m in business. Gives me a wealth of options for pool sizes, polling of connections and all that good gear – I can even “ping” the database from the admin tool to make sure it’s configured correctly. Most importantly for me, it gives me a single place for my database name, username and password. I can also do away with the ENC indirection, and just reference the JNDI name directly (jdbc/groovyblogs).

Enough JNDI for one day… Time to head off to jConsole and see what I might be able to monitor about the connection pool *while* the app is running…

8 Responses to “Grails, Jetty, Glassfish and JNDI Data Sources”

  1. Hello,

    that’s interesting. But can I deploy a war file with this configuration in a tomcat server?

    Gero

  2. Thanks Glen,

    for sharing your info, very smart solution, exactly fits my needs (GlassFish+PostgreSQL) and can easily be adopted to other deployment scenes (e.g. add serverName to jetty-env.xml in order to access remote servers).

    Regards,
    Reiner

  3. SergeTk says:

    Hi!

    When i follow your instructions i get following exception when trying to run grails with jndi

    java.lang.IllegalStateException: No Constructor: jdbc/data
    testtestdata
    on org.mortbay.jetty.webapp.WebAppContext@1747e0f{/wezi,D:grailsWorkspacewezi/web-app}

  4. Tom Herrick says:

    This is a pretty old post, but it’s the best description I’ve found about getting Grails to work with JNDI for use with Jetty. Unfortunately, I can’t get it to work. My JNDI configuration for the production environment works fine under Tomcat, but when I try to enable JNDI for the test environment (grails test-app), my functional tests blow up complaining with a “javax.naming.NameNotFoundException; remaining name ‘env/myDataSource'”.

    I’ve created a jetty-env.xml file for hsqldb that looks like the following:

    < ?xml version="1.0"?>
    < !DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
         "http://jetty.mortbay.org/configure.dtd">
    
      
        jdbc/myDataSource
    	
    		
    		 org.hsqldb.jdbcDriver
    		 jdbc:hsqldb:mem:devDB
    		 sa
    		 
    		 
    		 
    		   
    			 
    			   
    				 org.enhydra.jdbc.xapool
    			   
    			 
    		   
    		 
    		
    	
       
    
    

    and I’ve changed my DataSource.groovy to include the following:

    	test {
    		dataSource {
    			// see web-app/WEB-INF/jetty-env.xml for JNDI settings 
    			dbCreate = "update"
    			jndiName = "java:comp/env/myDataSource"
    			pooled = false // JNDI provides pooling
    		}
    

    As I’ve floundered around, I’ve also tried adding a section to the generated web.xml, and added enable.jndi=true to BuildConfig.groovy, but I still end up with the same error.

    Any idea what I might be doing wrong?

  5. Glen Smith says:

    @Tom that looks totally fine with me. Very weird.

    As an aside, the Refactor boys have done a more current and detailed write up on this with Tomcat (might be useful since 1.2 has moved to Tomcat for the inprocess web server).

  6. Dmitry says:

    Tom I think you are missing the word”jdbc” in this line:
    jndiName = “java:comp/env/myDataSource”
    it should say:
    jndiName = “java:comp/env/jdbc/myDataSource”
    because you named your JNDI datasource like so: “jdbc/myDataSource”

    Prefixing “jdbc/” to a logical name is done by convention and is not a requirement.

  7. ant says:

    hello,
    when i run app
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘sessionFactory': Cannot resolve reference to bean ‘
    dataSource’ while setting bean property ‘dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean
    with name ‘dataSource': Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name jdbc is not bound in this Cont
    ext

  8. Jetty lover says:

    Very Interesting. It totally work incorrectly for me. I got
    java.lang.IllegalStateException: No Constructor: jdbc/data
    testtestdata
    on org.mortbay.jetty.webapp.WebAppContext@1747e0f{/wezi,D:grailsWorkspacewezi/web-app}
    But other case work correctly In Java side.

logo
logo
Powered by WordPress | Designed by Elegant Themes