0

I am developing a Jersey application which is connected to a PostgreSQL database. I am looking for a solution how to configure Hibernate in a way that it always connects correctly to either the local or the Heroku based database (depending on if I deploy my application locally or if I push it to Heroku).

Using the Heroku guides, I tried something like this:

HibernateUtil.java:

private static SessionFactory buildSessionFactory() {
    try {
        // Create the SessionFactory from hibernate.cfg.xml
        Configuration configuration = new Configuration();
        configuration.configure("hibernate.cfg.xml");

        configuration.setProperty("hibernate.connection.url",
                System.getenv("DATABASE_URL"));

        URI dbUri = new URI(System.getenv("DATABASE_URL"));

        String username = dbUri.getUserInfo().split(":")[0];
        String password = dbUri.getUserInfo().split(":")[1];
        String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ':'
                + dbUri.getPort() + dbUri.getPath();
        configuration
                .setProperty("hibernate.connection.username", username);
        configuration
                .setProperty("hibernate.connection.password", password);
        configuration.setProperty("hibernate.connection.url", dbUrl);
        System.out.println("Hibernate Annotation Configuration loaded");

        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                .applySettings(configuration.getProperties()).build();
        System.out.println("Hibernate Annotation serviceRegistry created");

        SessionFactory sessionFactory = configuration
                .buildSessionFactory(serviceRegistry);

        return sessionFactory;
    } catch (Throwable ex) {
        // Make sure you log the exception, as it might be swallowed
        System.err.println("Initial SessionFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

My hibernate.cfg.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 4.0//EN"
        "http://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection properties - Driver, URL, user, password -->
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.url">jdbc:postgresql://localhost/MYAPP</property>
        <property name="hibernate.connection.username">user</property>
        <property name="hibernate.connection.password">password</property>

        <!-- org.hibernate.HibernateException: No CurrentSessionContext configured! -->
        <property name="hibernate.current_session_context_class">thread</property>

        <!-- Mapping with model class containing annotations -->
        <mapping class="com.example.object" />
    </session-factory>
</hibernate-configuration>

The idea is that HibernateUtil overrides the hibernate.cfg.xml properties (url, user, password). Deploying locally works but deploying to Heroku fails:

remote: [ERROR] Failed to execute goal de.juplo:hibernate4-maven-plugin: .1.0:export (default) on project myapp: Execution default of goal de.juplo:hib rnate4-maven-plugin:1.1.0:export failed: Error calling Driver#connect: Connecti n to localhost:5432 refused. Check that the hostname and port are correct and t at the postmaster is accepting TCP/IP connections. Connection refused -> [Help ]

Daniel
  • 502
  • 6
  • 17

1 Answers1

0

It looks like on Heroku, your app is using the configuration from hibernate.cfg.xml instead of the buildSessionFactory() method. Can you confirm that the buildSessionFactory() is being called?

I think you should remove the hibernate.connection.* properties from your hibernate.cfg.xml and use DATABASE_URL locally. You can either set it in your env, or put it in a .env file and run your app locally with foreman start, which will pick this file up. This is the best way to ensure pairity between dev and prod environments, and it will test your buildSessionFactory() code.

You can even use the Heroku database locally if you desire by following this guide. Capture the Heroku DATABASE_URL and put it in your .env file. Then add the ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory args to the JDBC URL.

codefinger
  • 10,088
  • 7
  • 39
  • 51
  • It looks like buildSessionFactory() is only called when calling a resource method for the first time (a method which calls the current SessionFactory to get the current Session). I thought this method will be called instantly when pushing to heroku and then It would override the properties according to Heroku's DATABASE_URL. I already set DATABASE_URL locally and this works fine. Is there a way to call buildSessionFactory() when pushing to heroku? – Daniel May 26 '15 at 16:12
  • Okay, I managed to deploy my app on Heroku when using a configuration similar to this one: http://stackoverflow.com/questions/12045070/how-do-i-configure-hibernate-orm-on-heroku . But now the problem is that tables are not created automatically when pushing to heroku but I don't know why. I guess because the hibernate.connection information is missing in hibernate.cfg.xml – Daniel May 26 '15 at 16:59