2015-01-12

Connecting to PostgreSQL from Tomcat 7 on OpenShift

I'm using a free OpenShift account to host a small site, and had some trouble getting a connection to my PostgreSQL cartridge from my Tomcat 7 (JBoss EWS 2.0) cartridge. As often happens, the act of asking the question made me think of a few additional solutions to explore, but I ended up posting the question then heading to OpenShift's support page to send a question. Like StackOverflow, OpenShift's contact page starts suggesting articles when you type in a subject, and that's how I found the article that describes their JNDI DataSources exposed by Tomcat.

There are a couple of examples in the article, but the one we're interested in is under Tomcat 6 (JBoss EWS 1.0) / Tomcat 7 (JBoss EWS 2.0) Example. The example code uses Java code embedded in a JSP page (please don't do that yourself) to demonstrate how to gain access to the MySQL JNDI DataSource, but they include the name of the PostgreSQL DataSource as well, so it's easy enough to adapt the code for our purposes.
package org.example.config.root;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
public class OpenshiftDataConfig {

 @Bean
 public DataSource dataSource() throws NamingException {
  DataSource datasource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/PostgreSQLDS");
  return datasource;
 }
 
}
That should provide you with a pooled DataSource, but if you're interested in more detail about how I came to this conclusion, read on.

I didn't see any information about whether the provided DataSource is pooled or not, and being unfamiliar with a Tomcat-provided DataSource, I tried wrapping it with a HikariCP HikariDataSource.
    @Bean
    public DataSource dataSource() throws NamingException {
        DataSource providedDatasource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/PostgreSQLDS");

        HikariDataSource hikariDatasource = new HikariDataSource();
        hikariDatasource.setDataSource(providedDatasource);

        return hikariDatasource;
    }
But I got the dreaded
org.hibernate.HibernateException: Connection cannot be null when 'hibernate.dialect' not set
I realized that Hibernate was trying to get a Connection from the DataSource, so I tried the same from my code to see if it's null at that point, which yields
java.lang.UnsupportedOperationException: Not supported by BasicDataSource
at org.apache.tomcat.dbcp.dbcp.BasicDataSource.setLoginTimeout(BasicDataSource.java:1121) ~[commons-dbcp-eap6.jar:na
Seeing dbcp in the package name suggested that there's a connection pool already in place, and it looks like the Tomcat JDBC connection pool. The package name in the documentation is org.apache.tomcat.jdbc.pool, but from a comment:
org.apache.tomcat.dbcp.dbcp.* is a package-renamed copy of Apache Commons DBCP database connection pool implementation.
The configuration can be found in app-root/runtime/repo/.openshift/config/context.xml.

No comments:

Post a Comment