This was my first attempt at Spring with JNDI but getting the below mentioned exception when trying to create the ApplicationContext like:
ApplicationContext context = new ClassPathXmlApplicationContext("master-job.xml");
The Spring configuration file is as follows:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="/jdbc/Eqpstatus"/>
<property name="resourceRef" value="true" />
</bean>
<bean id="masterDao" class="com.dao.MasterDao">
<property name="dataSource" ref="dataSource"/>
</bean>
On Server i have the required resource entry for the JNDI name.
<Resource auth="Container" driverClassName="oracle.jdbc.OracleDriver"
maxActive="10" maxIdle="2" maxWait="10000" name="jdbc/Eqpstatus"
password="xxxx" type="javax.sql.DataSource"
url="jdbc:oracle:thin:#(DESCRIPTION=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=xxxx) (PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=xxxx) (PORT=1521))(CONNECT_DATA=(SERVICE_NAME=xyz)))"
username="xxx"/>
The error i see is:
javax.naming.NameNotFoundException: Name jdbc is not bound in this Context
Would highly appreciate any inputs on this as am new to Spring-JNDI integration.
First, I think you should use the dedicated tag instead of declaring a "JndiObjectFactoryBean" bean :
<!-- JNDI DataSource for J2EE environments -->
<jee:jndi-lookup id="dataSource" jndi-name="java:jdbc/rppsDS-PUB-PROTO" default-ref="localDataSource" />
<!-- local dataSource for JUnit integration tests -->
<bean id="localDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="100"/>
<property name="maxWait" value="1000"/>
<property name="poolPreparedStatements" value="true"/>
<property name="defaultAutoCommit" value="true"/>
</bean>
Then, you need a jndi.properties file (which could be directly in application server dir such as JBoss) with a content similar to :
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099
If you are using Tomcat and everything is fine with your Tomcat configuration; this should be enough:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/dataSource" />
Where jdbc/dataSource is the name defined in your Tomcat config.
EDIT:
My bad, forgot about the jndi.properties; there are two possibilities:
either provide a jndi.properties on your classpath or
set the values in a in the <jee:jndi-environment/> element of <jee:jndi-lookup /> (see reference)
The java.naming.factory.initial property needs to be set for sure, to something like org.apache.naming.java.javaURLContextFactory, possibly some other values as well, like:
java.naming.factory.url.pkgs=org.apache.naming
java.naming.factory.url.pkgs.prefixes=org.apache.naming
java.naming.provider.url=org.apache.naming
Also see reference.
Related
Is there anyway where we can make the JNDI lookup optional in spring appllicationcontext xml configuration.
I want to deploy the same application which has JNDI setting(Data base connection) on two different environments. In one environment we need DB connection and another environment we don't need the DB connection. Could you please suggest if there is a away we can achieve this without modifying the applicationcontext.xml(I mean without commenting out the JNDI configuration and other related bean injection for DB connection).
Use profiles, something like:
<beans profile="prod">
<jee:jndi-lookup id="dbDataSource" jndi-name="jdbc/DatabaseName"expected-type="javax.sql.DataSource" />
</beans>
<beans profile="dev,default">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="connectionCachingEnabled" value="true"/>
</bean>type="javax.sql.DataSource" />
</beans>
Then when you start you app say which profile with system argument:
-Dspring.profiles.actibe=prod
The default profile will be dev.
My application has applicationContext.xml with entityManagerFactory bean defined as :
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="org.xyz" />
**<property name="dataSource" ref="poolDVLDataSource" />**
<!--<property name="dataSource" ref="poolPRDDataSource" /> -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform"
value="org.hibernate.dialect.Oracle10gDialect" />
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
</property>
</bean>
and data source references as
<bean id="poolPRDDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
....
</bean>
and
<bean id="poolDVLDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
....
</bean>
I'm using gradle for build. Depending on the deploying environment, is there a way to replace the dataSource ref to either "poolDVLDataSource" or "poolPRDDataSource" dynamically?
ReplaceRegExp ant task should fix your issue. https://ant.apache.org/manual/Tasks/replaceregexp.html
Sample gradle code below:
ant.replaceregexp(match:'existingName', replace:'newName', byline:true) {
fileset(dir: 'WebContent/WEB-INF', includes: 'applicationContext.xml')
}
I wouldn't be solving this with gradle, you should solve this in spring
You can use spring's <import /> with a ${parameter} so that the actual file is decided at runtime. For instance you could split your service configuration into two files. The "internal" file could contain all the services implemented by your application and the "external" config file could contain external config including database connections, JMS connections, mail servers etc, etc.
Eg: applicationContext.xml
<context:property-placeholder/>
<import resource="classpath:internal-services.xml" />
<import resource="classpath:${environment}/external-services.xml" />
For production, you can pass environment=prod as a system property and load the prod/external-services.xml which contains the "real" services. For tests you could pass environment=mock and load mock/external-services.xml which contains mocks of all of your external services.
I am pretty new in Spring and I have the following problem.
I am working on an application, running into JBoss server, that have to perform queries on a DB using JdbcTemplate.
Into JBoss I have setted the JNDI name that identify the database connection.
I tryied to implement this JdbcTemplate simple example and it is pretty clear for me how JdbcTemplate works. In this example to create the connection to the database it define a dataSource bean and then inject it into the class that use the JdbcTemplate, in this way:
<!-- Initialization for data source -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<!-- Definition for studentJDBCTemplate bean -->
<bean id="studentJDBCTemplate"
class="com.tutorialspoint.StudentJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
So, as you can see, in this configuration the datasource configuration is explicitly written into the xml configuration file.
How can I obtain it from JBoss through the defined JNDI name?
You can use following spring-servlet.xml:
<jee:jndi-lookup id="dataSource" jndi-name="<JNDI NAME>" />
add following in xsi:schemaLocation attribute of beans tag :
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
I'm trying to deploy my Spring MVC webapp (Hibernate and JPA) to a Tomcat 7 ClickStack in Cloudbees, but cannot seem to configure the database connection properly. I've tried following multiple tutorials (which offer many solutions), none of which have worked. If someone could take a look at my config files below and let me know if they see anything wrong it would be greatly appreciated.
The error:
java.lang.NullPointerException
org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'
First, I bound my database to my app using the cloudbees cli so that I don't have to declare it in cloudbees-web.xml:
bees app:bind -a myapp/app -db mydatabase
application - myapp/app bound to cb-db:myapp/mydatabase as mydatabase
(I have also tried unbinding the database and defining it in cloudbees-web.xml and also in context.xml without success)
spring-data.xml:
<jee:jndi-lookup id="datasource" jndi-name="jdbc/mydatabase"
lookup-on-startup="false" proxy-interface="javax.sql.DataSource"
cache="true" resource-ref="true" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="hibernate-jpa"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="showSql" value="false"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
web.xml:
<resource-ref>
<res-ref-name>jdbc/mydatabase</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
I have removed all references to connectors from my Maven files and all jars from the lib folder. Searching for the error message shows that it usually has to do with the driver not being found... but since the database is supplied by the container, why do I have to worry about that?
-- EDIT: Working META-INF/context.xml file --
Note that the com.cloudbees.jdbc.Driver referenced in a lot of the docs didn't work (threw a classnotfound exception), so I had to package the mysql-connector-java.jar file in the lib folder. Also, for now I just hardcoded the url, username, and password instead of setting it up to use the system properties.
<Context>
<Loader delegate="true"/>
<Resource
name="jdbc/mydatabase"
auth="Container"
type="javax.sql.DataSource"
maxActive="5"
maxIdle="2"
username="USERNAME"
maxWait="5000"
driverClassName="com.mysql.jdbc.Driver"
password="PASSWORD"
url="jdbc:mysql://MY_EC2_DB_URL:3306/mydatabase"/>
</Context>
I was facing the same issue and finally managed to "properly" configure the datasource !
I'm using a PropertyPlaceholderConfigurer as follows :
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="database" value="MYSQL" />
<property name="generateDdl" value="false" />
</bean>
<context:property-placeholder system-properties-mode="FALLBACK" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${dt4j.driver}" />
<property name="url" value="${dt4j.url}" />
<property name="username" value="${dt4j.username}" />
<property name="password" value="${dt4j.password}" />
</bean>
"FALLBACK" indicates placeholders should be resolved against any local properties and then against system properties.
Finally, I just need to add system properties (-Dprop=value) or add them in the Cloudbees deployer plugin to make it work.
There must be a better way but the main goal is achieved : the data source configuration is not hardcoded in the project !
Unfortunately at this point in time, the JNDI DB setup is not done for you in the tomcat7 stack.
When you bind the database to your app - it injects some system properties:
MYSQL_PASSWORD_MYDB
MYSQL_URL_MYDB
MYSQL_USERNAME_MYDB
(MYDB as it is the name of your db resource). You can then refer to them in your code/config.
For tomcat 7, you can put in /META-INF/context.xml into your app which will set up the JNDI data source (see http://tomcat.apache.org/tomcat-7.0-doc/jndi-datasource-examples-howto.html)
I'm more than inexperienced with Apache Tomcat, so forgive me if it's a trivial question I'm asking.
My task is to change a rather big program so that it uses the connection from Tomcat instead of its own bean, so that you don't have to rebuild the code when the database changes.
This is the original bean definition (slightly changed - passwords and such...):
<bean id="ProjectDS" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" scope="singleton">
<property name="url"
value="jdbc:as400://127.0.0.1/TEST2;prompt=false;naming=sql;errors=full;date format=usa;date separator=/;time format=hms;time separator=:;transaction isolation=read committed;"/>
<property name="driverClassName" value="com.ibm.as400.access.AS400JDBCDriver"/>
<property name="username" value="asdf"/>
<property name="password" value="asdf"/>
<property name="initialSize" value="${ProjectDS.initialSize}"/>
<property name="maxActive" value="${ProjectDS.maxActive}"/>
<property name="maxIdle" value="${ProjectDS.maxIdle}"/>
<property name="minIdle" value="${ProjectDS.minIdle}"/>
<property name="testOnBorrow" value="${ProjectDS.testOnBorrow}"/>
<property name="removeAbandoned" value="${ProjectDS.removeAbandoned}"/>
<property name="removeAbandonedTimeout" value="${ProjectDS.removeAbandonedTimeout}"/>
<property name="logAbandoned" value="${ProjectDS.logAbandoned}"/>
</bean>
After reading several tutorials about Tomcat configuration, I did the following:
The new bean:
<bean id="ProjectDS" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>ProjectDS</value>
</property>
<property name="resourceRef" value="true"></property>
</bean>
server.xml :
<Resource name="ProjectDS" global="ProjectDS" auth="Container"
type="org.apache.commons.dbcp.BasicDataSource"
driverClassName="com.ibm.as400.access.AS400JDBCDriver"
url="jdbc:as400://127.0.0.1/TEST2"
username="asdf"
password="asdf" />
context.xml:
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<ResourceLink global="ProjectDS" name="ProjectDS" type="org.apache.commons.dbcp.BasicDataSource"/>
What I get is:
Exception processing Global JNDI Resources
javax.naming.NamingException: Cannot create resource instance
I read somewhere that I shouldn't put the above into the server.xml but into the web.xml, but I don't know where exactly. Could that be the problem?
First, rollback your context.xml and server.xml in your tomcat and/or. Here is a working configuration:
Create a file in src/main/webapp/META-INF named context.xml which contains:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="ProjectDS" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.ibm.as400.access.AS400JDBCDriver"
url="jdbc:as400://127.0.0.1/TEST2"
username="asdf"
password="asdf" />
</Context>
Then, edit your bean in this way:
<bean id="ProjectDS" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/ProjectDS" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>
Difference here is the java:comp/env/ProjectDS and the proxy unterface.
Hope it will work for you!