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

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)

Related

How do I replace content or keyword of an xml (like applicationContext.xml) with Gradle build?

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.

Configure Hibernate C3P0 Connection Pooling

I'm stumbled upon a problem while developing a Web Application based on Struts2 with Spring and Hibernate.
When I refresh the site a few times, for example 2-4 times, Hibernate is showing up an exception about Too many connections. I've tried to implement C3P0 Connection pool and have some problems with it
The hibernate.cfg.xml configuration:
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/axelle</property>
<property name="hibernate.connection.username">axelle</property>
<property name="hibernate.connection.password">dbpassword</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
applicationContext.xml
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:jdbc.properties"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
p:connectionProperties="${jdbc.connectionProperties}"/>
<!-- ADD PERSISTENCE SUPPORT HERE (jpa, hibernate, etc) -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
The log output is:
org.hibernate.exception.JDBCConnectionException: Cannot open connection
and:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
And this is how PROCESSLIST MySQL window looks: http://img844.imageshack.us/img844/3959/be69273cc2.png
I've set max_size of connections to 20, but it seems like it doesn't read the C3P0 configuration from file, cause from the screen we can see that number of connections is higher than 20, or maybe I'm doing something wrong, but where? I really need some help guys, I'll appreciate this, and thanks in advance.
Mention these property in your hibernate.cfg.xml file
<property name="hibernate.c3p0.acquire_increment">1</property>
<property name="hibernate.c3p0.idle_test_period">100</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.min_size">10</property>
<property name="hibernate.c3p0.timeout">100</property>
Refer this link for better understanding: Configuration Properties
In your applicationContext, instead of using <bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" ... try using <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" ...
The C3P0PooledDataSource will create a wrapped database connection using the specified DriverClassName, url, username and password

JNDI Resource Definition in Apache Tomcat 6

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!

Hibernate (JPA,JSF 2.0, Spring) switch from HyperSQL to Oracle - Configuration is being ignored

i'm currently in the process of working on a midsized Webproject, using JSF 2.0 with Spring.As IDE i use Eclipse with JBoss Tools. The Webapp is deployed to a Tomcat v7.0 Server.
I use Hibernate/JPA/C3P0/ to connect to the Database (previously HyperSQL) I now tried to switch to an Oracle DB, which i did a number of times before and it never was a problem, however now it seems, that the changed configuartion is just being ignored. When i fire up the Server, it still uses the HyperSQl Driver and the old DB, although i cleaned the workdirectory of Tomcat, removed and redeployed the Webapp (which i built from scratch of course).
The project is split in two, one webapp and one service part. The project are dependent in Eclipse. However, although all of the businesslogic is implemented in the service layer, i can just remove it and the webapp doesn't throw an error and i can start it as if nothing has changed. This tells me that it must be cached somewhere and it is not refreshed on the server...I also deleted the server, added a freshly downloaded instance - still the same thing...Does anyone have an Idea what this could be about?
Here is my service.spring.xml:
<!-- Enable processing of #PersistenceContext and #PersistenceUnit -->
<context:annotation-config/>
<!-- Enable transaction configuration with #Transactional -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Configure a c3p0 pooled data source -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="user"/>
<property name="password" value="password"/>
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:#dburl"/>
<property name="initialPoolSize" value="1"/>
<property name="minPoolSize" value="1"/>
<property name="maxPoolSize" value="10"/>
</bean>
<!-- Configure the JPA entity manager factory with Hibernate -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false"/>
<property name="database" value="ORACLE"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
<property name="persistenceUnitName" value="mygourmet"/>
</bean>
<!-- Configure transaction manager for JPA -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
And my persistence.xml:
<persistence-unit name="mygourmet" transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.connection.autocommit" value="false" />
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
I used the exact same configuration on another project and it works like a charm...Any hints are highly appreciated, thank you guys in advance!
Problem solved - i did a mvn clean install, generated new eclipse projects and imported them back into eclipse. It seems the changes in my service module were not recognized by eclipse.

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.

Resources