From 8062085148d5820daeca8f4b4e7643daf6411911 Mon Sep 17 00:00:00 2001
From: Nikolaus Krismer <niko@krismer.de>
Date: Thu, 27 Mar 2014 14:37:25 +0100
Subject: [PATCH] reworked database connection closing/opening (no more open
 connections should remain after testing now)

---
 .../inf/isochrone/algorithm/Isochrone.java    |  36 ++-
 .../inf/isochrone/algorithm/MDijkstra.java    |   9 +-
 .../unibz/inf/isochrone/algorithm/MineX.java  |  13 +-
 .../unibz/inf/isochrone/algorithm/MrneX.java  |  21 +-
 .../inf/isochrone/config/ConfigDataset.java   |   2 +-
 .../inf/isochrone/config/ConfigIsochrone.java |  10 +-
 .../inf/isochrone/db/ConnectionFactory.java   |  43 ++-
 .../it/unibz/inf/isochrone/db/Database.java   |  10 +-
 .../it/unibz/inf/isochrone/util/Query.java    |   6 +-
 .../it/unibz/inf/isoga/db/DatabaseWeb.java    |   2 +-
 .../java/it/unibz/inf/isoga/db/DbUtility.java | 292 +++++++++---------
 .../inf/isoga/service/AbstractService.java    |   6 +-
 .../inf/isoga/service/ServiceIsochrone.java   |  12 +-
 .../unibz/inf/isochrone/db/DatabaseTest.java  |  16 +-
 .../isochrone/network/AlgorithmHelper.java    |  11 +-
 .../inf/isochrone/network/ComparisonTest.java |  25 +-
 16 files changed, 310 insertions(+), 204 deletions(-)

diff --git a/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java b/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java
index 7825d9f4..9b9f43e1 100644
--- a/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java
+++ b/src/main/java/it/unibz/inf/isochrone/algorithm/Isochrone.java
@@ -30,8 +30,7 @@ public abstract class Isochrone {
 	private final Query query;
 	private final PriorityQueue<Node> queue;
 	private Set<Integer> codes;
-
-	protected Database<ConfigDataset> db;
+	protected Database database;
 
 	// Constructors
 
@@ -39,17 +38,33 @@ public abstract class Isochrone {
 	 * Instantiates a new isochrone object.
 	 *
 	 * @param config the configuration of the dataset for the isochrone
+	 * @param db the databse object used for db communication
 	 * @param query the parameters for the isochrone
 	 * @throws AlgorithmException thrown if there are no date codes in the database for the specified query
 	 */
-	public Isochrone(final ConfigDataset config, final Query query) throws AlgorithmException {
+	public Isochrone(final ConfigDataset config, final Database db, final Query query) throws AlgorithmException {
+		this.database = db;
 		this.query = query;
 		this.queue = new PriorityQueue<Node>();
-		this.db = new Database<>(config, query.getMode(), query.getDir());
+
+		if (database == null) {
+			database = new Database(config, query.getMode(), query.getDir());
+		}
 
 		initDateCodes();
 	}
 
+	/**
+	 * Instantiates a new isochrone object.
+	 *
+	 * @param config the configuration of the dataset for the isochrone
+	 * @param query the parameters for the isochrone
+	 * @throws AlgorithmException thrown if there are no date codes in the database for the specified query
+	 */
+	public Isochrone(final ConfigDataset config, final Query query) throws AlgorithmException {
+		this(config, null, query);
+	}
+
 	// Public abstract methods
 
 	/**
@@ -77,6 +92,15 @@ public abstract class Isochrone {
 
 	// Public methods
 
+	/**
+	 * Closes all the resources needed by the isochrone class (like database connections).
+	 */
+	public void close() {
+		if (database != null) {
+			database.close();
+		}
+	}
+
 	/**
 	 * Computes the isochrone.
 	 *
@@ -223,7 +247,7 @@ public abstract class Isochrone {
 	 */
 	public double getAdjNodeCost(final Node node, final Node adjNode, final Set<Short> routeIds,
 			final Set<Integer> dateCodes, final long fromTime, final long toTime) {
-		return db.getAdjNodeCost(node, adjNode, routeIds, dateCodes, fromTime, toTime);
+		return database.getAdjNodeCost(node, adjNode, routeIds, dateCodes, fromTime, toTime);
 	}
 
 	/**
@@ -233,7 +257,7 @@ public abstract class Isochrone {
 	 * @return returns a set of date codes
 	 */
 	public Set<Integer> getDateCodes(final Calendar time) {
-		return db.getDateCodes(time);
+		return database.getDateCodes(time);
 	}
 
 	// Protected abstract methods
diff --git a/src/main/java/it/unibz/inf/isochrone/algorithm/MDijkstra.java b/src/main/java/it/unibz/inf/isochrone/algorithm/MDijkstra.java
index 03022765..ab34aa76 100644
--- a/src/main/java/it/unibz/inf/isochrone/algorithm/MDijkstra.java
+++ b/src/main/java/it/unibz/inf/isochrone/algorithm/MDijkstra.java
@@ -1,6 +1,7 @@
 package it.unibz.inf.isochrone.algorithm;
 
 import it.unibz.inf.isochrone.config.ConfigDataset;
+import it.unibz.inf.isochrone.db.Database;
 import it.unibz.inf.isochrone.network.Link;
 import it.unibz.inf.isochrone.network.Node;
 import it.unibz.inf.isochrone.util.Query;
@@ -23,12 +24,16 @@ public class MDijkstra extends Isochrone {
 	// Constructors
 
 	public MDijkstra(final ConfigDataset config, final Query query) throws AlgorithmException {
-		super(config, query);
+		this(config, null, query);
+	}
+
+	public MDijkstra(final ConfigDataset config, final Database db, final Query query) throws AlgorithmException {
+		super(config, db, query);
 
 		links = new LinkedHashMap<Integer, Link>();
 		nodes = new HashMap<Integer, Node>();
 
-		db.readNetwork(nodes, links);
+		database.readNetwork(nodes, links);
 	}
 
 	// Public methods
diff --git a/src/main/java/it/unibz/inf/isochrone/algorithm/MineX.java b/src/main/java/it/unibz/inf/isochrone/algorithm/MineX.java
index 03db5dd6..d10500c3 100644
--- a/src/main/java/it/unibz/inf/isochrone/algorithm/MineX.java
+++ b/src/main/java/it/unibz/inf/isochrone/algorithm/MineX.java
@@ -1,6 +1,7 @@
 package it.unibz.inf.isochrone.algorithm;
 
 import it.unibz.inf.isochrone.config.ConfigDataset;
+import it.unibz.inf.isochrone.db.Database;
 import it.unibz.inf.isochrone.network.Link;
 import it.unibz.inf.isochrone.network.Node;
 import it.unibz.inf.isochrone.util.Query;
@@ -19,7 +20,11 @@ public class MineX extends Isochrone {
 	// Constructors
 
 	public MineX(final ConfigDataset config, final Query query) throws AlgorithmException {
-		super(config, query);
+		this(config, null, query);
+	}
+
+	public MineX(final ConfigDataset config, final Database db, final Query query) throws AlgorithmException {
+		super(config, db, query);
 		nodes = new HashMap<Integer, Node>();
 	}
 
@@ -27,7 +32,7 @@ public class MineX extends Isochrone {
 
 	@Override
 	public Link getLink(final int linkId) {
-		final Link link = db.getLink(linkId, nodes);
+		final Link link = database.getLink(linkId, nodes);
 		if (link == null) {
 			throw new RuntimeException("LinkId not present: " + linkId);
 		}
@@ -39,7 +44,7 @@ public class MineX extends Isochrone {
 	public Node getNode(final int nodeId) {
 		Node node = nodes.get(nodeId);
 		if (node == null) {
-			node = db.getNode(nodeId);
+			node = database.getNode(nodeId);
 			if (node == null) {
 				throw new RuntimeException("NodeId not present: " + nodeId);
 			}
@@ -59,7 +64,7 @@ public class MineX extends Isochrone {
 
 	@Override
 	protected Collection<Link> calcAdjLinks(final int nodeId) {
-		return db.getAdjLinks(nodeId, nodes);
+		return database.getAdjLinks(nodeId, nodes);
 	}
 
 	@Override
diff --git a/src/main/java/it/unibz/inf/isochrone/algorithm/MrneX.java b/src/main/java/it/unibz/inf/isochrone/algorithm/MrneX.java
index 6430a471..15c28b01 100644
--- a/src/main/java/it/unibz/inf/isochrone/algorithm/MrneX.java
+++ b/src/main/java/it/unibz/inf/isochrone/algorithm/MrneX.java
@@ -1,6 +1,7 @@
 package it.unibz.inf.isochrone.algorithm;
 
 import it.unibz.inf.isochrone.config.ConfigDataset;
+import it.unibz.inf.isochrone.db.Database;
 import it.unibz.inf.isochrone.network.Link;
 import it.unibz.inf.isochrone.network.Node;
 import it.unibz.inf.isochrone.util.DistanceAlgorithm;
@@ -28,11 +29,15 @@ public class MrneX extends Isochrone {
 	// Constructors
 
 	public MrneX(final ConfigDataset config, final Query query) throws AlgorithmException {
-		this(config, query, Integer.MAX_VALUE);
+		this(config, null, query, Integer.MAX_VALUE);
 	}
 
-	public MrneX(final ConfigDataset config, final Query query, final int maxMemorySize) throws AlgorithmException {
-		super(config, query);
+	public MrneX(final ConfigDataset config, final Database db, final Query query) throws AlgorithmException {
+		this(config, db, query, Integer.MAX_VALUE);
+	}
+
+	public MrneX(final ConfigDataset config, final Database db, final Query query, final int maxMemorySize) throws AlgorithmException {
+		super(config, db, query);
 
 		adjList = new HashMap<Integer, List<Link>>();
 		loadedIERNodes = new HashMap<Integer, Node>();
@@ -46,7 +51,7 @@ public class MrneX extends Isochrone {
 
 	@Override
 	public Link getLink(final int linkId) {
-		final Link link = db.getLink(linkId, nodes);
+		final Link link = database.getLink(linkId, nodes);
 		if (link == null) {
 			throw new RuntimeException("LinkId not present: " + linkId);
 		}
@@ -58,7 +63,7 @@ public class MrneX extends Isochrone {
 	public Node getNode(final int nodeId) {
 		Node node = nodes.get(nodeId);
 		if (node == null) {
-			node = db.getNode(nodeId);
+			node = database.getNode(nodeId);
 			if (node == null) {
 				throw new RuntimeException("NodeId not present: " + nodeId);
 			}
@@ -108,7 +113,7 @@ public class MrneX extends Isochrone {
 		}
 
 		if (node.getCoordinates() == null) {
-			node.setCoordinates(db.getCoordinates(nodeId));
+			node.setCoordinates(database.getCoordinates(nodeId));
 		}
 
 		if (unlimitedMemory()) {
@@ -118,7 +123,7 @@ public class MrneX extends Isochrone {
 			final int reservedMemorySize = calcAvailableMemorySize(loadedIERNodes.isEmpty() ? 0.5f : 1f);
 			// CHECKSTYLE:ON MagicNumber
 
-			final double eDist = db.getRange(nodeId, reservedMemorySize);
+			final double eDist = database.getRange(nodeId, reservedMemorySize);
 			node.setRadius(Math.min(calcRemainingDistance(node), eDist));
 		}
 
@@ -200,7 +205,7 @@ public class MrneX extends Isochrone {
 	 *                       circle that should be loaded.
 	 */
 	private void loadLinksFromIER(final Node node, final Collection<Node> intersections) {
-		db.loadLinksFromIER(node, intersections, nodes, adjList);
+		database.loadLinksFromIER(node, intersections, nodes, adjList);
 	}
 
 }
diff --git a/src/main/java/it/unibz/inf/isochrone/config/ConfigDataset.java b/src/main/java/it/unibz/inf/isochrone/config/ConfigDataset.java
index e5c140fc..eec36d95 100644
--- a/src/main/java/it/unibz/inf/isochrone/config/ConfigDataset.java
+++ b/src/main/java/it/unibz/inf/isochrone/config/ConfigDataset.java
@@ -471,8 +471,8 @@ public class ConfigDataset {
 	private static Collection<String> filterInvalidDatasets(final Collection<String> datasets) {
 		LOGGER.info("Filtering invalid datasets (e.g. which have no database tables)");
 
-		final Collection<String> filteredList = new ArrayList<String>(datasets.size());
 		final ConfigIsochrone config = ConfigIsochrone.getInstance();
+		final Collection<String> filteredList = new ArrayList<String>(datasets.size());
 		final Collection<String> allTables = config.getAllTables();
 		for (final String ds : datasets) {
 			final ConfigDataset c = ConfigDataset.createInstance(ds);
diff --git a/src/main/java/it/unibz/inf/isochrone/config/ConfigIsochrone.java b/src/main/java/it/unibz/inf/isochrone/config/ConfigIsochrone.java
index f8649290..4ce45731 100644
--- a/src/main/java/it/unibz/inf/isochrone/config/ConfigIsochrone.java
+++ b/src/main/java/it/unibz/inf/isochrone/config/ConfigIsochrone.java
@@ -109,6 +109,8 @@ public final class ConfigIsochrone {
 	public Connection getConnection() {
 		try {
 			return factory.getConnection();
+		} catch (final NullPointerException e) {
+			e.printStackTrace();
 		} catch (final SQLException e) {
 			e.printStackTrace();
 		}
@@ -180,13 +182,18 @@ public final class ConfigIsochrone {
 	}
 
 	public Collection<String> getAllTables() {
+		final Connection connection = getConnection();
+		if (connection == null) {
+			throw new NullPointerException("Connection to database could not be initialized");
+		}
+
 		final Collection<String> result = new ArrayList<>();
 		final String query = "SELECT tablename FROM pg_tables WHERE schemaname='public'";
 
 		ResultSet rs = null;
 		CallableStatement stmt = null;
 		try {
-			stmt = getConnection().prepareCall(query);
+			stmt = connection.prepareCall(query);
 			rs = stmt.executeQuery();
 			while (rs.next()) {
 				result.add(rs.getString("tablename"));
@@ -196,6 +203,7 @@ public final class ConfigIsochrone {
 		} finally {
 			DbUtils.closeQuietly(rs);
 			DbUtils.closeQuietly(stmt);
+			DbUtils.closeQuietly(connection);
 		}
 
 		return result;
diff --git a/src/main/java/it/unibz/inf/isochrone/db/ConnectionFactory.java b/src/main/java/it/unibz/inf/isochrone/db/ConnectionFactory.java
index 8563c9dc..34251dce 100644
--- a/src/main/java/it/unibz/inf/isochrone/db/ConnectionFactory.java
+++ b/src/main/java/it/unibz/inf/isochrone/db/ConnectionFactory.java
@@ -16,10 +16,13 @@ import java.sql.SQLException;
  */
 public class ConnectionFactory {
 	private static final int MIN_CONNECTIONS = 5;
-	private Connection connection;
-	private BoneCP connectionPool;
 	private final int maxConnections;
 	private final boolean pooling;
+	private Connection connection;
+	private BoneCP connectionPool;
+	private String jdbcUrl;
+	private String username;
+	private String password;
 
 	// Constructor
 
@@ -46,7 +49,9 @@ public class ConnectionFactory {
 	 * @throws ClassNotFoundException thrown if the driver used for the database connection could not be found/loaded
 	 */
 	public void register(final String serverName, final String database, final int port, final String user, final String passwd) throws SQLException, ClassNotFoundException {
-		final String url = "jdbc:postgresql://" + serverName + ":" + port + "/" + database + "?binaryTransfer=true";
+		this.jdbcUrl = "jdbc:postgresql://" + serverName + ":" + port + "/" + database + "?binaryTransfer=true";
+		password = passwd;
+		username = user;
 
 		// load the database driver
 		Class.forName("org.postgresql.Driver");
@@ -56,14 +61,11 @@ public class ConnectionFactory {
 			config.setDefaultAutoCommit(false);
 			config.setUser(user);
 			config.setPassword(passwd);
-			config.setJdbcUrl(url);
+			config.setJdbcUrl(jdbcUrl);
 			config.setMinConnectionsPerPartition(Math.min(MIN_CONNECTIONS, maxConnections));
 			config.setMaxConnectionsPerPartition(maxConnections);
 			config.setPartitionCount(1);
 			connectionPool = new BoneCP(config);
-		} else {
-			connection = DriverManager.getConnection(url, user, passwd);
-			connection.setAutoCommit(false);
 		}
 	}
 
@@ -75,9 +77,34 @@ public class ConnectionFactory {
 	 */
 	public Connection getConnection() throws SQLException {
 		if (pooling) {
-			return connectionPool.getConnection();
+			if (connectionPool == null) {
+				throw new NullPointerException("ConnectionFactory has not registered any connectionPool configurations");
+			}
+
+			return createConnection();
+		}
+
+		if (username == null || password == null) {
+			throw new NullPointerException("ConnectionFactory has not registered any connection configurations");
+		}
+
+		if (connection == null || connection.isClosed()) {
+			connection = createConnection();
 		}
 
 		return connection;
 	}
+
+	// Private methods
+
+	private Connection createConnection() throws SQLException {
+		if (pooling) {
+			return connectionPool.getConnection();
+		}
+
+		final Connection c = DriverManager.getConnection(jdbcUrl, username, password);
+		c.setAutoCommit(false);
+
+		return c;
+	}
 }
diff --git a/src/main/java/it/unibz/inf/isochrone/db/Database.java b/src/main/java/it/unibz/inf/isochrone/db/Database.java
index ba92d986..006f0e1a 100644
--- a/src/main/java/it/unibz/inf/isochrone/db/Database.java
+++ b/src/main/java/it/unibz/inf/isochrone/db/Database.java
@@ -40,7 +40,7 @@ import org.apache.commons.dbutils.DbUtils;
  * @author Markus Innerebner
  * @version 2.2
  */
-public class Database<T extends ConfigDataset> {
+public class Database {
 	protected static final byte NW_MODE_CONTINUOUS = 0;
 	protected static final byte NW_MODE_DISCRETE = 1;
 
@@ -60,14 +60,14 @@ public class Database<T extends ConfigDataset> {
 	private final String queryGetLinksInRange;
 	private final String queryGetRange;
 	private final String queryLoadLinksFromIER;
-	protected final T config;
+	protected final ConfigDataset config;
 	protected Mode mode;
 	protected boolean isIncoming;
 	protected Connection connection;
 
 	// Constructor
 
-	public Database(final T config, final Mode mode, final Direction direction) {
+	public Database(final ConfigDataset config, final Mode mode, final Direction direction) {
 		this.config = config;
 		this.isIncoming = (direction == Direction.INCOMING);
 		this.mode = mode;
@@ -188,6 +188,8 @@ public class Database<T extends ConfigDataset> {
 		for (final PreparedStatement pstmt : pstmtsCacheMap.values()) {
 			DbUtils.closeQuietly(pstmt);
 		}
+
+		DbUtils.closeQuietly(connection);
 	}
 
 	/**
@@ -616,8 +618,8 @@ public class Database<T extends ConfigDataset> {
 	 */
 	@Override
 	protected void finalize() throws Throwable {
-		super.finalize();
 		close();
+		super.finalize();
 	}
 
 	// Protected methods
diff --git a/src/main/java/it/unibz/inf/isochrone/util/Query.java b/src/main/java/it/unibz/inf/isochrone/util/Query.java
index b35773ba..fad01ece 100644
--- a/src/main/java/it/unibz/inf/isochrone/util/Query.java
+++ b/src/main/java/it/unibz/inf/isochrone/util/Query.java
@@ -28,7 +28,7 @@ public class Query {
 	private Long fromTime;
 	private Boolean expireNodes;
 
-	// Constructor
+	// Constructors
 
 	/**
 	 * Construct a query object with every field except the nodes and
@@ -47,7 +47,7 @@ public class Query {
 		setTime(time);
 	}
 
-	// Public methods
+	// Getters
 
 	public Direction getDir() {
 		return dir;
@@ -89,6 +89,8 @@ public class Query {
 		return expireNodes;
 	}
 
+	// Setters
+
 	public void setDuration(final Long duration) {
 		this.duration = duration;
 	}
diff --git a/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java b/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java
index 2512fd44..8457d483 100644
--- a/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java
+++ b/src/main/java/it/unibz/inf/isoga/db/DatabaseWeb.java
@@ -41,7 +41,7 @@ import org.postgis.PGgeometry;
  * interface. (Mostly inserting vertices and links into the tables
  * used for the GeoServer)
  */
-public class DatabaseWeb extends Database<ConfigClient> {
+public class DatabaseWeb extends Database {
 	private final String queryGetIsoEdges;
 	private final String queryStoreLinks;
 	private final String queryStorePartialLinks;
diff --git a/src/main/java/it/unibz/inf/isoga/db/DbUtility.java b/src/main/java/it/unibz/inf/isoga/db/DbUtility.java
index 35f38a70..e7de60cc 100644
--- a/src/main/java/it/unibz/inf/isoga/db/DbUtility.java
+++ b/src/main/java/it/unibz/inf/isoga/db/DbUtility.java
@@ -42,49 +42,57 @@ public final class DbUtility {
 
 	// Public static methods
 
-	public static void dropTable(final Connection connection, final String tableName, final boolean cascade) {
+	public static void createBufferTable(final Connection connection, final String tableName) {
 		if (tableName == null || tableName.length() <= 0) {
 			return;
 		}
 
-		executeStatement(connection, "DROP TABLE IF EXISTS " + tableName + (cascade ? " CASCADE" : ""));
+		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, CONSTRAINT pkey_" + tableName + " PRIMARY KEY (\"ID\"))");
 	}
 
-	public static void truncateTable(final Connection connection, final String tableName) {
+	public static void createEdgeTable(final Connection connection, final String tableName) {
 		if (tableName == null || tableName.length() <= 0) {
 			return;
 		}
 
-		executeStatement(connection, "DELETE FROM " + tableName);
+		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, \"SOURCE\" integer, \"TARGET\" integer, \"OFFSET\" double precision, \"LENGTH\" double precision)");
 	}
 
-	public static void dropIndex(final Connection connection, final String indexName) {
+	public static void createSpatialIndex(final Connection connection, final TableEntry tableEntry) {
+		final String indexName = tableEntry.getIndexName();
 		if (indexName == null || indexName.length() <= 0) {
 			return;
 		}
 
-		executeStatement(connection, "DROP INDEX IF EXISTS " + indexName);
+		final String tableName = tableEntry.getTableName();
+		if (tableName == null || tableName.length() <= 0) {
+			return;
+		}
+
+		executeStatement(connection, "CREATE INDEX " + indexName + " ON " + tableName + " USING GIST(\"GEOMETRY\")");
 	}
 
-	public static void createTargetEdgeTable(final Connection connection, final String tableName) {
+	public static void createVertexAnnotationTable(final Connection connection, final String tableName) {
 		if (tableName == null || tableName.length() <= 0) {
 			return;
 		}
 
-		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, \"SOURCE\" integer, \"TARGET\" integer, \"OFFSET\" double precision, \"LENGTH\" double precision)");
+		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, \"ROUTE_ID\" smallint,\"TIME_A\" integer,\"TIME_D\" integer)");
 	}
 
-	public static void insertGeometryMetadata(final Connection connection, final TableEntry tableEntry, final int serverSrid) {
+	public static void createVertexTable(final Connection connection, final String tableName) {
+		if (tableName == null || tableName.length() <= 0) {
+			return;
+		}
+
+		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, \"DISTANCE\" double precision, \"ROUTE_ID\" smallint, \"STATE\" VARCHAR(7), \"T_TYPE\" smallint)");
+	}
+
+	public static void deleteGeometryMetadata(final Connection connection, final String tableName) {
 		CallableStatement prepareCall = null;
 		try {
-			prepareCall = connection.prepareCall("{call addgeometrycolumn(?,?,?,?,?,true)}");
-			// CHECKSTYLE:OFF MagicNumber
-			prepareCall.setString(1, tableEntry.getTableName());
-			prepareCall.setString(2, "GEOMETRY");
-			prepareCall.setInt(3, serverSrid);
-			prepareCall.setString(4, tableEntry.getGeometryType());
-			prepareCall.setInt(5, 2);
-			// CHECKSTYLE:ON MagicNumber
+			prepareCall = connection.prepareCall("{call DropGeometryTable(?)}");
+			prepareCall.setString(1, tableName);
 			prepareCall.executeUpdate();
 			connection.commit();
 		} catch (final SQLException e) {
@@ -99,18 +107,20 @@ public final class DbUtility {
 		}
 	}
 
-	public static void createSpatialIndex(final Connection connection, final TableEntry tableEntry) {
-		final String indexName = tableEntry.getIndexName();
+	public static void dropIndex(final Connection connection, final String indexName) {
 		if (indexName == null || indexName.length() <= 0) {
 			return;
 		}
 
-		final String tableName = tableEntry.getTableName();
+		executeStatement(connection, "DROP INDEX IF EXISTS " + indexName);
+	}
+
+	public static void dropTable(final Connection connection, final String tableName, final boolean cascade) {
 		if (tableName == null || tableName.length() <= 0) {
 			return;
 		}
 
-		executeStatement(connection, "CREATE INDEX " + indexName + " ON " + tableName + " USING GIST(\"GEOMETRY\")");
+		executeStatement(connection, "DROP TABLE IF EXISTS " + tableName + (cascade ? " CASCADE" : ""));
 	}
 
 	public static boolean dropTablesByRegexp(final Connection connection, final String regex) {
@@ -134,13 +144,25 @@ public final class DbUtility {
 		return false;
 	}
 
-	public static void deleteGeometryMetadata(final Connection connection, final String tableName) {
-		CallableStatement prepareCall = null;
+	public static ResponsePoiFeature getPoiFeatures(final String sqlExpr, final ConfigDataset config) {
+		final ResponsePoiFeature result = new ResponsePoiFeature();
+		if ("noResult".equals(sqlExpr)) {
+			result.setType("invalid");
+			return result;
+		}
+
+		final Connection connection = ConfigIsochrone.getInstance().getConnection();
+
+		Statement stmt = null;
+		ResultSet rSet = null;
 		try {
-			prepareCall = connection.prepareCall("{call DropGeometryTable(?)}");
-			prepareCall.setString(1, tableName);
-			prepareCall.executeUpdate();
-			connection.commit();
+			stmt = connection.createStatement();
+			rSet = stmt.executeQuery(sqlExpr);
+
+			while (rSet.next()) {
+				result.addFeature(new PoiFeature(rSet.getString("category"), rSet.getString("GEOMETRY")));
+			}
+			result.setType("FeatureCollection");
 		} catch (final SQLException e) {
 			e.printStackTrace();
 			try {
@@ -149,53 +171,30 @@ public final class DbUtility {
 				e1.printStackTrace();
 			}
 		} finally {
-			DbUtils.closeQuietly(prepareCall);
-		}
-	}
-
-	public static void createVertexAnnotationTable(final Connection connection, final String tableName) {
-		if (tableName == null || tableName.length() <= 0) {
-			return;
-		}
-
-		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, \"ROUTE_ID\" smallint,\"TIME_A\" integer,\"TIME_D\" integer)");
-	}
-
-	public static void createTargetVertexTable(final Connection connection, final String tableName) {
-		if (tableName == null || tableName.length() <= 0) {
-			return;
-		}
-
-		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, \"DISTANCE\" double precision, \"ROUTE_ID\" smallint, \"STATE\" VARCHAR(7), \"T_TYPE\" smallint)");
-	}
-
-	public static void createTargetBufferTable(final Connection connection, final String tableName) {
-		if (tableName == null || tableName.length() <= 0) {
-			return;
+			DbUtils.closeQuietly(rSet);
+			DbUtils.closeQuietly(stmt);
 		}
 
-		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, CONSTRAINT pkey_" + tableName + " PRIMARY KEY (\"ID\"))");
+		return result;
 	}
 
-	public static ResponsePoiFeature getPoiFeatures(final String sqlExpr, final ConfigDataset config) {
-		final ResponsePoiFeature result = new ResponsePoiFeature();
-		if ("noResult".equals(sqlExpr)) {
-			result.setType("invalid");
-			return result;
-		}
-
+	public static WpsStatistic getStatistics(final String sqlExpr, final boolean withSum, final ConfigDataset config) {
 		final Connection connection = ConfigIsochrone.getInstance().getConnection();
 
+		int sum = 0;
+		int count = 0;
 		Statement stmt = null;
 		ResultSet rSet = null;
 		try {
 			stmt = connection.createStatement();
 			rSet = stmt.executeQuery(sqlExpr);
 
-			while (rSet.next()) {
-				result.addFeature(new PoiFeature(rSet.getString("category"), rSet.getString("GEOMETRY")));
+			if (rSet.next()) {
+				if (withSum) {
+					sum = rSet.getInt("sum");
+				}
+				count = rSet.getInt("count");
 			}
-			result.setType("FeatureCollection");
 		} catch (final SQLException e) {
 			e.printStackTrace();
 			try {
@@ -208,7 +207,88 @@ public final class DbUtility {
 			DbUtils.closeQuietly(stmt);
 		}
 
-		return result;
+		return new WpsStatistic(count, sum);
+	}
+
+	public static SortedMap<Calendar, RouteEntity> getVertexAnnotation(final ConfigClient config, final int vertexId, final Direction direction) {
+		final Comparator<Object> comp = (direction == Direction.INCOMING) ? Collections.reverseOrder() : null;
+		final SortedMap<Calendar, RouteEntity> schedules =  new TreeMap<Calendar, RouteEntity>(comp);
+		final Connection connection = ConfigIsochrone.getInstance().getConnection();
+
+		final String arrivalTimeStr = "to_char(to_timestamp(CAST(\"TIME_A\" AS text),'SSSSS'),'HH24:MI') \"ARRIVAL_TIME\"";
+		final String departureTimeStr = "to_char(to_timestamp(CAST(\"TIME_D\" AS text),'SSSSS'),'HH24:MI') \"DEPARTURE_TIME\"";
+		final String query = "SELECT R.ROUTE_ID, "
+			+ arrivalTimeStr + ", "
+			+ departureTimeStr + ", "
+			+ "R.ROUTE_SHORT_NAME \"ROUTE_SHORT_NAME\", R.ROUTE_TYPE \"ROUTE_TYPE\" "
+			+ "FROM ? V, ? R WHERE V.\"ID\"=? AND V.\"ROUTE_ID\"=R.ROUTE_ID";
+
+		PreparedStatement statement = null;
+		ResultSet resultSet = null;
+		try {
+			statement = connection.prepareStatement(query);
+			// CHECKSTYLE:OFF MagicNumber
+			statement.setString(1, config.getVertexAnnotatedTableEntry().getTableName());
+			statement.setString(2, config.getTableRoutes());
+			statement.setInt(3, vertexId);
+			// CHECKSTYLE:ON MagicNumber
+
+			resultSet = statement.executeQuery();
+			while (resultSet.next()) {
+				final int routeId = resultSet.getInt("ROUTE_ID");
+				final String tArr = resultSet.getString("ARRIVAL_TIME");
+				final String tDep = resultSet.getString("DEPARTURE_TIME");
+				String time;
+				if (direction == Direction.INCOMING) {
+					time = tDep;
+					if (time.equals("00:00")) {
+						time = tArr;
+					}
+				} else {
+					time = tArr;
+					if (time.equals("00:00")) {
+						time = tDep;
+					}
+				}
+
+				final String routeName = resultSet.getString("ROUTE_SHORT_NAME");
+				final short routeType = resultSet.getShort("ROUTE_TYPE");
+				final RouteEntity routeEntity = new RouteEntity(routeId, routeName, routeType, time);
+				schedules.put(routeEntity.getTime(), routeEntity);
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		} finally {
+			DbUtils.closeQuietly(resultSet);
+			DbUtils.closeQuietly(statement);
+		}
+
+		return schedules;
+	}
+
+	public static void insertGeometryMetadata(final Connection connection, final TableEntry tableEntry, final int serverSrid) {
+		CallableStatement prepareCall = null;
+		try {
+			prepareCall = connection.prepareCall("{call addgeometrycolumn(?,?,?,?,?,true)}");
+			// CHECKSTYLE:OFF MagicNumber
+			prepareCall.setString(1, tableEntry.getTableName());
+			prepareCall.setString(2, "GEOMETRY");
+			prepareCall.setInt(3, serverSrid);
+			prepareCall.setString(4, tableEntry.getGeometryType());
+			prepareCall.setInt(5, 2);
+			// CHECKSTYLE:ON MagicNumber
+			prepareCall.executeUpdate();
+			connection.commit();
+		} catch (final SQLException e) {
+			e.printStackTrace();
+			try {
+				connection.rollback();
+			} catch (final SQLException e1) {
+				e1.printStackTrace();
+			}
+		} finally {
+			DbUtils.closeQuietly(prepareCall);
+		}
 	}
 
 	public static ResponseWps spatialIntersection2JSON(final String sqlExpr, final SqlQuery query, final ConfigDataset config) {
@@ -299,92 +379,12 @@ public final class DbUtility {
 		return result;
 	}
 
-	public static WpsStatistic getStatistics(final String sqlExpr, final boolean withSum, final ConfigDataset config) {
-		final Connection connection = ConfigIsochrone.getInstance().getConnection();
-
-		int sum = 0;
-		int count = 0;
-		Statement stmt = null;
-		ResultSet rSet = null;
-		try {
-			stmt = connection.createStatement();
-			rSet = stmt.executeQuery(sqlExpr);
-
-			if (rSet.next()) {
-				if (withSum) {
-					sum = rSet.getInt("sum");
-				}
-				count = rSet.getInt("count");
-			}
-		} catch (final SQLException e) {
-			e.printStackTrace();
-			try {
-				connection.rollback();
-			} catch (final SQLException e1) {
-				e1.printStackTrace();
-			}
-		} finally {
-			DbUtils.closeQuietly(rSet);
-			DbUtils.closeQuietly(stmt);
-		}
-
-		return new WpsStatistic(count, sum);
-	}
-
-	public static SortedMap<Calendar, RouteEntity> getVertexAnnotation(final ConfigClient config, final int vertexId, final Direction direction) {
-		final Comparator<Object> comp = (direction == Direction.INCOMING) ? Collections.reverseOrder() : null;
-		final SortedMap<Calendar, RouteEntity> schedules =  new TreeMap<Calendar, RouteEntity>(comp);
-		final Connection connection = ConfigIsochrone.getInstance().getConnection();
-
-		final String arrivalTimeStr = "to_char(to_timestamp(CAST(\"TIME_A\" AS text),'SSSSS'),'HH24:MI') \"ARRIVAL_TIME\"";
-		final String departureTimeStr = "to_char(to_timestamp(CAST(\"TIME_D\" AS text),'SSSSS'),'HH24:MI') \"DEPARTURE_TIME\"";
-		final String query = "SELECT R.ROUTE_ID, "
-			+ arrivalTimeStr + ", "
-			+ departureTimeStr + ", "
-			+ "R.ROUTE_SHORT_NAME \"ROUTE_SHORT_NAME\", R.ROUTE_TYPE \"ROUTE_TYPE\" "
-			+ "FROM ? V, ? R WHERE V.\"ID\"=? AND V.\"ROUTE_ID\"=R.ROUTE_ID";
-
-		PreparedStatement statement = null;
-		ResultSet resultSet = null;
-		try {
-			statement = connection.prepareStatement(query);
-			// CHECKSTYLE:OFF MagicNumber
-			statement.setString(1, config.getVertexAnnotatedTableEntry().getTableName());
-			statement.setString(2, config.getTableRoutes());
-			statement.setInt(3, vertexId);
-			// CHECKSTYLE:ON MagicNumber
-
-			resultSet = statement.executeQuery();
-			while (resultSet.next()) {
-				final int routeId = resultSet.getInt("ROUTE_ID");
-				final String tArr = resultSet.getString("ARRIVAL_TIME");
-				final String tDep = resultSet.getString("DEPARTURE_TIME");
-				String time;
-				if (direction == Direction.INCOMING) {
-					time = tDep;
-					if (time.equals("00:00")) {
-						time = tArr;
-					}
-				} else {
-					time = tArr;
-					if (time.equals("00:00")) {
-						time = tDep;
-					}
-				}
-
-				final String routeName = resultSet.getString("ROUTE_SHORT_NAME");
-				final short routeType = resultSet.getShort("ROUTE_TYPE");
-				final RouteEntity routeEntity = new RouteEntity(routeId, routeName, routeType, time);
-				schedules.put(routeEntity.getTime(), routeEntity);
-			}
-		} catch (final SQLException e) {
-			e.printStackTrace();
-		} finally {
-			DbUtils.closeQuietly(resultSet);
-			DbUtils.closeQuietly(statement);
+	public static void truncateTable(final Connection connection, final String tableName) {
+		if (tableName == null || tableName.length() <= 0) {
+			return;
 		}
 
-		return schedules;
+		executeStatement(connection, "DELETE FROM " + tableName);
 	}
 
 	// Private static methods
diff --git a/src/main/java/it/unibz/inf/isoga/service/AbstractService.java b/src/main/java/it/unibz/inf/isoga/service/AbstractService.java
index ee5bfa4b..49fb4293 100644
--- a/src/main/java/it/unibz/inf/isoga/service/AbstractService.java
+++ b/src/main/java/it/unibz/inf/isoga/service/AbstractService.java
@@ -67,7 +67,7 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 		// register edge table and layer
 		final TableEntry edgeTableEntry = configClient.getEdgeTableEntry();
 		DbUtility.deleteGeometryMetadata(connection, edgeTableEntry.getTableName());
-		DbUtility.createTargetEdgeTable(connection, edgeTableEntry.getTableName());
+		DbUtility.createEdgeTable(connection, edgeTableEntry.getTableName());
 		DbUtility.insertGeometryMetadata(connection, edgeTableEntry, serverSrid);
 		DbUtility.createSpatialIndex(connection, edgeTableEntry);
 		createdEntries.add(edgeTableEntry);
@@ -92,7 +92,7 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 		// register vertex table and layer
 		final TableEntry vertexTableEntry = configClient.getVertexTableEntry();
 		DbUtility.deleteGeometryMetadata(connection, vertexTableEntry.getTableName());
-		DbUtility.createTargetVertexTable(connection, vertexTableEntry.getTableName());
+		DbUtility.createVertexTable(connection, vertexTableEntry.getTableName());
 		DbUtility.insertGeometryMetadata(connection, vertexTableEntry, serverSrid);
 		DbUtility.createSpatialIndex(connection, vertexTableEntry);
 		createdEntries.add(vertexTableEntry);
@@ -111,7 +111,7 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 		// register area buffer table and layer
 		final TableEntry areaBufferTableEntry = configClient.getAreaBufferTableEntry();
 		DbUtility.deleteGeometryMetadata(connection, areaBufferTableEntry.getTableName());
-		DbUtility.createTargetBufferTable(connection, areaBufferTableEntry.getTableName());
+		DbUtility.createBufferTable(connection, areaBufferTableEntry.getTableName());
 		DbUtility.insertGeometryMetadata(connection, areaBufferTableEntry, serverSrid);
 		DbUtility.createSpatialIndex(connection, areaBufferTableEntry);
 		createdEntries.add(areaBufferTableEntry);
diff --git a/src/main/java/it/unibz/inf/isoga/service/ServiceIsochrone.java b/src/main/java/it/unibz/inf/isoga/service/ServiceIsochrone.java
index 0de84182..299fcc35 100644
--- a/src/main/java/it/unibz/inf/isoga/service/ServiceIsochrone.java
+++ b/src/main/java/it/unibz/inf/isoga/service/ServiceIsochrone.java
@@ -68,7 +68,7 @@ public class ServiceIsochrone extends AbstractService<RequestIsochrone, Response
 		truncateTables(config);
 		final Query query = new Query(direction, request.getSpeed(), request.getDmax(), request.getDate(), true, request.getMode());
 		query.setStartLocations(locationsFromQueryNodes(request.getQueryNodes(), db));
-		final Isochrone isochrone = getAlgorithm(request.getAlgorithm(), config, query);
+		final Isochrone isochrone = getAlgorithm(request.getAlgorithm(), config, db, query);
 		final BBoxOutput output = isochrone.compute(new BBoxOutput(config, db, direction));
 		final long timeIsochrone = System.currentTimeMillis() - startComputationTiming;
 
@@ -84,6 +84,8 @@ public class ServiceIsochrone extends AbstractService<RequestIsochrone, Response
 			}
 		}
 
+		db.close();
+
 		final ResponseIsochrone response = new ResponseIsochrone();
 		response.setBoundingBox(output.getBoundingBox());
 
@@ -99,17 +101,17 @@ public class ServiceIsochrone extends AbstractService<RequestIsochrone, Response
 
 	// Private methods
 
-	public Isochrone getAlgorithm(final Algorithm algorithm, final ConfigDataset config, final Query query) throws AlgorithmException {
+	public Isochrone getAlgorithm(final Algorithm algorithm, final ConfigDataset config, final DatabaseWeb db, final Query query) throws AlgorithmException {
 		final Isochrone result;
 		switch (algorithm) {
 			case MINEX:
-				result = new MineX(config, query);
+				result = new MineX(config, db, query);
 				break;
 			case MRNEX:
-				result = new MrneX(config, query);
+				result = new MrneX(config, db, query);
 				break;
 			default:
-				result = new MDijkstra(config, query);
+				result = new MDijkstra(config, db, query);
 		}
 
 		return result;
diff --git a/src/test/java/it/unibz/inf/isochrone/db/DatabaseTest.java b/src/test/java/it/unibz/inf/isochrone/db/DatabaseTest.java
index 971b77f7..ee08f8c0 100644
--- a/src/test/java/it/unibz/inf/isochrone/db/DatabaseTest.java
+++ b/src/test/java/it/unibz/inf/isochrone/db/DatabaseTest.java
@@ -44,8 +44,9 @@ public class DatabaseTest {
 	@Test
 	public void testCreateDatabaseObject() {
 		final ConfigDataset config = ConfigDataset.getInstance(TEST_DATASET);
-		final Database<ConfigDataset> db = new Database<>(config, Mode.MULTIMODAL, Direction.INCOMING);
+		final Database db = new Database(config, Mode.MULTIMODAL, Direction.INCOMING);
 		Assert.assertNotNull(db, "Database object could not be created!");
+		db.close();
 	}
 
 	@Test
@@ -54,28 +55,31 @@ public class DatabaseTest {
 		final Map<Integer, Link> compareLinks = new LinkedHashMap<Integer, Link>();
 		fillHashMaps(compareNodes, compareLinks);
 
-		initDb();
-
+		final Database db = initDb();
 		Assert.assertEquals(nodes.get(NODE_ID), compareNodes.get(NODE_ID), "Nodes comparison");
 		Assert.assertEquals(links.get(LINK_ID), compareLinks.get(LINK_ID), "Links comparison");
+
+		db.close();
 	}
 
 	@Test
 	public void testCountEdges() {
-		initDb();
+		final Database db = initDb();
 
 		// 2687 Doesn't correspond to the number of nodes in
 		// the nodes table, but the number of distinct
 		// target/source node in the edges table
 		Assert.assertEquals(nodes.size(), EXPECTED_NODE_COUNT, "Node count was unexpected");
 		Assert.assertEquals(links.size(), EXPECTED_LINK_COUNT, "Link count was unexpected");
+
+		db.close();
 	}
 
 	// Private methods
 
-	private Database<ConfigDataset> initDb() {
+	private Database initDb() {
 		final ConfigDataset config = ConfigDataset.getInstance(TEST_DATASET);
-		final Database<ConfigDataset> db = new Database<>(config, Mode.MULTIMODAL, Direction.INCOMING);
+		final Database db = new Database(config, Mode.MULTIMODAL, Direction.INCOMING);
 		db.readNetwork(nodes, links);
 
 		return db;
diff --git a/src/test/java/it/unibz/inf/isochrone/network/AlgorithmHelper.java b/src/test/java/it/unibz/inf/isochrone/network/AlgorithmHelper.java
index 6a597d15..73adea3b 100644
--- a/src/test/java/it/unibz/inf/isochrone/network/AlgorithmHelper.java
+++ b/src/test/java/it/unibz/inf/isochrone/network/AlgorithmHelper.java
@@ -16,11 +16,11 @@ final class AlgorithmHelper {
 
 	// Public static methods
 
-	public static void run(final Class<? extends Isochrone> algorithmClass, final TestParameters params) {
-		run(algorithmClass, params, true);
+	public static MemoryOutput run(final Class<? extends Isochrone> algorithmClass, final TestParameters params) {
+		return run(algorithmClass, params, true);
 	}
 
-	public static void run(final Class<? extends Isochrone> algorithmClass, final TestParameters params, final boolean expireNodes) {
+	public static MemoryOutput run(final Class<? extends Isochrone> algorithmClass, final TestParameters params, final boolean expireNodes) {
 		ConfigDataset c = ConfigDataset.getInstance(params.getDataset());
 		Query query = new Query(params.getDirection(), params.getWalkingSpeed(), params.getRuntime(), params.getDate(), expireNodes, params.getMode());
 		query.setStartNodeIds(params.getStartNodeId());
@@ -32,7 +32,10 @@ final class AlgorithmHelper {
 			Assert.fail(e.getMessage());
 		}
 
-		algorithm.compute();
+		final MemoryOutput o = algorithm.compute();
+		algorithm.close();
+
+		return o;
 	}
 
 
diff --git a/src/test/java/it/unibz/inf/isochrone/network/ComparisonTest.java b/src/test/java/it/unibz/inf/isochrone/network/ComparisonTest.java
index 215f47b5..9adf9d8c 100644
--- a/src/test/java/it/unibz/inf/isochrone/network/ComparisonTest.java
+++ b/src/test/java/it/unibz/inf/isochrone/network/ComparisonTest.java
@@ -12,6 +12,7 @@ import it.unibz.inf.isochrone.util.Query;
 
 import java.util.Calendar;
 import java.util.GregorianCalendar;
+import java.util.Map;
 
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -35,7 +36,13 @@ public class ComparisonTest {
 		queryMinex.setStartNodeIds(NODE_ID);
 		final Isochrone mineX = new MineX(config, queryMinex);
 
-		Assert.assertEquals(mDijkstra.compute().getLinks(), mineX.compute().getLinks(), "Dijkstra != MineX");
+		final Map<Integer, Link> linksDijkstra = mDijkstra.compute().getLinks();
+		final Map<Integer, Link> linksMineX = mineX.compute().getLinks();
+
+		mDijkstra.close();
+		mineX.close();
+
+		Assert.assertEquals(linksDijkstra, linksMineX, "Dijkstra != MineX");
 	}
 
 	@Test
@@ -50,7 +57,13 @@ public class ComparisonTest {
 		queryMrneX.setStartNodeIds(NODE_ID);
 		final Isochrone mrneX = new MrneX(config, queryMrneX);
 
-		Assert.assertEquals(mDijkstra.compute().getLinks(), mrneX.compute().getLinks(), "Dijkstra != MrneX");
+		final Map<Integer, Link> linksDijkstra = mDijkstra.compute().getLinks();
+		final Map<Integer, Link> linksMrneX = mrneX.compute().getLinks();
+
+		mDijkstra.close();
+		mrneX.close();
+
+		Assert.assertEquals(linksDijkstra, linksMrneX, "Dijkstra != MrneX");
 	}
 
 	@Test
@@ -62,6 +75,12 @@ public class ComparisonTest {
 		final Isochrone mineX = new MineX(config, query);
 		final Isochrone mrneX = new MrneX(config, query);
 
-		Assert.assertEquals(mineX.compute().getLinks(), mrneX.compute().getLinks(), "MineX != MrneX");
+		final Map<Integer, Link> linksMineX = mineX.compute().getLinks();
+		final Map<Integer, Link> linksMrneX = mrneX.compute().getLinks();
+
+		mineX.close();
+		mrneX.close();
+
+		Assert.assertEquals(linksMineX, linksMrneX, "MineX != MrneX");
 	}
 }
-- 
GitLab