Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintaining JNDI across multiple instances of Tomcat

I am wondering how people manage maintaining JNDI resources across multiple instances of their Tomcat Application server. Lets take, for example, my database JNDI resource. It is declared within my /conf/context.xml file and references from my apps web.xml file.

That JNDI resource has to be independently defined on my development box, staging box, and production box. What if I want to set up a new instance of a developer/staging/production box? That means I have to recreate the resource name inside the context.xml for each new instance I bring up? From a setup perspective this is a place where there could be some human error that could cause a app server to start pointing to the wrong DB.

I am finding this to be cumbersome and confusing as I scale up both the number of developers on my project as well as eventually the number of production servers I might use.

Do you just make it part of your setup or create a setup script that deals with this for you every time you re-install tomcat and setup a box? Or is there some other level of indirection that could make this easier?

like image 256
Ish Avatar asked Jul 14 '09 19:07

Ish


People also ask

Does Tomcat supports JNDI?

Tomcat provides a JNDI InitialContext implementation instance for each web application running under it, in a manner that is compatible with those provided by a Java Enterprise Edition application server. The Java EE standard provides a standard set of elements in the /WEB-INF/web.

What is JNDI DataSource in Tomcat?

Actual benefit of DataSource comes when we use it with a JNDI Context. For example, connection pool in a web application deployed in a servlet container. Most of the popular servlet containers provide built-in support for DataSource through Resource configuration and JNDI context.


2 Answers

I'm assuming that for a given resource, you using the same JNDI name in each environment. Otherwise you'd have to edit your code to point to the new resource(JNDI) name.

Setting up the environment the first time can be almost impossible to test ahead of time. There is no way to verify that some string, like the production database connection string, didn't get fat-fingered until you actually have to use it. It's the nature of environment configuration. With that said, if you want to reduce the likely-hood of mistakes, first you need to make sure that each resource is given a name that is used regardless on which environment it is hosted. Create a dbConnectionString resource name in a properties file that points to jndi:/jdbc/myproject/resources/dbConnectionString and make sure all environments declare that same resource. Below is how we kept the code isolated from these types of environmental dependencies. That being said, you will always have to manually verify that the configuration of a specific server is using the appropriate values for the defined resources.

NOTE: never create resource names like "dbProdConnectionString", "dbQAConnectionString", "dbDevConnectionString". You will be defeating the purpose of trying to eliminate manual intervention because then you've added an indirection step that will need a code change (to point the code to the correct resource name) and build (to package the changes into your .war file) when moving between environments.


What we did was create a folder structure for the properties that were environment specific. Under that folder we created folders for each specific environment targeted for deployment, including local development. It looked like this:

Project
\
 -Properties
 \
  -Local (your PC)
  -Dev (shared dev server)
  -Test (pre-production)
  -Prod (Production)

In each folder we put parallel copies of the properties/config files and put the different configurations only in the file in the appropriate folder. The secret was to control the classpath of the deployment environment. We defined a PROPERTIES classpath entry on every server. On Prod, it would be set to "$ProjectDir/Properties/Prod" while on Test the same variable would be set to "$ProjectDir/Properties/Test".

This way we could have database connection strings for the dev/test/prod database preconfigured and not have to checkout/in the property file each time we wanted to build for a different environment.

This also meant that we could deploy the exact same .war/.ear file to Test and Prod without rebuilding. Any properties that weren't declared in the properties file we handled in a similar way by using the same JNDI name in each environment but using values that were specific to that environment.

like image 200
Kelly S. French Avatar answered Nov 13 '22 02:11

Kelly S. French


Are you deploying multiple web applications that must use shared resources?

If not, there's absolutely NO reason to declare your resources in /conf/context.xml. They should instead be declared in a separate, private to your web application context.xml file that will be deployed as /META-INF/context.xml inside your WAR. That file, along with your web.xml should be checked into your source control system and be deployed as part of your build - no manual intervention whatsoever.

If you are deploying multiple web apps with shared resources you can either write a custom resource factory that would expose the same resource to multiple webapps (see Tomcat documentation, at the bottom of the page) and use the above approach or - for development environment at least - you can automatically change (or even replace as default does nothing) /conf/context.xml as part of your build. For production deployment that's not advisable, of course.

like image 42
ChssPly76 Avatar answered Nov 13 '22 03:11

ChssPly76