Adverts

Introduction

This one had me going for ages so I thought I should put up a page about it. Getting connection pooling to work in Tomcat should be easy but it seems it often turns into a complete nightmare resulting in the following error message:

org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot
	create JDBC driver of class '' for connect URL 'null'
at org.apache.tomcat.dbcp.dbcp.BasicDataSource.createDataSource
	(BasicDataSource.java:780)
at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection
	(BasicDataSource.java:540)
	etc etc

My Setup

These instructions probably work for all recent versions of Tomcat (99.9% certain they will work on all 5.x versions and 85% sure for 4.x versions - I am currently using versions 5.0.28 and 5.5.7). I am connecting to a Postgres database but these instructions should pretty much cover configuring a connection to any database.

The Configuration

The generally accepted way of configuring the system is to put one of the following sections into the context.xml file of your webapp (the 5.5.7 configuration doesn't seem to work in 5.0.28 and the 5.0.28 configuration doesn't seem to work in 5.5.7):

Tomcat 5.5.7 Resource Coniguration

<Resource name="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
username="username"
password="password"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://example.com:1234/myDB"
maxWait="1000"
removeAbandoned="true"
maxActive="30"
maxIdle="10"
removeAbandonedTimeout="60"
logAbandoned="true"/>

Tomcat 5.0.28 Resource Coniguration

<Resource
	name="jdbc/postgres"
	auth="Container"
	type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/postgres">
	<parameter>
		<name>factory</name>
		<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
	</parameter>
	<parameter>
		<name>driverClassName</name>
		<value>org.postgresql.Driver</value>
	</parameter>
	<parameter>
		<name>url</name>
		<value>jdbc:postgresql://example.com:1234/sample</value>
	</parameter>
	<parameter>
		<name>username</name>
		<value>username</value>
	</parameter>
	<parameter>
		<name>password</name>
		<value>password</value>
	</parameter>
	<parameter>
		<name>maxActive</name>
		<value>20</value>
	</parameter>
	<parameter>
		<name>maxIdle</name>
		<value>10</value>
	</parameter>
	<parameter>
		<name>maxWait</name>
		<value>-1</value>
	</parameter>
	<parameter>
		<name>removeAbandoned</name>
		<value>true</value>
	</parameter>
	<parameter>
		<name>removeAbandonedTimeout</name>
		<value>300</value>
	</parameter>
	<parameter>
		<name>logAbandoned</name>
		<value>true</value>
	</parameter>
</ResourceParams>

You then aquire the datasource with a section of code like this:

try {
	Context initContext = new InitialContext();
	Context envContext  = (Context)initContext.lookup("java:/comp/env");
	DataSource ds = (DataSource)envContext.lookup("jdbc/postgres");
} catch( NamingException ne ) {
	throw new RuntimeException( "Unable to aquire data source", ne );
}

This works (see note below) if, and only if, you put the configuration parameters in the right file which also has the right name and lives in the right place :o)

Note: The factory name changed in Tomcat 5.5.7 to the value shown in the top example in Tomcat 5.0.28 it is org.apache.commons.dbcp.BasicDataSourceFactory as shown in the bottom example.

I first tried placing the context.xml file in the standard directory where tomcat picks up such files ($TOMCAT_HOME/conf/service_name/host_name) but for some reason this didn't work. I followed the convention of naming the context file the same as the webapp name (in my case ROOT.xml) but to no avail. No matter how I tried it this just didn't seem to work. YMMV of course but I intend to avoid that method from now on.

The solution that I found was placing the resource configuration element (above) in a file called context.xml that lives in the META-INF directory of the webapp and then turing off automatic deployment in the server.xml file. The following is a server.xml that works. It is cut down to the bare minimum though and intended for connection using AJP1.3:

<Server port="8005" shutdown="SHUTDOWN" debug="0">
	<Service name="Catalina">
		<Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
		port="8009" protocol="AJP/1.3"/>
		<Engine name="Tomcat-Engine" defaultHost="www.example.com">
			<Host name="www.example.com" appBase="webapps/example"
			autoDeploy="false">
				<Valve
				className="org.apache.catalina.valves.FastCommonAccessLogValve"
				directory="/var/logs/example"
				prefix="example_log"
				suffix=".log"
				pattern="combined"/>
        	</Host>
		</Engine>
	</Service>
</Server>

A lot of messages I read about solving this problem talk about putting things in the web.xml file. This is not necessary. You also don't need to, and probably shouldn't, include resource-ref elements unless you are placing the resource configuration element in the global resource section of the server.xml file (which is used to make resources available to all contexts).

Adverts

Donate and Help

Please support this site and
Bandwidth doesn't grow on trees y' know :o)

Adverts

Get Adsense