Tomcat DataSource JNDI Example in Java

Filed Under: Database

Welcome to Tomcat DataSource JNDI Example Tutorial. We looked at the JDBC DataSource in the last tutorial and learned how to use that in standalone java application.

Tomcat DataSource JNDI

tomcat datasource, jndi example, tomcat jndi, jndi tutorial
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. This helps us in creating and using DataSource connection pool with just few lines of configuration. This tutorial is aimed to provide Tomcat DataSource JNDI configuration example.

Apache Tomcat provide three ways to configure DataSource in JNDI context.

  1. Application context.xml – This is the easiest way to configure DataSource, all we need is a context.xml file in META-INF directory. We have to define Resource element in the context file and container will take care of loading and configuring it. The approach is simple but it has some drawbacks;
    • Since the context file is bundled with the WAR file, we need to build and deploy new WAR for every small configuration change. Same issue comes if your application works in distributed environment or your application needs to be deployed in different testing environments such as QA, IT, PROD etc.
    • The datasource is created by container for the application usage only, so it can’t be used globally. We can’t share the datasource across multiple applications.
    • If there is a global datasource (server.xml) defined with same name, the application datasource is ignored.
  2. Server context.xml – If there are multiple applications in the server and you want to share DataSource across them, we can define that in the server context.xml file. This file is located in apache-tomcat/conf directory. The scope of server context.xml file is application, so if you define a DataSource connection pool of 100 connections and there are 20 applications then the datasource will be created for each of the application. This will result in 2000 connections that will obviously consume all the database server resources and hurt application performance.
  3. server.xml and context.xml – We can define DataSource at global level by defining them in the server.xml GlobalNamingResources element. If we use this approach, then we need to define a ResourceLink from context.xml file of server or application specific. This is the preferred way when you are looking to share a common resource pool across multiple applications running on the server. Regarding resource link, whether to define it at server level context xml file or application level depends on your requirement.

Let’s head over to the Tomcat DataSource JNDI example in java web application.

For the test data setup, please refer to my last article about JDBC DataSource Example.

Tomcat DataSource JNDI Configuration Example – server.xml

Add below code in the tomcat server.xml file. The code should be added in the GlobalNamingResources element. Also make sure that database driver is present in the tomcat lib directory, so in this case mysql jdbc jar have to be present in the tomcat lib.


<Resource name="jdbc/MyDB" 
      global="jdbc/MyDB" 
      auth="Container" 
      type="javax.sql.DataSource" 
      driverClassName="com.mysql.jdbc.Driver" 
      url="jdbc:mysql://localhost:3306/UserDB" 
      username="pankaj" 
      password="pankaj123" 
      
      maxActive="100" 
      maxIdle="20" 
      minIdle="5" 
      maxWait="10000"/>

Here we are creating JNDI context with name as jdbc/MyDB which is a type of DataSource. We are passing database configurations in url, username, password and driverClassName attribute. Connection pooling properties are defined in maxActive, maxIdle and minIdle attributes.

Tomcat DataSource JNDI Resource Link Configuration – context.xml

Add below code in the server context.xml file.


<ResourceLink name="jdbc/MyLocalDB"
                global="jdbc/MyDB"
                auth="Container"
                type="javax.sql.DataSource" />

Notice that resource link name is different than global link, we have to use this name in our java program to get the DataSource.

Tomcat DataSource JNDI Example

Create a dynamic web application with name JDBCDataSourceTomcat and then create a Servlet with below code.


package com.journaldev.jdbc.datasource;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/JDBCDataSourceExample")
public class JDBCDataSourceExample extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Context ctx = null;
		Connection con = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			ctx = new InitialContext();
			DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
			
			con = ds.getConnection();
			stmt = con.createStatement();
			
			rs = stmt.executeQuery("select empid, name from Employee");
			
			PrintWriter out = response.getWriter();
            response.setContentType("text/html");
            out.print("<html><body><h2>Employee Details</h2>");
            out.print("<table border=\"1\" cellspacing=10 cellpadding=5>");
            out.print("<th>Employee ID</th>");
            out.print("<th>Employee Name</th>");
            
            while(rs.next())
            {
                out.print("<tr>");
                out.print("<td>" + rs.getInt("empid") + "</td>");
                out.print("<td>" + rs.getString("name") + "</td>");
                out.print("</tr>");
            }
            out.print("</table></body><br/>");
            
            //lets print some DB information
            out.print("<h3>Database Details</h3>");
            out.print("Database Product: "+con.getMetaData().getDatabaseProductName()+"<br/>");
            out.print("Database Driver: "+con.getMetaData().getDriverName());
            out.print("</html>");
            
		}catch(NamingException e){
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			try {
				rs.close();
				stmt.close();
				con.close();
				ctx.close();
			} catch (SQLException e) {
				System.out.println("Exception in closing DB resources");
			} catch (NamingException e) {
				System.out.println("Exception in closing Context");
			}
			
		}
	}

}

Notice that I am using Servlet 3 Annotation based configuration and it will work in Tomcat 7 or higher versions. If you are using lower version of Tomcat then you need to do some modifications to the servlet code, to remove WebServlet annotation and configure in web.xml file.

The part of servlet code that we are interested in;


ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");

This is the way to get the JNDI resources defined to be used by the application. We could have written it in this way too;


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

I am also printing some database information to check which database we are connected.

Now when you will run the application, you will see following output.

Tomcat DataSource JNDI Example MySQL, JNDI DataSource MySQL

Let’s see how easy it is to switch the database server because we are using Tomcat DataSource. All you need is to change the Database properties. So if we have to switch to Oracle database, my Resource configuration will look like below.


<Resource name="jdbc/MyDB" 
      global="jdbc/MyDB" 
      auth="Container" 
      type="javax.sql.DataSource" 
      driverClassName="oracle.jdbc.driver.OracleDriver" 
      url="jdbc:oracle:thin:@localhost:1521:orcl" 
      username="hr" 
      password="oracle" 
      
      maxActive="100" 
      maxIdle="20" 
      minIdle="5" 
      maxWait="10000"/>

And when we restart the server and run the application, it will connect to Oracle database and produce below result.

Tomcat DataSource JNDI Example Oracle

That’s all for Tomcat DataSource JNDI configuration example tutorial, you can define the resource in similar way in context.xml files too.

Comments

  1. Ramesh says:

    Good information. Thank you very much.

  2. Pran Sukh says:

    I don’t see any error or exception in your point
    ” If there is a global datasource (server.xml) defined with same name, the application datasource is ignored. ”
    I tried everything to let this happen….. but nothing happens, i need to raise this issue, why it is not ignoring the application context.xml Datasource when there is Global DataSource in server.xml with same name.

  3. Debaranjan Ghosh says:

    while running this getting following error type Status report

    message /JDBCDataSourceExample/

    description The requested resource is not available.

    1. Pran Sukh says:

      JDBCDataSourceExample may be your project name but you need to call your servlet class, just put /ServletClassName. Your URL will be like
      http://localhost:8080/JDBCDataSourceExample/ServletClassName

      My project name is RestWithJerrsy and ServletDataSource is servlet class, so the perfect URL is.

      http://localhost:8080/RestWithJerrsy/ServletDataSource

  4. rahul kumar says:

    nice post , each and every thing is define clearly actually i configure in context.xml due to this in my webapp there are 6 folder so it create 6 times connection . i give initialsize 10 so it create 60 connection 10 for each application . but when i conigure in server.xm it work fine and create 10 connection .
    tanks for this post.

  5. Fazeela says:

    Nice article.

  6. Alberto says:

    Dear Mr. JournalDev,
    Congrats for your job.
    I have a web application with a connection pool defined in server.xml of the server ($CATALINA_HOME/server.xml). I can use this connection pool for JPA connections but I cannot open connection from this pool directly using the context and the lookup of the context. I have tried using ResourceLinks on context.xml of the application which pointed to the dataSource globally defined but it does not work. I have created another connection pool in the context.xml application file and it works, but it is not so efficient. The question is: it is possible to use the global Data Source defined on server.xml of the web application server for connecting database trough the Web Application? Thanks in advance,
    Alberto.

    1. Pankaj says:

      Yes, that is the topic of this tutorial. The datasource is defined in Tomcat server.xml file and our web application is using that.

  7. Sandeep says:

    Hi,

    what is difference between Resourceand ResourceLink in context.xml and server.xml why you have used java:/comp/env/jdbc/MyLocalDB to get DataSource why not jdbc/MyDB. Please let me know as i am begineer

    1. Pran Sukh says:

      Me too….. Please answer.

  8. Sandeep says:

    Hi Pankaj,

    what is difference between these two configurations why you are using java:/comp/env/jdbc/MyLocalDB why can’t be this java:/comp/env/jdbc/MyDB
    to get the DataSource

  9. Santhoshkumar says:

    Hey Everyone,

    I need some help.
    “java:/comp/env” without providing this how to read JNDI configuration in Tomcat Server. My application is working in Jettty server without any issues, but while migrating to Tomcat i am facing JNDI issues. if i am adding JNDI Prefix it is working fine. I have to change entire application. Without any changes in my application how to resolve this issue.

    1. Sandy says:

      you con’t bro….

  10. Lavanya says:

    what is happening in the following code. please tell me the flow of the program, please let me know what is the difference between test0001 and test003. is resource leak happening in this code ???

    package data;

    import javax.naming.InitialContext;
    import javax.naming.NamingException;

    public class Sample{

    public static void test000(){
    try {
    InitialContext ctx = new InitialContext(); // jtest is able to find a resource leak here.
    } catch (NamingException e) {
    e.printStackTrace();
    }
    }

    public void test001(){
    try {

    InitialContext ctx = new InitialContext();
    call001(ctx);
    } catch (NamingException e) {
    e.printStackTrace();
    }
    }

    public void call001(InitialContext ctx){
    // do nothing.
    }

    public void test002(){
    try{
    InitialContext ctx = new InitialContext();
    call002(ctx);
    }catch(NamingException e){
    e.printStackTrace();
    }
    }

    private boolean isTrue = false;

    public void call002(InitialContext ctx){

    if(this.isTrue){
    try{
    ctx.close();
    }catch(NamingException e){
    e.printStackTrace();
    }
    }
    }

    }

    Thanks in advance 🙂

    1. Pankaj says:

      Well its a long program, but it’s clear that you are not closing InitialContext object so resource leak is happening. In case of test000 method, it’s clear and since there are no close() call even in any if-else condition, so jtest is able to find it easily. In call002() method, if condition is used and you can set isTrue to “true” from some other code to close the context.

      1. Lavanya says:

        thank you for your response.

        is resource leak happening in test001 method???

        Thanks for ur time.

  11. Sagar says:

    Fantastic useful stuff.Thanks bro:)

  12. Atelo says:

    Hi, Great article, very helpful….
    But I have a doubt, which is a difference beetween:

    java:comp/env/jdbc/name_ds
    java:/comp/env/jdbc/name_ds
    java:jdbc/name_ds
    java:/jdbc/name_ds

    where can I setup the way to call the jndi? I have this problem, in my pc an example works with “java:/comp/env/jdbc/name_ds”, the same example in the my friend computer doesn’t work, we changed to “java:/jdbc/name_ds” to work.

    We don’t know what is the reason…

    Anybody can help us?

    Thanks

  13. Dmitry says:

    Hello,
    I have an error when I run this example.
    org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class ” for connect URL ‘null’.
    I can’t find any solution in google 🙁
    Pls help me.

  14. Yatin says:

    Hi All,
    I have following configuration..

    — main-context.xml

    –DataSource.xml

    WEB-INF/database.properties

    <!–

    –>
    Instead of above definition I have used following definition

    –database.properties

    jdbc.jndiName=java:comp/env/jdbc/MYAPPDB

    –server.xml

    I have encrypted datasource password using BASE64Encoder

    Here is my EncryptedDataSource class for decrypting password which extends JndiObjectFactoryBean

    package my.app.util;

    import java.io.IOException;

    import javax.naming.NamingException;

    import org.apache.commons.configuration.JNDIConfiguration;
    import org.springframework.jndi.JndiObjectFactoryBean;

    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;

    public class EncryptedDataSource extends JndiObjectFactoryBean{

    /*@Override
    public String getPassword() {
    String password = super.getPassword();
    password = decode(password);
    return password;
    }*/

    private String decode(String decode) {
    BASE64Decoder decoder = new BASE64Decoder();
    try {
    decode = new String(decoder.decodeBuffer(decode));
    } catch (IOException e) {
    e.printStackTrace();
    }
    return decode;
    }

    private String encode(String encode) throws IOException {
    BASE64Encoder encoder = new BASE64Encoder();
    encode = new String(encoder.encodeBuffer(encode.getBytes()));
    return encode;
    }

    public static void main(String[] args) throws IllegalArgumentException, NamingException {

    EncryptedDataSource ed = new EncryptedDataSource();

    try {
    String password = ed.encode(“password”);
    System.out.println(“password = “+password);
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    }
    I want to decrypt while connection pooling. Please help.

  15. Kamil says:

    Great article, very helpful. Thanks!

  16. Sam says:

    This is my first time i’m commenting on the web, because it really works and the article is really great.

  17. Jeevitha says:

    Sir,I would like to know about my project . regarding the connection of servlet code to telegram web for bus booking through online

  18. Jorge de Lemos says:

    THANK YOU SO MUCH for this post, I had problems to understand this JNDI stuff, I didn’t know anything about JNDI and know everything is clear!

    Thanks Pankaj 🙂

  19. Punnoose says:

    Nice article. Thank You.

  20. Pavan says:

    nice post.Very helpful

  21. Ali Saleh says:

    Thank you Pankaj for this useful article,
    But I wold like to add regarding Eclipse
    Don’t forget that the Tomcat files will be under the “Server” in the eclipse project hierarchy so modifying them in tomcat alone will not help

    thank you again

  22. Oleg says:

    Thank for great tutorials.
    I have problem with this one. It doesn’t show me table, it just show message “TODO write content”. What can be wrong?

  23. Ju says:

    Thanks a lot for this really clear example.

  24. pradeep says:

    Thanks for the post. I read a lot of blogs, and everywhere I saw only the configuration in Server.xml file. I was trying to following the same thing but it never worked, after looking at your explanation, I added the elements in Context.xml and it worked like a charm. Thanks again, brother.

  25. irshad says:

    I have put in server context.xml. but i have put following tag in the web.xml

    DB Connection
    jdbc/MoranDB
    javax.sql.DataSource
    Container

    ==============
    i am able to use the Datasource connection. But i want to know the difference between using
    (server.xml and context.xml) and as i do(context.xml of server and web.xml of application).
    PS: i am using tomcat-7 and Mysql database.
    please give you insight. thank you

    1. irshad says:

      DB Connection
      jdbc/MoranDB
      javax.sql.DataSource
      Container

  26. lalit says:

    i do not understand this sir plz explain where it is …”java:/comp/env/jdbc/MyLocalDB”

    1. Denn says:

      Seems it’s typo. Use jdbc/MyDB instead

  27. Venkata Sriram says:

    Hi sir,i created a datasource in Server.xml and writing resourcelink in context.xml but it is not considering second Database Connection Details sir.

    in Server.xml under GlobalNamingResources tag i wrote 2 Resource tags for 2 different db connections

    and in Context.xml i wrote 2 ResourceLink for those 2 different db connections,

    First Connection is working where as second one is not working sir.

  28. Anshul Jain says:

    THanks for the post, but

    I am getting Error: Java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to sun.jdbc.odbc.ee.DataSource

    can you please help

    1. Oleg says:

      Wrong import lib

  29. Zulifqar says:

    Excellent post………………Could you please explain how you get this ” java:/comp/env”…. Sorry I am kind of beginner in Java language. Thanking in advance.

    regards,

    Zulifqar

    1. Pankaj says:

      java:comp/env is the root node of JNDI tree from where we can lookup specific JNDI contexts.

  30. Arun says:

    good explanation…

  31. subbareddy says:

    nice post……………….and where did u get this path java:/comp/env

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages