Data Source Handling with Tomcat 7.0

The “new” J2EE6 standard allows for setting up of datasources in the web.xml of a web application. If the webserver is compliant- this feature will enable defining your database resources in the web.xml like the example below.

web.xml config

  MySQL Datasource example
  jdbc/mkyongdb
  javax.sql.DataSource
  Container

Thanks to resource injection, the following code is used to obtain the data source, which can be used as per normal.

resource injection

import javax.annotation.Resource;
public class CustomerBean{

    @Resource(name="jdbc/mkyongdb")
    private DataSource ds;

    public List getCustomerList() throws SQLException{

      //get database connection
      Connection con = ds.getConnection();
      //...

What is great about resource injection, is that at class instantiation (e.g. beans / servlets / filters / etc), the J2EE server will pick up that you want to use a connection that it manages. It will then “inject” one of its free resources for you into the place you have marked in your code (the @Resource annotation). After which the instantiation of the class will complete. This means that you do not need to do any lookups or know of your famous “InitialContext” to obtain a database connection.

The above is the recommended way to do this- according to the Tomcat documentation. I find this to be great if you are developer focused environment, where developers have access to every system and have access to all passwords in all environments.

In short, this way of doing things is very developer focused:

  • Benefit: Everything is managed in one project by the developers in one location.
  • Negative: The developer / build needs to change the database config (web.xml) between environments.
  • Negative: The developer needs to know about all database details and credentials.

Better alternative

NOTE: This is Tomcat 7.0 specific.

Instead of defining the data source in the web.xml, setup the data source in the context.xml file, which is located in the “conf\” directory of the tomcat server. The connection is inherited into the web.xml as if it was defined there. Thus the developer only need know of the data sources on the server by name.

The reason for editing the config.xml file and not the server.xml file (both equally viable ways to achieve this), is that editing the server.xml file requires a server restart- whilst the config.xml file is auto reloaded and does not require the restart.

config.xml config

...


    
    WEB-INF/web.xml

...

This way of doing things shifts the work off to the sysadmin (if you have one) and allows for the developer to be completely agnostic of the environment that his code is running on. This way, the databases that are used can be changed without the developer ever knowing that this happened. Additionally it means that the developer will not gain the credentials for sensitive environments like production.

In short, this way is more suited for enterprise (with the separation of concerns):

  • Benefit: Moves data source configuration to the sysadmins.
  • Benefit: Hides environment details from developers- making things more generic as well as secure.
  • Benefit: Database and driver management is moved to the server and the client need not care about the driver or database used.
  • Benefit: No need to change config between environments in the build.
  • Negative: Moves the config from the developer project to the server, thus splitting the deploy configuration.

Gotcha

The annotation variant works in servlets with context, otherwise context has to be collected manually

import javax.naming.Context;
import javax.naming.InitialContext;
public class CustomerBean{

	private DataSource ds;

	public CustomerBean(){
	  try {
		Context ctx = new InitialContext();
		ds = (DataSource)ctx.lookup("java:comp/env/jdbc/mkyongdb");
	  } catch (NamingException e) {
		e.printStackTrace();
	  }
	}

	public List getCustomerList() throws SQLException{

	  //get database connection
	  Connection con = ds.getConnection();
	  //...