23

I tried to run flyway in my application before hibernate is hooking in on my JBoss AS 7.1. I tried with an @javax.ejb.Startup annotation, but this gets executed AFTER Hibernate is initialized and the database scheme is checked.

So as far as I understand we can use a CDI Extension which hooks in before Hibernate is initialized. Is there some support for that out of the box for flyway? And if not, has anyone tried to do this before?

Dominik Obermaier
  • 5,610
  • 4
  • 34
  • 45
  • 1
    I don't think there's a J2EE standard event which happens early enough for this. You would have to hook in to container-specific interfaces. I have no idea if anyone's done that for Flyway, sorry. Have you considered doing it as part of your deployment or start script instead of application startup? – Tom Anderson Jun 17 '12 at 14:09
  • @TomAnderson I have considered to do the flyway action in my deployment script, I have to use the Command Line Flyway Tool for that. It is not clear from the documentation if it supports Java Migrations, too, so I guess I just have to try that ;) I am sure there is a way to achieve this on application startup, because it is possible with Liquibase (see https://github.com/aaronwalker/liquibase/commit/5be42a6779b2bef95e2d02d8703aceec91aedb59). I tried something similar, but unfortunately it does not work on my machine.... – Dominik Obermaier Jun 17 '12 at 14:15
  • 1
    @DominikObermaier Yes, Flyway Command Line does support Java migrations. They can be shipped as jar files inside the /jars folder. – Axel Fontaine Jun 17 '12 at 21:06

2 Answers2

39

Ok I finally found out how to do this: I had to use the Hibernate Integration API. This is the whole code I had to write:

public class FlywayIntegrator implements Integrator {

  @Override
  public void integrate(final Configuration configuration, final SessionFactoryImplementor sessionFactoryImplementor, final SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
    final Flyway flyway = new Flyway();

    flyway.setDataSource(....);
    flyway.migrate();
  }

  @Override
  public void integrate(final MetadataImplementor metadataImplementor, final SessionFactoryImplementor sessionFactoryImplementor, final SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
    //no-op
  }

  @Override
  public void disintegrate(final SessionFactoryImplementor sessionFactoryImplementor, final SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
    //no-op
  }
}

If anyone is interested in more details, I created a github project which demonstrates that: https://github.com/dobermai/Hibernate-Flyway-Integration

kryger
  • 12,906
  • 8
  • 44
  • 65
Dominik Obermaier
  • 5,610
  • 4
  • 34
  • 45
  • 2
    Thank you for posting your solution Dominik. I read through your conversation with Scott etc in the jboss IRC channel and it led me here - it's great that you've created a githib project to demonstrate it too. – user1180316 Nov 15 '12 at 20:44
  • 4
    Thanks a lot. This really helped me. To get a data source from JBoss in the Integrator context use this: DataSource dataSource = InitialContext.doLookup("java:jboss/datasources/your-ds"); – homaxto Mar 15 '13 at 13:05
  • It would be really great if it was possible to do this right from the `configuration`, `sessionFactoryImplementor` or `sessionFactoryServiceRegistry`. I've poked around and can't find the datasource or it's JNDI name. :(. – danieljimenez Dec 17 '14 at 17:49
  • How did you manage to get Hibernate to load the integrator? Did you have to add an entry to the module.xml file as mentioned in the chat protocol here: http://echelog.com/logs/browse/jboss-as7/1342562400? – Markus Roth Jul 13 '15 at 09:56
  • Is it run fast on your code guys? Here is very slow after 40 migrations files. – John John Pichler Sep 29 '17 at 11:13
1

CDI defines its own lifecycle which is executed when an applications starts / stops. (Shouldn't you know about it already: This is a good place to learn about the basic mechanism.)

The problem - to my best knowledge - is that the Hibernate initialization process is not directly linked to the CDI startup. This means that I'm not sure if its safe to rely on a relation between Hibernate & CDI "events". There is certainly nothing like a CDI-Event HibernateInitialized.

Having said this, I'd give it a try :) You should implement a simple extension that hooks up at BeforeBeanDiscovery, which is as early as it gets.

This online presentation gives an overview about the different CDI events and their order. It's in German, unfortunately.

Jan Groth
  • 14,039
  • 5
  • 40
  • 55
  • 1
    Thanks, I already figured out, that the BeforeBeanDiscovery Event is thrown after Hibernate is initialized. So I guess it is not possible to hook in before Hibernate gets initialized (at least not with CDI, perhaps there is something AS specific?). – Dominik Obermaier Jun 19 '12 at 11:07