How to make JNDI look up optional in Spring - spring

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.

Related

How can I obtain the DataSource connection through the JNDI name in Spring?

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

Build Maven project without include Spring bean profile

I use Spring bean profile to separate each datasource environments:
<bean id="fooJDBCTemplate" class="com.rakuya.r_erp.task.dao.FooJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<beans profile="dev">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
</beans>
<beans profile="qa">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
</beans>
<beans profile="prod">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
</beans>
And i use following command to build jar file and specify profile
mvn clean package -Dspring.profiles.active=prod
But i got the error about no definition of dataSource when executing the jar file.
It seems like Maven does not use the Spring profile to build jar.
How can I configure the Maven or Spring peofile to use the dataSource ?
Thx
You need to pass the profile -D switch when you run your app.
Since your bears are all the same type (DriverManagerDataSource) and the only thing that differs between environments are some of the properties, I think it would be best to get rid of the spring profiles and use properties to set these values. PropertyPlaceholderConfigurer should be able to handle this scenario where you set a vm param specifying what environment you want. Something like -Denv=dev.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:${env}.properties</value>
</list>
</property>
</bean>
Then you would only need one datasource bean like the following:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
And a property file for each environment named dev.properties, qa.properties, and prod.properties with values in each for db.driver, db.url, etc.
When spring starts up it will select the appropriate properties file based on the value passed in with -Denv and load the corresponding property values into your datasource bean.

Cloudbees, Tomcat, and Spring: "Cannot create JDBC driver of class '' for connect URL 'null'"

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)

Error upon integrating JNDI with Spring

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.

Setup Connection Pooling in Spring MVC

How can I setup connection pooling in Spring MVC? I am working on an intranet website powered by Spring MVC 2.5 and jQuery. This is my first attempt at web development.
I am not sure but, I am only using this in my spring configuration file and I saw this in the Spring MVC step By Step tutorial
<bean id="dataSource" 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}" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
This looks good during development and connection speed is fast but I am not sure if this will still holds true if many users are concurrently connected.
How can I achieve this? I have read that this is not an optimal connection datasource.
You might want to look at c3p0, which has some powerful configuration and optimization available.
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="..." />
<property name="jdbcUrl" value="..." />
<property name="user" value="..." />
<property name="password" value="..." />
</bean>
Your current setup is correct, all you need to do in order to use basic connection pooling is use a DataSource implementation provided by a connection pooling library, in your case Apache DBCP. See this post for a few links to other alternatives, C3P0 being one of them.
Note that when you actually use the DataSource bean you're injecting wrap it in a SimpleJdbcTemplate or use DataSourceUtils to obtain a Connection - see Spring JDBC Documentation
For connection Pooling
<bean id="dataSource" 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}" />
//Add this two more parameters
<property name="**initialSize**" value="20" />
<property name="**maxActive**" value="30" />
</bean>
connection pool will create 20 database connection as initialSize is 20 and goes up to 30 Database connection if required as maxActive is 30.

Resources