Discussions

Web tier: servlets, JSP, Web frameworks: JNDI datasources in Tomcat 5

  1. JNDI datasources in Tomcat 5 (17 messages)

    I have a problem using a datasource in Tomcat 5.
    I've searched the web and these forums and it seems to be a common problem but the solutions are varied and I haven't
    got it working yet.
    The JNDI lookup works fine but it fails on this line:
    Connection conn = ds.getConnection();

    With the exception:
    javax.servlet.ServletException: Cannot create JDBC driver of class '' for connect URL 'null'

    I have configured the datasource in my [myapp]/META-INF/context.xml like this:

    <Context path="/myapp" docBase="myapp"
            debug="5" reloadable="true" crossContext="true">

    <Resource name="jdbc/myappdb" auth="Container" type="javax.sql.DataSource">
      <ResourceParams>

      <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://127.0.0.1/myappdb</value>
      </parameter>

      <parameter>
        <name>username</name>
        <value>myappuser</value>
      </parameter>

      <parameter>
        <name>password</name>
        <value>verysecret</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>60</value>
      </parameter>

      <parameter>
        <name>logAbandoned</name>
        <value>true</value>
      </parameter>

      </ResourceParams>
    </Resource>
    </Context>

    The resource is referenced in my [myapp]/WEB-INF/web.xml like this:
       ... display name ...
      <resource-ref>
        <description>myapp postgres database</description>
        <res-ref-name>jdbc/myappdb</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
      </resource-ref>
       ... servlet ...

    The postgres driver jar is located in [tomcat]/common/lib.
    The app is deployed as a war named myapp.war in [tomcat]/webapps.
    The tomcat logs display no errors during startup.

    Could anyone shed some light on this?

    I appreciate any help.

    Threaded Messages (17)

  2. JNDI datasources in Tomcat 5[ Go to top ]

    I was able to get a similar scenario to work using Tomcat 5. I did not define a resource ref in web.xml.

    Note that your context.xml only seems to be used if you use the manager/html upload and deploy feature for a war file.

    If you haven't done this, consider putting your context.xml in the conf/Catalina/localhost. The convention seems to be to name the file the same as the webapp context name.

    My hunch is that this is your problem and you are not getting your context.xml read. I suspect you are getting a default context built for you without the jndi def you need. Perhaps the resource-ref in your web-xml is satisfying the JNDI lookup.

    I had some conflicts with other db jars as I was trying to use two different versions of a db jar in two different webapps. I used the classloader hierarchy to solve this problem. I had to move my db jars into my WEB-INF/lib directory. When I did this, I also had to move a copy of dbcp out of common/lib and into both server/lib and the WEB_INF/lib of each webapp. This kept all the versions separate.

    Since you have only one db, and you have it in common/lib, I doubt if this is you problem. I only mention it to try to give some more food for thought.

    Good luck and I hope this helps.
  3. JNDI datasources in Tomcat 5[ Go to top ]

    I did some more investigating and I see that when Tomcat 5 starts up and there is a mywebapp.war file but no mywebapp directory, it WILL extract context.xml from META-INF and place it in ./tomcat5.0/conf/Catalina/localhost.

    This context worked for me:

    <Context path="/usmg" docBase="mywebapp" debug="0" reloadable="false" crossContext="true">
        <ResourceParams name="jdbc/offboard">
            <parameter>
                <name>factory</name>
                <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
            </parameter>
            <parameter> <name>maxActive</name>
                <value>20</value>
            </parameter>
            <parameter>
                <name>maxIdle</name>
                <value>10</value>
            </parameter>
            <parameter>
                <name>maxWait</name>
                <value>10000</value>
            </parameter>
            <parameter>
                <name>validationQuery</name>
                <value>select 1 from userrole</value>
            </parameter>
            <parameter>
                <name>username</name>
                <value>myuser</value>
            </parameter>
            <parameter>
                <name>password</name>
                <value>mypassword</value>
            </parameter>
            <parameter>
                <name>driverClassName</name>
                <value>COM.ibm.db2.jdbc.net.DB2Driver</value>
            </parameter>
            <parameter>
                <name>connectionProperties</name>
                <value>currentSchema=mySchema</value>
            </parameter>
            <parameter>
                <name>url</name>
                <value>jdbc:db2//mydb2host:6790/MYDB</value>
            </parameter>
            <parameter>
                <name>removeAbandoned</name>
                <value>true</value>
            </parameter>
            <parameter>
                <name>removeAbandonedTimeout</name>
                <value>60</value>
            </parameter>
            <parameter>
                <name>logAbandoned</name>
                <value>true</value>
            </parameter>
        </ResourceParams>
        <Resource auth="Container" description="DB2 Datasource" name="jdbc/offboard" type="javax.sql.DataSource"></Resource>
    <Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_mywebapp_log." suffix=".txt" timestamp="true"/>
    </Context>

    I have nothing in my web.xml relating to this JNDI entry.

    I use the following code to get a connection:

    import org.apache.log4j.Logger;
    import java.sql.Connection;
    import java.sql.SQLException;
    import javax.sql.DataSource;
    import javax.naming.InitialContext;
    import javax.naming.Context;
    import javax.naming.NamingException;

    public class DBUtil {

        private static Logger logger = Logger.getLogger(DBUtil.class);
        private static boolean debug = logger.isDebugEnabled();
        private static boolean info = logger.isInfoEnabled();


        public static Connection getConnection(String jndiName) throws DatabaseException {
            Connection conn = null;
            try {
                Context ctx = new InitialContext();
                if (ctx == null )
                    throw new DatabaseException("No Context");
                DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/" + jndiName);
                if (ds == null) {
                    throw new DatabaseException("Datasource not found");
                }
                conn = ds.getConnection();
                if (conn == null) {
                    throw new DatabaseException("Could not get connection");
                }
            } catch (SQLException e) {
                throw new DatabaseException(e);
            } catch (NamingException e) {
                throw new DatabaseException(e.getMessage());
            }
            return conn;
        }
    }
  4. this worked for me[ Go to top ]

    I had a similar problem. First I had: InitialContext context = new InitialContext(); DataSource ds = (DataSource) context.lookup("/jdbc/thingie"); it din't work so, after changing the above lines to: InitialContext context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/thingie"); it worked smooth ! hope it works for u too.
  5. JNDI datasources in Tomcat 5[ Go to top ]

    One last gasp: I tried using the <resource-ref> in the wb.xml and it worked for me as well after commenting out my <Resource auth="Container" description="DB2 Datasource" .../> in mywebappcontext.xml. Could it be that your <resource-ref> is misplaced in your web.xml? The dtd says

    <!ELEMENT web-app (icon?, display-name?, description?, distributable?,
    context-param*, filter*, filter-mapping*, listener*, servlet*,
    servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,
    error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*,
    login-config?, security-role*, env-entry*, ejb-ref*, ejb-local-ref*)>

    so it must be placed after ...servlet...
  6. JNDI datasources in Tomcat 5[ Go to top ]

    You need to create a context XML file for each application that you deploy. For example, your XML file below should be as follows:

    $CATALINA_HOME/conf/Catalina/localhost/myapp.xml

    Keep in mind that the name of the XML file should be the same as the app.
    I find this approach works better than the default context.
  7. I have the same problem.
    I'm sorry I don't have a solution. Do you have a solution yet?

    Here are my comments, which I hope will take us forward a little:

    Starting with nothing but the java code:
        Context initContext = new InitialContext();
        DataSource ds = (DataSource)initContext.lookup("java:comp/env/jdbc/dbName");
    I obviously get "javax.naming.NameNotFoundException: Name dbName is not bound in this Context"


    Then adding a resource reference in my WEB-INF/web.xml file:
        <resource-ref>
            <description>DB Connection</description>
            <res-ref-name>jdbc/dbName</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Container</res-auth>
        </resource-ref>
    This satisfies the jndi reference in my java code (so I have not mis-spelt the name) giving me the error "org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'".
    Clearly it has assumed a default factory for my DataSource and (understandably) has no parameters available to fill in the Driver and Url properties.


    Then adding a resource in my Tomcat/conf/Catalina/localhost/app.xml file:
        <Resource
            name="jdbc/dbName"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.commons.dbcp.BasicDataSourceFactory"
        />
    gives me the error "org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'".
    Notice the error is now from a class in package org.apache.commons and not org.apache.tomcat as it did last time.
    So I can deduce:
    1) The resource name is spelt correctly.
    2) The resource declaration in my <Context> has been found.
    3) My chosen factory has been successfuly found in Tomcat/common/lib.


    Now comes the frustrating part.
    Then adding the resource parameters (I won't give a complete list of parameters here but they are very similar to yours):
        <ResourceParams
            name="jdbc/dbName"
            >
            <parameter>
                <name>driverClassName</name>
                <value>com.mysql.jdbc.Driver</value>
            </parameter>
            <parameter>
                <name>url</name>
                <value>jdbc:mysql://localhost:3306/?autoReconnect=true</value>
            </parameter>
        </ResourceParams>
    gives me the error "org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'".
    Notice the error is exactly the same as before.
    If I change my java code to obtain a BasicDataSource (instead of just the DataSource interface) I can confirm that ds.getUrl() does return null.


    The upshot of all of this is that:
    1) I believe I have put the <resource-ref> and <Resource> definitions in the right place.
    2) I believe I have put the org.apache.commons.dbcp.BasicDataSourceFactory in the right place.
    3) The problem is that the <ResourceParams> definition is entirely ignored.


    I hope my comments have, at the very least, helped to narrow down where the problem actually is so that we can concentrate on the correct area.
  8. Same JNDI Problem[ Go to top ]

    I m stuck with the same JNDI DataSource problem as this thread points to. If you have found the slution could u please let me know too. my email id is xkamlesh at yahoo dot com

    thanks a lot
  9. I've found the solution[ Go to top ]

    Hi,

    Make sure that you include ....META-INF/context.xml (it must be exactly context.xml not myapp.xml) in you war file while you build it. Simply unpack the war file and see if META-INF/context.xml is in there. Then tomcat, while deploying, will put this context under $CATALINA_HOME/conf/Catalina/localhost/myapp.xml (tomcat is by itself changing the file name from context.xml into myapp.xml)

    let me know if it helps (wak [at] wp.pl)

    WK
  10. After almost a day on the same problem, here is the answer that I have found:

    You're original context.xml file :

    ...
    <Resource name="jdbc/myappdb" auth="Container" type="javax.sql.DataSource">
      <ResourceParams>

      <parameter>
        <name>factory</name>
        <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
      </parameter>

    ...

    worked for me in Tomcat 5.0, but when I went to Tomcat 5.5 it produced the results that you are talking about.

    To fix this I have removed the ResourceParams element and put all the parameters as attributes in the Resource element:

    <Resource name="jdbc/myappdb" auth="Container" type="javax.sql.DataSource" factory="org.apache.commons.dbcp.BasicDataSourceFactory" driverClassName="org.postgresql.Driver" ..... />

    It then works in Tomcat 5.5
  11. clean build folder[ Go to top ]

    I've been having similar problems too and after doing a lot of hair pulling, cleaning out my build directory did the trick. Unbelievable. Yep, just delete the build directory and let it recompile all your classes from scratch.
  12. May be this[ Go to top ]

    I stumbled with the same "could not instantiate driver class '' with url null" problem.

    After reading all this discussion and others, i finally got it working.

    Here's how.
    1) I have a Tomcat 5.0.28 with autoDeploy="true" feature.
    2) It is running.
    3) I copy the foo.war file in webapps
    4) I copy a foo.xml context definition with the Context, Resource and ResourceParams elements.

    That's all, BUT, I slightly touched the XML.
    I rplaced the <Resource .... /> with two <Resource ...></Resource>

    The XML looks exactly like yours except for this detail and it was not until this modification that i got it running.

    Hope it helps.
  13. I have gotten back to this again and was trying it under Tomcat 5.5.9 and finally got it to work (again). Running Tomcat under eclipse was very helpful because when I got to a line like
    DataSource ds = (DataSource)ctx.lookup ("java:/comp/env/jdbc/" + jndiName);
    I could inspect ds and see that it was empty. The problem is that only a skelton ds was being created. The solution is to add

    factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
    to your resource. This was omitted from the documentation and in any event the factory is different than in Tomcat 4 or 5.0.

    This is what worked for me for a DB2 database:

    in server.xml

    <GlobalNamingResources>
    <Resource name="jdbc/obqsmqdb" auth="Container"
                    type="javax.sql.DataSource"
                 factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
               maxActive="30" maxIdle="10" maxWait="10000"
                     url="jdbc:db2://sa1c:50002/GWPRODE"
         driverClassName="com.ibm.db2.jcc.DB2Driver"
                username="myuserid"
                password="mypassword"
         removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true"
    connectionProperties="currentSchema=MYSCHEMA;"
         validationQuery="select 1 from SESSION_POOL_ID_MAPPING"
             description="DB2 Datasource" />
    <!-- currentSchema MUST be uppercase -->
    </GlobalNamingResources>

    in web.xml
    <web-app>
    <!-- other stuff here -->
        <resource-ref>
            <description>DB2 Connection</description>
            <res-ref-name>jdbc/obqsmqdb</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Container</res-auth>
        </resource-ref>
    </web-app>

    in context.xml
    <Context path="/obqsmq"
             docBase="obqsmq"
             displayName="Obqsmq Application"
             reloadable="false"
             crossContext="true"
             cookies="true"
             swallowOutput="true"
             override="true"
             debug="0">

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

    I also tried with the <Resource> in context.xml instead of <ResourceLink> and that worked as well.

    Tomcat 5.5 writes the context.xml into
    Tomcat-5.5.9/conf/Catalina/localhost/obqsmq.xml
    renaming it along the way to my app name, obqsmq. I have not investigated this thoroughly but it looks like if you stop Tomcat, then delete the app and app.war from the webapps directory, then replace the app.war, the app.xml context is NOT updated. When you delete app, app.war, you must also delete
    Tomcat-5.5.9/conf/Catalina/localhost/app.xml. If you don't do this, you will wonder (as I did) why changes make no difference.

    Peter
  14. After reading the JNDI Resources HOW-TO of Tomcat 5.5, I can only conclude "Resources" configuration seems to have changed.

    I think a Resource section like below inside your context.xml should work. Apparently this is equivalent to the <resource-ref> section in the web.xml (so I think you only need one or 'tother and not both).

    HTH

    Mark

    <Context path="/myapp" docBase="myapp" debug="5" reloadable="true" crossContext="true">

    <Resource
    name="jdbc/myappdb"
    auth="Container"
    type="javax.sql.DataSource"
    factory="org.apache.commons.dbcp.BasicDataSourceFactory"
    driverClassName="org.postgresql.Driver"
    url="jdbc:postgresql://127.0.0.1/myappdb"
    username="myappuser"
    password="verysecret"
    maxActive="20"
    maxIdle="10"
    maxWait="-1"
    removeAbandoned="true"
    removeAbandonedTimeout="60"
    logAbandoned="true" />
    </Context>
  15. does work for me[ Go to top ]

    hi,
    my successful config with
    tomcat 5.5.7
    postgresql 7.4 & pg74.216.jdbc3.jar
    java 5

    ----context.xml-----
    <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/PgDataPool2" docBase="PgDataPool2" debug="5" reloadable="true" crossContext="true">
    <Resource
    name="jdbc/gis"
    auth="Container"
    type="javax.sql.DataSource"
    factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
    driverClassName="org.postgresql.Driver"
    url="jdbc:postgresql://127.0.0.1/gis"
    username="postgres"
    password="xxx"
    maxActive="20"
    maxIdle="10"
    maxWait="-1"
    removeAbandoned="true"
    removeAbandonedTimeout="60"
    logAbandoned="true"/>
    </Context>

    -----web.xml---------
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
        <session-config>
            <session-timeout>
                30
            </session-timeout>
        </session-config>
        <welcome-file-list>
    <welcome-file>
                index.jsp
            </welcome-file>
        </welcome-file-list>
        <resource-ref>
            <description>gis connection</description>
            <res-ref-name>jdbc/gis</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Container</res-auth>
        </resource-ref>
    </web-app>

    no changes for server.xml, standard JSP source for pooling. Hope that helps.
  16. This is what I tried and it worked. Put the resource information in server.xml in between <host> & context> tag

    and give the reference to web.xml of your application
    I tried this configuration in Tomcat5.5 with Oracle.

    ----- server.xml ----
          <Host name="localhost" appBase="webapps"
           unpackWARs="true" autoDeploy="true"
           xmlValidation="false" xmlNamespaceAware="false">
      <Context path="/quickstart" docBase="quickstart">
        <Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
        <ResourceParams name="jdbc/quickstart">
            <parameter>
                <name>factory</name>
                <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
            </parameter>

            <!-- DBCP database connection settings -->
            <parameter>
                <name>url</name>
                <value>jdbc:oracle:thin:@10.112.73.50:1521:EPS</value>
            </parameter>
            <parameter>
                <name>driverClassName</name><value>oracle.jdbc.driver.OracleDriver</value>
            </parameter>
            <parameter>
                <name>username</name>
                <value>scott</value>
            </parameter>
            <parameter>
                <name>password</name>
                <value>tiger</value>
            </parameter>

            <!-- DBCP connection pooling options -->
            <parameter>
                <name>maxWait</name>
                <value>3000</value>
            </parameter>
            <parameter>
                <name>maxIdle</name>
                <value>100</value>
            </parameter>
            <parameter>
                <name>maxActive</name>
                <value>10</value>
            </parameter>
        </ResourceParams>
    </Context>
          </Host>



    ------ web.xml ----
      <resource-ref>
            <description>Connection Pool</description>
            <res-ref-name>jdbc/quickstart</res-ref-name>
            <res-type>javax.sql.Datasource</res-type>
            <res-auth>Container</res-auth>
      </resource-ref>
  17. Looks good[ Go to top ]

    But how time flies! According to this tomcat 7 article, servlet 3.0 will be released pretty soon. Hard to imagine where the time went.

  18. connectionProperties="currentSchema=METRICSERVICE_UAT;username='xxxxx';password='xxxxx'"