Grails 1.3.6 & JNDI on Tomcat
We’ve been struggling for a couple of days to configure grails to pick up JNDI resources using the embedded tomcat plugin (run-app). After some googling I found an article which solved my problem. At least for now. You will find the link to the article at the end of this post. For completeness, I’ve added a few comments in this blog post + the steps for how to get this working.
Before we start. Some notes about Tomcat and JNDI.
Tomcat support a number of different JNDI resource types (normally configured in Tomcat’s context xml file).
These are:
<Environment>
<Resource>
<ResourceLink>
<Transaction>
On a side note, also Jetty support at least the first three resource types but additional configuration is needed which is beyond the scope of this post.
The <Environment> type is mainly used to configure environmental properties within an application while <Resource> and <ResourceLink> types link to external resources such as JDBC, JMS or LDAP. I won’t elaborate on <Transaction> since I’m unfamiliar with this type.
When it comes to configuring the embedded tomcat plugin (1.2-M2) with JNDI it took a little while to get this right.
If you are only using <Resource> types you won’t have any problems \:) The problem you will encounter is with applications using the <Environment> type. As of version 1.2-M2 the tomcat plugin doesn’t support <Environment> JNDI types. On the other hand, the Jetty plugin support both of them. The very quick solution is to switch to Jetty obviously. Hopefully next version of the tomcat plugin will have better JNDI support. In the meantime we have to fall back on the following hack.
There is an easy way to get the Tomcat plugin to accept other types of JNDI resources and this is what the following article is about [http://6by9.wordpress.com/2010/12/10/grails-1-3-5-tomcat-plugin-and-jndi-environment-variables/]
I’ve also provided the steps here but please read the article before following the steps below.
Do the following:
- Locate the following file TomcatServer.groovy. Mine was located under:C:\Documents and Settings\alejandro.cuesta\.grails\1.3.6\projects\trace\plugins\tomcat-1.3.6\src\groovy\org\grails\tomcat
- Replace the private preStart() method with the following methods
private preStart() {
eventListener?.event("ConfigureTomcat", [tomcat])
def jndiEntries = grailsConfig?.grails?.naming?.entries
if(jndiEntries instanceof Map) {
def envs = jndiEntries.remove('environments')
if (envs instanceof Map) {
envs.each { name, cfg ->
if (cfg) {
addEnvironment(name, cfg)
}
}
}
def ress = jndiEntries.remove('resources')
if (ress instanceof Map) {
ress.each { name, cfg ->
if (cfg) {
addResource(name, cfg)
}
}
}
jndiEntries.each { name, cfg ->
if(cfg) {
addResource(name, cfg)
}
}
}
}
private addEnvironment(name, envCfg) {
if (!envCfg["type"]) {
throw new IllegalArgumentException("Must supply a environment type for JNDI configuration")
}
def env = loadInstance('org.apache.catalina.deploy.ContextEnvironment')
env.name = name
env.type = envCfg.type
env.description = envCfg.description
env.override = envCfg.override as boolean
env.value = envCfg.value
context.namingResources.addEnvironment env
}
private addResource(name, resCfg) {
if (!resCfg["type"]) {
throw new IllegalArgumentException("Must supply a resource type for JNDI configuration")
}
def res = loadInstance('org.apache.catalina.deploy.ContextResource')
res.name = name
res.auth = resCfg.remove("auth")
res.scope = resCfg.remove("scope")
res.type = resCfg.remove("type")
res.description = resCfg.remove("description")
// now it's only the custom properties left in the Map...
resCfg.each {key, value ->
res.setProperty (key, value)
}
context.namingResources.addResource res
}
- The tomcat plugin has now been configured to also read environment resource types
- You should now be able to define your resources in Config.groovy. Such as
grails.naming.entries = [
"resources" : [
"jms/bananas": [
type: "org.apache.activemq.command.ActiveMQTopic",
description: "Fruit salad",
factory: "org.apache.activemq.jndi.JNDIReferenceFactory",
physicalName: "bananas"
]
],
"environments" : [
"/app/config/db.mysql.username": [
type: "java.lang.String",
value: "MYUSERNAME",
override: "true"
],
"/app/config/db.mysql.password": [
type: "java.lang.String",
value: "MYPASSWORD",
override: "true"
]
]
]
Hi Alex!
Thank you so much.
This is exactly what we need!
This is such basic requirement, it weird that the plugin doesn’t support Environments.
Let’s hope they add support soon.
Emilio Trussardi
April 13, 2011 at 11:27 am
You are welcome Emilio!
alexcuesta
April 13, 2011 at 12:30 pm