Configure JNDI Datasource in Tomcat

Datetime:2016-08-23 03:53:04          Topic: DataBase  Tomcat           Share

Almost all web applications need to access a database. So we need to be aware what the best practices are in order to configure these databases efficiently. A database connection is expensive to make, that is why most of the servlet containers provide built-in support for connection pooling. We can leverage this connection pooling in tomcat by registering the datasource via the JNDI context. In this tutorial we explain how to configure a datasource in tomcat and how to obtain an instance of this datasource via JNDI.

Prerequisites

We are configuring a MySQL database. This example assumes you’ve already created a database and installed the driver. If you haven’t installed the driver, download the MySQL driver and add the driver in the $TOMCAT_HOME/lib folder.

Configure Datasource in tomcat – server.xml

Add the following Resource element to the GlobalNamingResource element inside the $TOMCAT_HOME/conf/server.xml file. Here we are creating a Resource of type javax.sql.DataSource with a JNDI name of jdbc/DatabaseName . As we are using MySQL database, we provide the com.mysql.jdbc.Driver driver class. Note that if you are using a different database, you should change the url and driverClassName accordingly. The other properties are used to configure the connection pool for our DataSource .

<Server>
  
	... 
  
	<GlobalNamingResources>
			  
		<Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
                          username="user" password="password"
                          url="jdbc:mysql://localhost:3306/DB_USERS"
                          driverClassName="com.mysql.jdbc.Driver"
                          initialSize="5" maxWait="5000"
                          maxActive="120" maxIdle="5"
                          validationQuery="select 1"
                          poolPreparedStatements="true"/>
			  
	</GlobalNamingResources>

	...
</Server>

Configure ResourceLink – context.xml

Next, we add the ResourceLink element to the Context element inside the $TOMCAT_HOME/conf/context.xml . This will create a linked resource to the global JNDI resource. Note that the name differs from the global JNDI resource. We should use the name of the resource link in our application.

<Context>
		
	...
		
	<ResourceLink name="jdbc/LocalDatabaseName"
                      global="jdbc/DatabaseName"
                      type="javax.sql.DataSource"/>
	
</Context>

At this point you have successfully configured a datasource in tomcat. When you run tomcat, the data source should be available under the JNDI name: jdbc/LocalDatabaseName .

Define preconfigured JNDI Datasource – web.xml

Then, we register the ResourceLink JNDI name – under which the application will look up the preconfigured data source – inside the /WEB-INF/web.xml servlet descriptor of our application. I noticed this isn’t mandatory, but it helps to inform your colleagues of which data sources are available.

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
		                     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

    <!-- preconfigured jndi datasource-->
    <resource-ref>
        <res-ref-name>jdbc/EmployeeDB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

</web-app>

DataSource Lookup via JNDI

Now that our data-source is configured, we can look up the datasource via JNDI. First, we create an instance of the InitialContext . Then look up the context using the standard "java:comp/env" JNDI name. Finally, we look up the DataSource via the "jdbc/LocalDatabaseName" JNDI name.

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource dataSource = (DataSource) envCtx.lookup("jdbc/LocalDatabaseName");

We can also immediately look up the DataSource via the "java:/comp/env/jdbc/LocalDatabaseName" JNDI name.

Context initCtx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup("java:/comp/env/jdbc/LocalDatabaseName");

We can also obtain an instance of the DataSource by injecting it via the @Resource annotation in a servlet environment.

@Resource(name="jdbc/LocalDatabaseName")
private DataSource dataSource;

Example Servlet JNDI DataSource lookup via @Resource

Finally, we show you a simple example how to obtain a reference of the DataSource instance in a servlet environment. This example assumes that we configured a DataSource under the jdbc/LocalDatabaseName JNDI name. We also created a tbl_users table and inserted a couple of dummy records.

package com.memorynotfound.jndi;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.sql.DataSource;
import java.io.*;
import java.sql.*;

@WebServlet(urlPatterns = "/*")
public class WelcomeServlet extends HttpServlet {

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

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Statement stmt = null;
        ResultSet rs = null;
        try {
            Connection con = ds.getConnection();
            stmt = con.createStatement();

            rs = stmt.executeQuery("select id, name, email from tbl_users");

            PrintWriter out = resp.getWriter();
            resp.setContentType("text/html");
            out.write("<html>");
            out.write("<body>");

            out.write("<h3>Database Records</h3>");
            while(rs.next())  {
                out.write("id: " + rs.getInt("id") + " ");
                out.write("name: " + rs.getString("name") + " ");
                out.write("email: " + rs.getString("email") + " ");
                out.write("</br>");
            }

            //lets print some DB information
            out.write("<h3>Database Meta Data</h3>");
            DatabaseMetaData metaData = con.getMetaData();
            out.write("Database Product: " + metaData.getDatabaseProductName() + "<br/>");
            out.write("Database Version: " + metaData.getDatabaseMajorVersion() + "."
                    + metaData.getDatabaseMinorVersion() + "<br/>");
            out.write("Database Driver: " + metaData.getDriverName() + "<br/>");
            out.write("Database Driver version: " + metaData.getDriverMajorVersion() + "."
                    + metaData.getDriverMinorVersion() + "<br/>");
            out.write("Database user: " + metaData.getUserName());
            out.write("</html>");

        } catch (SQLException e) {
            e.printStackTrace();
        } finally{
            try {
                if (rs != null) {
                    rs.close();
                }
                if (stmt != null) {
                    stmt.close();
                }
            } catch (SQLException e) {
                System.out.println("Exception in closing DB resources");
            }
        }
    }
}

Demo

URL: http://localhost:8080/jndi/

References

Download





About List