Commit addc6a67 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

java code uses flyway to manage migration scripts

parent e74860da
<?xml version="1.0"?> <?xml version="1.0"?>
<project <project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>lcsb.mapviewer</groupId> <groupId>lcsb.mapviewer</groupId>
...@@ -75,8 +76,8 @@ ...@@ -75,8 +76,8 @@
<dependency> <dependency>
<groupId>org.sbml.jsbml</groupId> <groupId>org.sbml.jsbml</groupId>
<artifactId>jsbml</artifactId> <artifactId>jsbml</artifactId>
<version>1.2</version> <version>1.3.1</version>
<!-- for now we use lower version of log4j and this one introduce some <!-- for now we use lower version of log4j and this one introduce some
problem with tomcat loggin --> problem with tomcat loggin -->
<exclusions> <exclusions>
<exclusion> <exclusion>
...@@ -91,6 +92,10 @@ ...@@ -91,6 +92,10 @@
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId> <artifactId>log4j-1.2-api</artifactId>
</exclusion> </exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
......
<project <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"> http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>lcsb.mapviewer</groupId> <groupId>lcsb.mapviewer</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<version>1.0</version> <version>1.0</version>
</parent> </parent>
<artifactId>persist</artifactId> <artifactId>persist</artifactId>
<name>MapViewer persist</name> <name>MapViewer persist</name>
<description>Data Access Interface to the model</description> <description>Data Access Interface to the model</description>
<dependencies> <dependencies>
<!-- dependency from the MapViewer model --> <!-- https://mvnrepository.com/artifact/org.flywaydb/flyway-core -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>${flyway.version}</version>
</dependency>
<!-- dependency from the MapViewer model -->
<dependency> <dependency>
<groupId>lcsb.mapviewer</groupId> <groupId>lcsb.mapviewer</groupId>
<artifactId>model</artifactId> <artifactId>model</artifactId>
<version>1.0</version> <version>1.0</version>
</dependency> </dependency>
<!-- apache ftp --> <!-- apache ftp -->
<dependency> <dependency>
<groupId>commons-net</groupId> <groupId>commons-net</groupId>
<artifactId>commons-net</artifactId> <artifactId>commons-net</artifactId>
<version>${commons-net.version}</version> <version>${commons-net.version}</version>
</dependency> </dependency>
<!-- Hibernate --> <!-- Hibernate -->
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId> <artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version> <version>${hibernate.version}</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>xml-apis</artifactId> <artifactId>xml-apis</artifactId>
<groupId>xml-apis</groupId> <groupId>xml-apis</groupId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<!-- Library excluded from above; it was in conflict with Xerces --> <!-- Library excluded from above; it was in conflict with Xerces -->
<dependency> <dependency>
<groupId>xml-apis</groupId> <groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId> <artifactId>xml-apis</artifactId>
<version>${xml-apis.version}</version> <version>${xml-apis.version}</version>
</dependency> </dependency>
<!-- Log4J --> <!-- Log4J -->
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>log4j</groupId>
<artifactId>log4j</artifactId> <artifactId>log4j</artifactId>
<version>${log4j.version}</version> <version>${log4j.version}</version>
</dependency> </dependency>
<!-- Spring --> <!-- Spring -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId> <artifactId>spring-core</artifactId>
<version>${springframework.version}</version> <version>${springframework.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId> <artifactId>spring-context</artifactId>
...@@ -84,28 +90,28 @@ ...@@ -84,28 +90,28 @@
</dependency> </dependency>
<!-- spring module used for conneting orm (hibernate in our case) --> <!-- spring module used for conneting orm (hibernate in our case) -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId> <artifactId>spring-orm</artifactId>
<version>${springframework.version}</version> <version>${springframework.version}</version>
</dependency> </dependency>
<!-- spring module used for password encoding --> <!-- spring module used for password encoding -->
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId> <artifactId>spring-security-taglibs</artifactId>
<version>${springframework.security.version}</version> <version>${springframework.security.version}</version>
</dependency> </dependency>
<!-- spring module used for testing --> <!-- spring module used for testing -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
<version>${springframework.version}</version> <version>${springframework.version}</version>
</dependency> </dependency>
<!-- postgres connector --> <!-- postgres connector -->
<dependency> <dependency>
<groupId>postgresql</groupId> <groupId>postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
...@@ -122,16 +128,16 @@ ...@@ -122,16 +128,16 @@
<groupId>cglib</groupId> <groupId>cglib</groupId>
<artifactId>cglib</artifactId> <artifactId>cglib</artifactId>
<version>${cglib.version}</version> <version>${cglib.version}</version>
</dependency> </dependency>
<!-- Gson --> <!-- Gson -->
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>${gson.version}</version> <version>${gson.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package lcsb.mapviewer.persist;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.flywaydb.core.Flyway;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.ScriptException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class CustomDatabasePopulator implements DatabasePopulator {
Logger logger = Logger.getLogger(CustomDatabasePopulator.class);
private DataSource dataSource;
// public CustomDatabasePopulator(DataSource source) {
// logger.debug("Constructor");
// logger.debug(source);
// }
@Override
public void populate(Connection connection) throws SQLException, ScriptException {
logger.debug(dataSource);
ComboPooledDataSource source = (ComboPooledDataSource) dataSource;
String url = source.getJdbcUrl();
String user = source.getUser();
String password = source.getPassword();
Flyway flyway = new Flyway();
flyway.setDataSource(url, user, password);
flyway.baseline();
flyway.migrate();
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}
...@@ -9,12 +9,17 @@ import javax.management.MBeanServer; ...@@ -9,12 +9,17 @@ import javax.management.MBeanServer;
import javax.management.ObjectName; import javax.management.ObjectName;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.flywaydb.core.Flyway;
import org.hibernate.SQLQuery; import org.hibernate.SQLQuery;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.jmx.StatisticsService; import org.hibernate.jmx.StatisticsService;
import org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import lcsb.mapviewer.common.exception.InvalidStateException; import lcsb.mapviewer.common.exception.InvalidStateException;
/** /**
...@@ -33,275 +38,275 @@ import lcsb.mapviewer.common.exception.InvalidStateException; ...@@ -33,275 +38,275 @@ import lcsb.mapviewer.common.exception.InvalidStateException;
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class DbUtils extends Observable { public class DbUtils extends Observable {
/**
* Default class logger.
*/
private static Logger logger = Logger.getLogger(DbUtils.class);
/** /**
* Hibernate session factory. * Default class logger.
*/ */
@Autowired private static Logger logger = Logger.getLogger(DbUtils.class);
private SessionFactory sessionFactory;
/**
* Hibernate session factory.
*/
@Autowired
private SessionFactory sessionFactory;
/** /**
* Service used for connection statistics. * Service used for connection statistics.
*/ */
private StatisticsService statisticsService; private StatisticsService statisticsService;
/** /**
* This flag indicates if the object was initialized or not. * This flag indicates if the object was initialized or not.
* *
* @see #init() * @see #init()
*/ */
private boolean initialized = false; private boolean initialized = false;
/**
* Bean used for statistics.
*/
private MBeanServer mbeanServer;
/** /**
* Static map containing opened custom sessions. This object is also used for * Bean used for statistics.
* synchronization between threads when accessing informations about sessions. */
*/ private MBeanServer mbeanServer;
private static Map<Long, Session> sessionForThread = new HashMap<Long, Session>();
/** /**
* This determines if every add/update/delete operation should be flushed (for * Static map containing opened custom sessions. This object is also used for
* specific {@link Thread}). There are few drawbacks of this approach: * synchronization between threads when accessing informations about sessions.
* <ol> */
* <li>when autoflushing is set to false, then the data consistency could be private static Map<Long, Session> sessionForThread = new HashMap<Long, Session>();
* broken (even in the same thread/transaction)</li>,
* <li>we have to automatically take care of the flushing, therefore there
* might be some problems with long transactions.</li>
* </ol>
*/
private static Map<Long, Boolean> autoFlushForThread = new HashMap<>();
/** /**
* This method initialize services responsible for statistics. * This determines if every add/update/delete operation should be flushed (for
*/ * specific {@link Thread}). There are few drawbacks of this approach:
private void init() { * <ol>
if (!initialized) { * <li>when autoflushing is set to false, then the data consistency could be
if (SpringApplicationContext.getApplicationContext().containsBean("mbeanServer")) { * broken (even in the same thread/transaction)</li>,
logger.info("Hibernate statistics turned on"); * <li>we have to automatically take care of the flushing, therefore there might
mbeanServer = SpringApplicationContext.getApplicationContext().getBean(MBeanServer.class); * be some problems with long transactions.</li>
statisticsService = new StatisticsService(); * </ol>
statisticsService.setSessionFactory(sessionFactory); */
statisticsService.setStatisticsEnabled(true); private static Map<Long, Boolean> autoFlushForThread = new HashMap<>();
ObjectName objectName;
try {
objectName = new ObjectName("org.hibernate:name=HibernateStatistics");
mbeanServer.registerMBean(statisticsService, objectName); /**
} catch (Exception e) { * This method initialize services responsible for statistics.
logger.error(e, e); */
} private void init() {
} else { if (!initialized) {
logger.info("Hibernate statistics turned off"); if (SpringApplicationContext.getApplicationContext().containsBean("mbeanServer")) {
} logger.info("Hibernate statistics turned on");
} mbeanServer = SpringApplicationContext.getApplicationContext().getBean(MBeanServer.class);
initialized = true; statisticsService = new StatisticsService();
statisticsService.setSessionFactory(sessionFactory);
statisticsService.setStatisticsEnabled(true);
ObjectName objectName;
try {
objectName = new ObjectName("org.hibernate:name=HibernateStatistics");
} mbeanServer.registerMBean(statisticsService, objectName);
} catch (Exception e) {
logger.error(e, e);
}
} else {
logger.info("Hibernate statistics turned off");
}
}
initialized = true;
/** }
* Executes sql query given in the parameter.
*
* @param query
* sql query to be executed
* @return The number of entities updated or deleted.
*/
public int executeSqlQuery(String query) {
return executeSqlQuery(query, new HashMap<String, Object>());
}
/** /**
* Executes sql query given in the parameter. * Executes sql query given in the parameter.
* *
* @param query * @param query
* sql query to be executed * sql query to be executed
* @param params * @return The number of entities updated or deleted.
* map of parameters used in the query */
* @return The number of entities updated or deleted. public int executeSqlQuery(String query) {
*/ return executeSqlQuery(query, new HashMap<String, Object>());
public int executeSqlQuery(String query, Map<String, Object> params) { }
SQLQuery sqlQuery = getSessionFactory().getCurrentSession().createSQLQuery(query);
for (Entry<String, Object> entry : params.entrySet()) { /**
sqlQuery.setParameter(entry.getKey(), entry.getValue()); * Executes sql query given in the parameter.
} *
return sqlQuery.executeUpdate(); * @param query
} * sql query to be executed
* @param params
* map of parameters used in the query
* @return The number of entities updated or deleted.
*/
public int executeSqlQuery(String query, Map<String, Object> params) {
SQLQuery sqlQuery = getSessionFactory().getCurrentSession().createSQLQuery(query);
/** for (Entry<String, Object> entry : params.entrySet()) {
* Returns hibernate session for current thread. sqlQuery.setParameter(entry.getKey(), entry.getValue());
* }
* @return session for the current thread return sqlQuery.executeUpdate();
*/ }
public Session getSessionForCurrentThread() {
Long id = Thread.currentThread().getId();
Session session = null;
synchronized (sessionForThread) {
session = sessionForThread.get(id);
}
if (session == null) {
session = sessionFactory.getCurrentSession();
}
return session;
}
/** /**
* Closes custom session for current thread. * Returns hibernate session for current thread.
*/ *
public void closeSessionForCurrentThread() { * @return session for the current thread
Long id = Thread.currentThread().getId(); */
Session session = null; public Session getSessionForCurrentThread() {
synchronized (sessionForThread) { Long id = Thread.currentThread().getId();
session = sessionForThread.get(id); Session session = null;
sessionForThread.remove(id); synchronized (sessionForThread) {
} session = sessionForThread.get(id);
if (session != null) { }
logger.debug("Closing session for thread: " + id); if (session == null) {
session.getTransaction().commit(); session = sessionFactory.getCurrentSession();
}
return session;
}
session.close(); /**
int counter = -1; * Closes custom session for current thread.
synchronized (sessionForThread) { */
sessionForThread.remove(id); public void closeSessionForCurrentThread() {
counter = sessionForThread.size(); Long id = Thread.currentThread().getId();
} Session session = null;
synchronized (autoFlushForThread) { synchronized (sessionForThread) {
autoFlushForThread.remove(id); session = sessionForThread.get(id);
} sessionForThread.remove(id);
setChanged(); }
notifyObservers(counter); if (session != null) {
logger.debug("Session closed for thread: " + id); logger.debug("Closing session for thread: " + id);
} session.getTransaction().commit();
}
/** session.close();
* Creates custom session for current thread. int counter = -1;
*/ synchronized (sessionForThread) {
public void createSessionForCurrentThread() { sessionForThread.remove(id);
Long id = Thread.currentThread().getId(); counter = sessionForThread.size();
Session session = null; }
synchronized (sessionForThread) {