diff --git a/pom.xml b/pom.xml
index a300d503..2ae4a614 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,18 +106,6 @@
-
- genepi
- genepi-db
- 1.2.1
-
-
- log4j
- log4j
-
-
-
-
genepi
genepi-hadoop
@@ -138,6 +126,18 @@
+
+ commons-dbutils
+ commons-dbutils
+ 1.7
+
+
+
+ commons-dbcp
+ commons-dbcp
+ 1.4
+
+
mysql
mysql-connector-java
@@ -383,12 +383,6 @@
netty-resolver-dns-native-macos
runtime
-
-
- jakarta.annotation
- jakarta.annotation-api
- compile
-
ch.qos.logback
diff --git a/src/main/java/cloudgene/mapred/apps/ApplicationRepository.java b/src/main/java/cloudgene/mapred/apps/ApplicationRepository.java
index 9b4b589a..bc2cc641 100644
--- a/src/main/java/cloudgene/mapred/apps/ApplicationRepository.java
+++ b/src/main/java/cloudgene/mapred/apps/ApplicationRepository.java
@@ -18,11 +18,11 @@
import com.amazonaws.services.s3.model.S3ObjectSummary;
import cloudgene.mapred.core.User;
+import cloudgene.mapred.database.util.DatabaseUpdater;
import cloudgene.mapred.util.GitHubException;
import cloudgene.mapred.util.GitHubUtil;
import cloudgene.mapred.util.GitHubUtil.Repository;
import cloudgene.mapred.wdl.WdlApp;
-import genepi.db.DatabaseUpdater;
import genepi.hadoop.S3Util;
import genepi.io.FileUtil;
import net.lingala.zip4j.ZipFile;
diff --git a/src/main/java/cloudgene/mapred/database/CounterDao.java b/src/main/java/cloudgene/mapred/database/CounterDao.java
index 06cfa5c9..455e6c67 100644
--- a/src/main/java/cloudgene/mapred/database/CounterDao.java
+++ b/src/main/java/cloudgene/mapred/database/CounterDao.java
@@ -8,10 +8,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.jobs.AbstractJob;
-import genepi.db.Database;
-import genepi.db.IRowMapMapper;
-import genepi.db.JdbcDataAccessObject;
public class CounterDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/CounterHistoryDao.java b/src/main/java/cloudgene/mapred/database/CounterHistoryDao.java
index 12a7c510..97aaef62 100644
--- a/src/main/java/cloudgene/mapred/database/CounterHistoryDao.java
+++ b/src/main/java/cloudgene/mapred/database/CounterHistoryDao.java
@@ -14,8 +14,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import genepi.db.Database;
-import genepi.db.JdbcDataAccessObject;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
public class CounterHistoryDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/DownloadDao.java b/src/main/java/cloudgene/mapred/database/DownloadDao.java
index 9787aae0..3d511ac6 100644
--- a/src/main/java/cloudgene/mapred/database/DownloadDao.java
+++ b/src/main/java/cloudgene/mapred/database/DownloadDao.java
@@ -8,11 +8,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.jobs.CloudgeneParameterOutput;
import cloudgene.mapred.jobs.Download;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
public class DownloadDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/JobDao.java b/src/main/java/cloudgene/mapred/database/JobDao.java
index 090e8ae3..39132ec3 100644
--- a/src/main/java/cloudgene/mapred/database/JobDao.java
+++ b/src/main/java/cloudgene/mapred/database/JobDao.java
@@ -10,14 +10,14 @@
import cloudgene.mapred.core.User;
import cloudgene.mapred.database.UserDao.UserMapper;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.jobs.AbstractJob;
import cloudgene.mapred.jobs.CloudgeneJob;
import cloudgene.mapred.jobs.CloudgeneParameterInput;
import cloudgene.mapred.jobs.CloudgeneParameterOutput;
import cloudgene.mapred.jobs.CloudgeneStep;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
public class JobDao extends JdbcDataAccessObject {
@@ -267,14 +267,19 @@ public List findAllNotRetiredJobs() {
sql.append("select * ");
sql.append("from job ");
sql.append("join `user` on job.user_id = `user`.id ");
- sql.append("where state != ? AND state != ? ");
+ sql.append("where state not in (?,?,?,?,?,?,?) ");
sql.append("order by job.id desc ");
List result = new Vector();
- Object[] params = new Object[2];
- params[0] = AbstractJob.STATE_RETIRED;
- params[1] = AbstractJob.STATE_DELETED;
+ Object[] params = new Object[7];
+ params[0] = AbstractJob.STATE_WAITING;
+ params[1] = AbstractJob.STATE_RUNNING;
+ params[2] = AbstractJob.STATE_EXPORTING;
+ params[3] = AbstractJob.STATE_RETIRED;
+ params[4] = AbstractJob.STATE_DELETED;
+ params[5] = AbstractJob.STATE_RETIRED;
+ params[6] = AbstractJob.STATE_DELETED;
try {
diff --git a/src/main/java/cloudgene/mapred/database/MessageDao.java b/src/main/java/cloudgene/mapred/database/MessageDao.java
index 67398de8..80ea1c1e 100644
--- a/src/main/java/cloudgene/mapred/database/MessageDao.java
+++ b/src/main/java/cloudgene/mapred/database/MessageDao.java
@@ -8,11 +8,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.jobs.CloudgeneStep;
import cloudgene.mapred.jobs.Message;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
public class MessageDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/ParameterDao.java b/src/main/java/cloudgene/mapred/database/ParameterDao.java
index 101b1b9f..8422d40f 100644
--- a/src/main/java/cloudgene/mapred/database/ParameterDao.java
+++ b/src/main/java/cloudgene/mapred/database/ParameterDao.java
@@ -8,15 +8,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.jobs.AbstractJob;
import cloudgene.mapred.jobs.CloudgeneParameterInput;
import cloudgene.mapred.jobs.CloudgeneParameterOutput;
import cloudgene.mapred.jobs.Download;
import cloudgene.mapred.wdl.WdlParameterInputType;
import cloudgene.mapred.wdl.WdlParameterOutputType;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
public class ParameterDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/StepDao.java b/src/main/java/cloudgene/mapred/database/StepDao.java
index c4c53e45..094318c3 100644
--- a/src/main/java/cloudgene/mapred/database/StepDao.java
+++ b/src/main/java/cloudgene/mapred/database/StepDao.java
@@ -8,13 +8,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.jobs.CloudgeneJob;
import cloudgene.mapred.jobs.CloudgeneStep;
import cloudgene.mapred.jobs.Message;
import cloudgene.mapred.steps.EmptyStep;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
public class StepDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/TemplateDao.java b/src/main/java/cloudgene/mapred/database/TemplateDao.java
index b0d6ef06..ee679603 100644
--- a/src/main/java/cloudgene/mapred/database/TemplateDao.java
+++ b/src/main/java/cloudgene/mapred/database/TemplateDao.java
@@ -9,9 +9,9 @@
import org.slf4j.LoggerFactory;
import cloudgene.mapred.core.Template;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
public class TemplateDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/UserDao.java b/src/main/java/cloudgene/mapred/database/UserDao.java
index 549d5aa9..7b94868a 100644
--- a/src/main/java/cloudgene/mapred/database/UserDao.java
+++ b/src/main/java/cloudgene/mapred/database/UserDao.java
@@ -9,10 +9,10 @@
import org.slf4j.LoggerFactory;
import cloudgene.mapred.core.User;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IRowMapper;
+import cloudgene.mapred.database.util.JdbcDataAccessObject;
import cloudgene.mapred.util.PublicUser;
-import genepi.db.Database;
-import genepi.db.IRowMapper;
-import genepi.db.JdbcDataAccessObject;
public class UserDao extends JdbcDataAccessObject {
diff --git a/src/main/java/cloudgene/mapred/database/updates/BcryptHashUpdate.java b/src/main/java/cloudgene/mapred/database/updates/BcryptHashUpdate.java
index d387793b..d63addb6 100644
--- a/src/main/java/cloudgene/mapred/database/updates/BcryptHashUpdate.java
+++ b/src/main/java/cloudgene/mapred/database/updates/BcryptHashUpdate.java
@@ -8,8 +8,8 @@
import cloudgene.mapred.core.User;
import cloudgene.mapred.database.UserDao;
-import genepi.db.Database;
-import genepi.db.IUpdateListener;
+import cloudgene.mapred.database.util.Database;
+import cloudgene.mapred.database.util.IUpdateListener;
public class BcryptHashUpdate implements IUpdateListener {
diff --git a/src/main/java/cloudgene/mapred/database/util/AbstractDatabaseConnector.java b/src/main/java/cloudgene/mapred/database/util/AbstractDatabaseConnector.java
new file mode 100644
index 00000000..2bb0b28c
--- /dev/null
+++ b/src/main/java/cloudgene/mapred/database/util/AbstractDatabaseConnector.java
@@ -0,0 +1,81 @@
+package cloudgene.mapred.database.util;
+
+import org.apache.commons.dbcp.BasicDataSource;
+
+public abstract class AbstractDatabaseConnector implements DatabaseConnector {
+
+ private int maxActive = 10;
+
+ private int maxWait = 10000;
+
+ private boolean defaultAutoCommit = true;
+
+ private boolean testWhileIdle = true;
+
+ private int minEvictableIdleTimeMillis = 1800000;
+
+ private int timeBetweenEvictionRunsMillis = 1800000;
+
+ protected BasicDataSource createDataSource() {
+
+ BasicDataSource dataSource = new BasicDataSource();
+ dataSource.setMaxActive(maxActive);
+ dataSource.setMaxWait(maxWait);
+ dataSource.setMaxIdle(maxActive);
+ dataSource.setDefaultAutoCommit(defaultAutoCommit);
+ dataSource.setTestWhileIdle(testWhileIdle);
+ dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ return dataSource;
+
+ }
+
+ public int getMaxActive() {
+ return maxActive;
+ }
+
+ public void setMaxActive(int maxActive) {
+ this.maxActive = maxActive;
+ }
+
+ public int getMaxWait() {
+ return maxWait;
+ }
+
+ public void setMaxWait(int maxWait) {
+ this.maxWait = maxWait;
+ }
+
+ public boolean isDefaultAutoCommit() {
+ return defaultAutoCommit;
+ }
+
+ public void setDefaultAutoCommit(boolean defaultAutoCommit) {
+ this.defaultAutoCommit = defaultAutoCommit;
+ }
+
+ public boolean isTestWhileIdle() {
+ return testWhileIdle;
+ }
+
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ }
+
+ public int getMinEvictableIdleTimeMillis() {
+ return minEvictableIdleTimeMillis;
+ }
+
+ public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+ this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ }
+
+ public int getTimeBetweenEvictionRunsMillis() {
+ return timeBetweenEvictionRunsMillis;
+ }
+
+ public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ }
+
+}
diff --git a/src/main/java/cloudgene/mapred/database/util/Database.java b/src/main/java/cloudgene/mapred/database/util/Database.java
new file mode 100644
index 00000000..c7c4b85b
--- /dev/null
+++ b/src/main/java/cloudgene/mapred/database/util/Database.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2016 Lukas Forer and Sebastian Schönherr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ ******************************************************************************/
+
+package cloudgene.mapred.database.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Database
+ *
+ * @author Lukas Forer
+ *
+ */
+public class Database {
+
+ private static final Logger log = LoggerFactory.getLogger(Database.class);
+
+ private DatabaseConnector connector;
+
+ public Database() {
+ }
+
+ public void connect(DatabaseConnector connector) throws SQLException {
+ this.connector = connector;
+ try {
+
+ connector.connect();
+
+ log.debug("Establish connection successful");
+
+ fireChangeEvent(DatabaseListener.AFTER_CONNECTION);
+ } catch (SQLException e) {
+ log.error("Establish connection failed", e);
+ throw e;
+ }
+ }
+
+ public void disconnect() throws SQLException {
+
+ if (connector != null) {
+
+ if (connector.getDataSource() != null) {
+
+ log.debug("Disconnecting");
+
+ fireChangeEvent(DatabaseListener.BEFORE_DISCONNECTION);
+ try {
+
+ connector.disconnect();
+
+ log.debug("Disconnection successful");
+ fireChangeEvent(DatabaseListener.AFTER_DISCONNECTION);
+ } catch (SQLException e) {
+ log.error("Disconnection failed", e);
+ throw e;
+ }
+ }
+
+ }
+ }
+
+ public boolean isConnected() {
+ if (connector != null) {
+ return !connector.getDataSource().isClosed();
+ } else {
+ return false;
+ }
+ }
+
+ public BasicDataSource getDataSource() {
+ return connector.getDataSource();
+ }
+
+ /*
+ * ListenerSupport
+ */
+
+ private Vector listeners = new Vector();
+
+ public void addDatabaseListener(DatabaseListener listener) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener);
+ }
+ }
+
+ public void removeDatabaseListener(DatabaseListener listener) {
+ listeners.remove(listener);
+ }
+
+ private void fireChangeEvent(int event) {
+ Iterator iter = listeners.iterator();
+ while (iter.hasNext()) {
+ (iter.next()).onDatabaseEvent(event);
+ }
+ }
+
+ public void executeSQL(InputStream is) throws SQLException, IOException,
+ URISyntaxException {
+ connector.executeSQL(is);
+ }
+
+ public DatabaseConnector getConnector() {
+ return connector;
+ }
+
+}
diff --git a/src/main/java/cloudgene/mapred/database/util/DatabaseConnector.java b/src/main/java/cloudgene/mapred/database/util/DatabaseConnector.java
new file mode 100644
index 00000000..d95978e5
--- /dev/null
+++ b/src/main/java/cloudgene/mapred/database/util/DatabaseConnector.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2016 Lukas Forer and Sebastian Schönherr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ ******************************************************************************/
+
+package cloudgene.mapred.database.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.sql.SQLException;
+
+import org.apache.commons.dbcp.BasicDataSource;
+
+public interface DatabaseConnector {
+
+ public void connect() throws SQLException;
+
+ public void disconnect() throws SQLException;
+
+ public BasicDataSource getDataSource();
+
+ public void executeSQL(InputStream is) throws SQLException, IOException,
+ URISyntaxException;
+
+ public String getSchema();
+
+ boolean existsTable(String table) throws SQLException;
+}
+
diff --git a/src/main/java/cloudgene/mapred/database/util/DatabaseConnectorFactory.java b/src/main/java/cloudgene/mapred/database/util/DatabaseConnectorFactory.java
index 1bd9a1eb..b49f7cbd 100644
--- a/src/main/java/cloudgene/mapred/database/util/DatabaseConnectorFactory.java
+++ b/src/main/java/cloudgene/mapred/database/util/DatabaseConnectorFactory.java
@@ -2,9 +2,8 @@
import java.util.Map;
-import genepi.db.DatabaseConnector;
-import genepi.db.h2.H2Connector;
-import genepi.db.mysql.MySqlConnector;
+import cloudgene.mapred.database.util.h2.H2Connector;
+import cloudgene.mapred.database.util.mysql.MySqlConnector;
public class DatabaseConnectorFactory {
diff --git a/src/main/java/cloudgene/mapred/database/util/DatabaseListener.java b/src/main/java/cloudgene/mapred/database/util/DatabaseListener.java
new file mode 100644
index 00000000..96fabb57
--- /dev/null
+++ b/src/main/java/cloudgene/mapred/database/util/DatabaseListener.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2016 Lukas Forer and Sebastian Schönherr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ ******************************************************************************/
+
+package cloudgene.mapred.database.util;
+
+public interface DatabaseListener {
+
+ public static final int AFTER_CONNECTION = 1;
+ public static final int AFTER_DISCONNECTION = 2;
+ public static final int BEFORE_DISCONNECTION = 3;
+ public static final int ERROR = 4;
+
+ public void onDatabaseEvent(int event);
+
+}
diff --git a/src/main/java/cloudgene/mapred/database/util/DatabaseUpdater.java b/src/main/java/cloudgene/mapred/database/util/DatabaseUpdater.java
new file mode 100644
index 00000000..7d91c48e
--- /dev/null
+++ b/src/main/java/cloudgene/mapred/database/util/DatabaseUpdater.java
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2016 Lukas Forer and Sebastian Schönherr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ ******************************************************************************/
+
+package cloudgene.mapred.database.util;
+
+import genepi.io.FileUtil;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DatabaseUpdater {
+
+ protected static final Logger log = LoggerFactory.getLogger(DatabaseUpdater.class);
+
+ private DatabaseConnector connector;
+
+ private Database database;
+
+ private String oldVersion;
+
+ private String currentVersion;
+
+ private String filename;
+
+ private InputStream updateFileAsStream;
+
+ private boolean needUpdate = false;
+
+ private Map listeners = new HashMap();
+
+ public DatabaseUpdater(Database database, String filename, InputStream updateFileAsStream, String currentVersion) {
+
+ this.filename = filename;
+ this.database = database;
+ this.connector = database.getConnector();
+ this.updateFileAsStream = updateFileAsStream;
+ this.currentVersion = currentVersion;
+
+ if (isVersionTableAvailable(database)) {
+
+ oldVersion = readVersionDB();
+ log.info("Read current DB version: " + oldVersion);
+
+ // should not happen, since an entry is created when metadata table
+ // exists
+ if (oldVersion == null) {
+ oldVersion = readVersion(filename);
+ log.info("Read curent version from DB was not successful, read it from file: " + oldVersion);
+ }
+
+ } else {
+ // check also file for backwards compatibility
+ oldVersion = readVersion(filename);
+ log.info("Read current version from file: " + oldVersion);
+ }
+ log.info("Current app version: " + currentVersion);
+ needUpdate = (compareVersion(currentVersion, oldVersion) > 0);
+
+ }
+
+ public void addUpdate(String version, IUpdateListener listener) {
+ listeners.put(version, listener);
+ }
+
+ public boolean updateDB() {
+
+ if (needUpdate()) {
+ log.info("Database needs update...");
+ if (!update()) {
+ log.error("Updating database failed.");
+ try {
+ database.disconnect();
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return false;
+ }
+ log.info("Update database done.");
+ } else {
+ log.info("Database is already up-to-date.");
+ if (!isVersionTableAvailable(database)) {
+ writeVersion(currentVersion);
+ }
+ }
+
+ String dbVersion = readVersionDB();
+ if (!dbVersion.equals(currentVersion)) {
+ log.error("App version (v" + currentVersion + ") and DB version (v" + dbVersion
+ + ") does not match. Update Application to latest version.");
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean update() {
+ if (needUpdate) {
+
+ log.info("Updating database from " + oldVersion + " to " + currentVersion + "...");
+
+ try {
+ readAndPrepareSqlClasspath(updateFileAsStream, oldVersion, currentVersion);
+ } catch (IOException | URISyntaxException | SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ // check if DB version match with Main version
+ if (isVersionTableAvailable(database)) {
+ String currentDBVersion = readVersionDB();
+ if ((compareVersion(currentVersion, currentDBVersion) > 0)) {
+ writeVersion(currentVersion);
+ }
+ } else {
+ writeVersion(currentVersion);
+ }
+
+ log.info("Updating database was successful.");
+
+ }
+
+ return true;
+
+ }
+
+ public boolean needUpdate() {
+ return needUpdate;
+ }
+
+ public void writeVersion(String newVersion) {
+
+ try {
+
+ if (!isVersionTableAvailable(database)) {
+ createVersionTable(database);
+ }
+
+ Connection connection = connector.getDataSource().getConnection();
+ PreparedStatement ps = connection.prepareStatement("INSERT INTO database_versions (version) VALUES (?)");
+ ps.setString(1, newVersion);
+ ps.executeUpdate();
+ log.info("Version in DB updated to: " + newVersion);
+
+ if (new File(filename).exists()) {
+ FileUtil.deleteFile(filename);
+ log.info("Deleted version.txt on file system.");
+ }
+
+ connection.close();
+
+ } catch (SQLException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+
+ public String readVersion(String versionFile) {
+
+ File file = new File(versionFile);
+
+ if (file.exists()) {
+
+ try {
+
+ return readFileAsString(versionFile);
+
+ } catch (Exception e) {
+
+ return "0.0.0";
+
+ }
+
+ } else {
+
+ return "0.0.0";
+
+ }
+
+ }
+
+ public String readVersionDB() {
+
+ String version = null;
+
+ try {
+ Connection connection = connector.getDataSource().getConnection();
+ PreparedStatement ps = connection.prepareStatement(
+ "select version from database_versions where updated_on = (SELECT MAX(updated_on) from database_versions) "
+ + "order by updated_on, id DESC");
+ ResultSet result = ps.executeQuery();
+
+ if (result.next()) {
+ version = result.getString(1);
+ }
+
+ connection.close();
+
+ } catch (SQLException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ return version;
+ }
+
+ public static String readFileAsString(String filename) throws java.io.IOException, URISyntaxException {
+
+ InputStream is = new FileInputStream(filename);
+
+ DataInputStream in = new DataInputStream(is);
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ String strLine;
+ StringBuilder builder = new StringBuilder();
+ while ((strLine = br.readLine()) != null) {
+ // builder.append("\n");
+ builder.append(strLine);
+ }
+
+ in.close();
+
+ return builder.toString();
+ }
+
+ public String readAndPrepareSqlClasspath(InputStream filestream, String minVersion, String maxVersion)
+ throws java.io.IOException, URISyntaxException, SQLException {
+
+ DataInputStream in = new DataInputStream(filestream);
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ String strLine;
+ StringBuilder builder = new StringBuilder();
+ boolean reading = false;
+ String version = null;
+
+ while ((strLine = br.readLine()) != null) {
+
+ if (strLine.startsWith("--")) {
+
+ if (builder.length() > 0) {
+ executeSQLFile(builder.toString(), version);
+ builder.setLength(0);
+ IUpdateListener listener = listeners.get(version);
+ if (listener != null) {
+ listener.afterUpdate(database);
+ }
+ }
+
+ version = strLine.replace("--", "").trim();
+ reading = (compareVersion(version, minVersion) > 0 && compareVersion(version, maxVersion) <= 0);
+ if (reading) {
+ log.info("Loading SQL update for version " + version);
+ IUpdateListener listener = listeners.get(version);
+ if (listener != null) {
+ listener.beforeUpdate(database);
+ }
+ }
+
+ }
+
+ if (reading) {
+ builder.append("\n");
+ builder.append(strLine);
+ }
+ }
+
+ // last block
+ executeSQLFile(builder.toString(), version);
+
+ in.close();
+
+ return builder.toString();
+
+ }
+
+ public void executeSQLFile(String sqlContent, String version) throws SQLException {
+
+ if (sqlContent.length() > 0) {
+ Connection connection;
+ connection = connector.getDataSource().getConnection();
+ PreparedStatement ps = connection.prepareStatement(sqlContent);
+ ps.executeUpdate();
+ connection.close();
+ log.info("DB SQL Update " + version + " finished");
+ writeVersion(version);
+ }
+
+ }
+
+ public static int compareVersion(String version1, String version2) {
+
+ String parts1[] = version1.split("-", 2);
+ String parts2[] = version2.split("-", 2);
+
+ String tiles1[] = parts1[0].split("\\.");
+ String tiles2[] = parts2[0].split("\\.");
+
+ for (int i = 0; i < tiles1.length; i++) {
+ int number1 = Integer.parseInt(tiles1[i].trim());
+ int number2 = Integer.parseInt(tiles2[i].trim());
+
+ if (number1 != number2) {
+
+ return number1 > number2 ? 1 : -1;
+
+ }
+
+ }
+
+ if (parts1.length > 1) {
+ if (parts2.length > 1) {
+ return parts1[1].compareTo(parts2[1]);
+ } else {
+ return -1;
+ }
+ } else {
+ if (parts2.length > 1) {
+ return 1;
+ }
+ }
+
+ return 0;
+
+ }
+
+ public boolean isVersionTableAvailable(Database database) {
+ try {
+ return database.getConnector().existsTable("database_versions");
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public void createVersionTable(Database database) {
+ try {
+ Connection connection = connector.getDataSource().getConnection();
+ String statement = "create table database_versions ( \r\n"
+ + " id integer not null auto_increment primary key,\r\n"
+ + " version varchar(255) not null,\r\n"
+ + " updated_on timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP \r\n" + ")";
+ PreparedStatement ps = connection.prepareStatement(statement);
+ ps.executeUpdate();
+ connection.close();
+ log.info("Table database_versions created.");
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/main/java/cloudgene/mapred/database/util/Fixtures.java b/src/main/java/cloudgene/mapred/database/util/Fixtures.java
index 5ade48c6..c31099c7 100644
--- a/src/main/java/cloudgene/mapred/database/util/Fixtures.java
+++ b/src/main/java/cloudgene/mapred/database/util/Fixtures.java
@@ -8,7 +8,6 @@
import cloudgene.mapred.database.TemplateDao;
import cloudgene.mapred.database.UserDao;
import cloudgene.mapred.util.HashUtil;
-import genepi.db.Database;
public class Fixtures {
diff --git a/src/main/java/cloudgene/mapred/database/util/GroupedListHandler.java b/src/main/java/cloudgene/mapred/database/util/GroupedListHandler.java
new file mode 100644
index 00000000..cea1f679
--- /dev/null
+++ b/src/main/java/cloudgene/mapred/database/util/GroupedListHandler.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2016 Lukas Forer and Sebastian Schönherr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ ******************************************************************************/
+
+package cloudgene.mapred.database.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.commons.dbutils.ResultSetHandler;
+
+public class GroupedListHandler implements ResultSetHandler