Spring Jndi Configuration, Server.xml

40,319

Solution 1

When you run your testcases, you will want to use JDBC instead of JNDI lookup. The simple reason is because you usually don't run your testcases from the application server. Thus, JNDI lookup will fail.

What I do on my end is to place data source in a separate file. I have one file for production that uses JNDI:-

project-datasource.xml

<jee:jndi-lookup id="geoCodeData" jndi-name="java:comp/env/jdbc/myTomcatPool"></jee:jndi-lookup>

... another another file for unit test that uses JDBC:-

project-datasource-test.xml

// use the same bean name "geoCodeData"
<bean id="geoCodeData" class="...">
    <property name="driverClassName" value="..." />
    <property name="url" value="..." />
    <property name="username" value="..." />
    <property name="password" value="..." />
</bean>

The web app will use project-datasource.xml whereas the unit test will use project-datasource-test.xml.

Solution 2

After several hours of tearing out my (already sparse) hair I have managed to get my tomcat server to pool database connections to Oracle and use the Spring framework. I though I would reply to this question even though there seems to be an answer, just in case it helped anybody else.

What I wanted: A connection pool administered by Tomcat (rather than per servlet) and the config for the DB connection in the Tomcat server config (again, rather than the servlet config files).

We have several instances of Tomcat and each one connects to a specific Oracle DB, but developers are producing servlets that could be required to run on any one of them, hence I don't want the DB connection details in the WAR file they produce, but to let them look it up and be provided with that server's data source, via JNDI.

In the Tomcat server conf/context.xml I added the following code:


<Resource       name="jdbc/banner"
                auth="Container"
            factory="org.apache.commons.dbcp.BasicDataSourceFactory"
                    type="javax.sql.DataSource"
                    driverClassName="oracle.jdbc.OracleDriver"
                    url="jdbc:oracle:thin:@DBan8DB1.example.ac.uk:1522:bde8"
            username="dbsro"
            password="verysecret"
            initialSize="5"
            maxActive="20"
            maxIdle="10"
            removeAbandoned="true"
            global="jdbc/banner"
            maxWait="-1"/>

Obviously I have the ojdbc, pool and dbcp JAR files present in Tomcat's lib directory on the server. An important point to note here is that the type is of "javax.sql.DataSource" rather than "org.apache.commons.dbcp.BasicDataSource" which I originally thought it should be.

Now in the Web Application's WEB-INF/web.xml I added the following:


   <resource-ref>
        <description>Oracle Banner Datasource</description>
        <res-ref-name>jdbc/banner</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

and in my Web Application's servlet-context.xml file (where ever you keep yours might vary) I had this. This is not the whole file but the XML name space is important here, for the jee parts:


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">


<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/banner" resource-ref="true" />

Again note the fully qualified reference jndi-name="java:comp/env/jdbc/banner" which seemed to be required. Why is isn't needed in the resource-ref section of the web.xml file, I have no idea.

If anyone has any thoughts on this I would be pleased to read them.

By the way, this URL helped: Tomcat6 JNDI data source how-to

After all that, the connection worked. So I mopped the blood, sweat and tears from my work station and enjoyed a delicious cup of fresh coffee.

Share:
40,319
blong824
Author by

blong824

I am a Developer in Phoenix, AZ. I have experience working with Java, Spring, Javascript, Html5, and CSS3. I enjoy golfing, reading, learning new things, and spending time with my wife and daughter.

Updated on January 15, 2020

Comments

  • blong824
    blong824 over 4 years

    I have a problem setting up my configuration for JNDI with Spring. I checked the other posts but could not get my problem solved. I am using Tomcat 6 as my container. From my understanding I need to set up a resource on the server. So in my server.xml file I have this:

    <GlobalNamingResources>
        <Resource auth="Container" driverClassName="org.postgresql.Driver"
                maxActive="100" maxIdle="5" maxWait="10000"
                minEvictableIdleTimeMillis="60000" name="jdbc/myTomcatPool"
                password="password" testOnBorrow="true" testWhileIdle="true"
                timeBetweenEvictionRunsMillis="10000" type="javax.sql.DataSource"
                url="jdbc:postgresql://localhost:5432/postgis" username="postgres"
                validationQuery="SELECT 1"/>
    </GlobalNamingResources>
    

    I have the following in my spring-context.xml (which is on the classpath):

    <jee:jndi-lookup id="geoCodeData" jndi-name="java:comp/env/jdbc/myTomcatPool" />
    
    <bean id="geoCodeService" class="com.sample.SampleImpl">
        <property name="dataSource" ref="geoCodeData"/>
    </bean>
    

    I then have this in file META-INF/context.xml:

    <Context path="/myApp" reloadable="true" cacheMaxSize="51200"
            cacheObjectMaxSize="2560">
        <ResourceLink global="jdbc/myTomcatPool" name="jdbc/myTomcatPool"
                type="javax.sql.DataSource"/>
    </Context>
    

    My server starts up free of errors.

    When I try to run the following test (that worked before I added the JNDI code):

    public class Test {
        public static void main(String[] args) {
            ApplicationContext ctx =
                new ClassPathXmlApplicationContext("spring-context.xml");
        }
    }
    

    I get the following error:

    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'geoCodeData': Invocation of init method failed;

    nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial

    Is my configuration wrong or is the way I am trying to run the test incorrect?

  • blong824
    blong824 over 13 years
    That makes sense. I thought it might have to do with just the test case. I will try this. I am going to mark this as the answer. Thanks again. One last question, I would then add the project-datasource.xml to my list of contextConfigLocation's in my web.xml and use the project-datasource-test.xml in my test classes like my example?
  • acdcjunior
    acdcjunior over 10 years
    What a clever solution! Btw, you can refer to the newly-created datasource file in you app config xml using: <import resource="classpath:project-datasource.xml"/> and the alike. Cheers!
  • Manuel Spigolon
    Manuel Spigolon over 9 years
    This helped me a lot!