From ca15bb1be1622666f19917738cc9de9537b2e95f Mon Sep 17 00:00:00 2001
From: Nikolaus Krismer <niko@krismer.de>
Date: Fri, 21 Mar 2014 11:23:59 +0100
Subject: [PATCH] fixed bug on startup (invalid table cleanup regexp) improved
 error handling when geoserver could not create layers fixed todo (added
 logging output on database table creation) added some argument checks in
 DbUtility class

---
 .../inf/isochrone/config/ConfigDataset.java   |  2 +-
 .../java/it/unibz/inf/isoga/db/DbUtility.java | 47 +++++++++++++++++--
 .../inf/isoga/service/AbstractService.java    | 31 ++++++++++--
 .../it/unibz/inf/isoga/web/JsonWebsocket.java |  6 ++-
 .../unibz/inf/isoga/web/StartupListener.java  |  2 +-
 5 files changed, 76 insertions(+), 12 deletions(-)

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 e1865496..e5c140fc 100644
--- a/src/main/java/it/unibz/inf/isochrone/config/ConfigDataset.java
+++ b/src/main/java/it/unibz/inf/isochrone/config/ConfigDataset.java
@@ -436,8 +436,8 @@ public class ConfigDataset {
 	};
 
 	private void initTableEntries() {
-		edgeTableEntry = createTableEntry(getTableIsoLinks(), getIndexIsoLinks(), TableType.EDGE);
 		areaBufferTableEntry = createTableEntry(getTableIsoAreaBuffer(), getIndexIsoAreaBuffer(), TableType.COVERAGE);
+		edgeTableEntry = createTableEntry(getTableIsoLinks(), getIndexIsoLinks(), TableType.EDGE);
 		vertexAnnotatedTableEntry = createTableEntry(getTableIsoNodesAnnotations());
 		vertexTableEntry = createTableEntry(getTableIsoNodes(), getIndexIsoNodes(), TableType.VERTEX);
 	}
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 517b2523..35f38a70 100644
--- a/src/main/java/it/unibz/inf/isoga/db/DbUtility.java
+++ b/src/main/java/it/unibz/inf/isoga/db/DbUtility.java
@@ -43,20 +43,35 @@ public final class DbUtility {
 	// Public static methods
 
 	public static void dropTable(final Connection connection, final String tableName, final boolean cascade) {
-		executeStatement(connection, "DROP TABLE " + tableName + (cascade ? " CASCADE" : ""));
+		if (tableName == null || tableName.length() <= 0) {
+			return;
+		}
+
+		executeStatement(connection, "DROP TABLE IF EXISTS " + tableName + (cascade ? " CASCADE" : ""));
 	}
 
 	public static void truncateTable(final Connection connection, final String tableName) {
+		if (tableName == null || tableName.length() <= 0) {
+			return;
+		}
+
 		executeStatement(connection, "DELETE FROM " + tableName);
 	}
 
 	public static void dropIndex(final Connection connection, final String indexName) {
+		if (indexName == null || indexName.length() <= 0) {
+			return;
+		}
+
 		executeStatement(connection, "DROP INDEX IF EXISTS " + indexName);
 	}
 
-	public static void createTargetEdgeTable(final Connection connection, final String edgeTableName) {
-		executeStatement(connection, "CREATE TABLE " + edgeTableName
-				+ " (\"ID\" integer NOT NULL, \"SOURCE\" integer, \"TARGET\" integer, \"OFFSET\" double precision, \"LENGTH\" double precision)");
+	public static void createTargetEdgeTable(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)");
 	}
 
 	public static void insertGeometryMetadata(final Connection connection, final TableEntry tableEntry, final int serverSrid) {
@@ -85,7 +100,17 @@ public final class DbUtility {
 	}
 
 	public static void createSpatialIndex(final Connection connection, final TableEntry tableEntry) {
-		executeStatement(connection, "CREATE INDEX " + tableEntry.getIndexName() + " ON " + tableEntry.getTableName() + " USING GIST(\"GEOMETRY\")");
+		final String indexName = tableEntry.getIndexName();
+		if (indexName == null || indexName.length() <= 0) {
+			return;
+		}
+
+		final String tableName = tableEntry.getTableName();
+		if (tableName == null || tableName.length() <= 0) {
+			return;
+		}
+
+		executeStatement(connection, "CREATE INDEX " + indexName + " ON " + tableName + " USING GIST(\"GEOMETRY\")");
 	}
 
 	public static boolean dropTablesByRegexp(final Connection connection, final String regex) {
@@ -129,14 +154,26 @@ public final class DbUtility {
 	}
 
 	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;
+		}
+
 		executeStatement(connection, "CREATE TABLE " + tableName + " (\"ID\" integer NOT NULL, CONSTRAINT pkey_" + tableName + " PRIMARY KEY (\"ID\"))");
 	}
 
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 48cfd01d..ee5bfa4b 100644
--- a/src/main/java/it/unibz/inf/isoga/service/AbstractService.java
+++ b/src/main/java/it/unibz/inf/isoga/service/AbstractService.java
@@ -12,6 +12,8 @@ import it.unibz.inf.isoga.service.dto.IRequest;
 import it.unibz.inf.isoga.service.dto.IResponse;
 
 import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Collection;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,6 +38,15 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 
 	// Protected methods
 
+	private void performDbCleanup(final Connection connection, final Collection<TableEntry> createdEntries) {
+		for (TableEntry entry : createdEntries) {
+			LOGGER.debug("Deleting created layer, since an error occured during client config registration");
+			DbUtility.deleteGeometryMetadata(connection, entry.getTableName());
+			DbUtility.dropTable(connection, entry.getTableName(), false);
+			DbUtility.dropIndex(connection, entry.getIndexName());
+		}
+	}
+
 	/**
 	 * Creates the database tables and new layers for every session.
 	 *
@@ -43,6 +54,7 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 	 * @param configClient the configuration containing the tables and layer names which are created/registered.
 	 */
 	protected void registerTableAndLayers(final Connection connection, final ConfigClient configClient) {
+		final Collection<TableEntry> createdEntries = new ArrayList<>(5);
 		final ConfigGeoserver configGeoserver = ConfigGeoserver.getInstance();
 		final GeoServerRESTPublisher publisher = configGeoserver.getGeoServerPublisher();
 		final String ws = configGeoserver.getRenderServerWorkspace();
@@ -52,18 +64,21 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 		final int serverSrid = configClient.getServerSRID();
 		final String srs = "EPSG:" + serverSrid;
 
-		// register edge layer
+		// register edge table and layer
 		final TableEntry edgeTableEntry = configClient.getEdgeTableEntry();
 		DbUtility.deleteGeometryMetadata(connection, edgeTableEntry.getTableName());
 		DbUtility.createTargetEdgeTable(connection, edgeTableEntry.getTableName());
 		DbUtility.insertGeometryMetadata(connection, edgeTableEntry, serverSrid);
 		DbUtility.createSpatialIndex(connection, edgeTableEntry);
-		// TODO: Log database table creation
+		createdEntries.add(edgeTableEntry);
+		LOGGER.debug("Successfully created edge table \"" + edgeTableEntry.getTableName() + "\"");
+
 		final GSFeatureTypeEncoder edgeFeatureTypeEncoder = getFeatureEncoder(edgeTableEntry, serverExtend, srs);
 		final GSLayerEncoder edgeLayerEncoder = new GSLayerEncoder();
 		edgeLayerEncoder.setDefaultStyle("STYLE_ISO_EDGES");
 		if (!publisher.publishDBLayer(ws, ds, edgeFeatureTypeEncoder, edgeLayerEncoder)) {
 			LOGGER.debug("Could not register edge layer \"" + edgeFeatureTypeEncoder.getName() + "\"");
+			performDbCleanup(connection, createdEntries);
 			throw new RuntimeException("Couldn't register edge layer on the GeoServer");
 		}
 		LOGGER.debug("Successfully registered edge layer \"" + edgeFeatureTypeEncoder.getName() + "\"");
@@ -71,33 +86,43 @@ public abstract class AbstractService<T extends IRequest, U extends IResponse> i
 		// create vertex annotation table
 		final TableEntry annotatedTableEntry = configClient.getVertexAnnotatedTableEntry();
 		DbUtility.createVertexAnnotationTable(connection, annotatedTableEntry.getTableName());
+		createdEntries.add(annotatedTableEntry);
 		LOGGER.debug("Successfully created vertex annotation table \"" + annotatedTableEntry.getTableName() + "\"");
 
-		// register vertex table
+		// register vertex table and layer
 		final TableEntry vertexTableEntry = configClient.getVertexTableEntry();
 		DbUtility.deleteGeometryMetadata(connection, vertexTableEntry.getTableName());
 		DbUtility.createTargetVertexTable(connection, vertexTableEntry.getTableName());
 		DbUtility.insertGeometryMetadata(connection, vertexTableEntry, serverSrid);
 		DbUtility.createSpatialIndex(connection, vertexTableEntry);
+		createdEntries.add(vertexTableEntry);
+		LOGGER.debug("Successfully created vertex table \"" + vertexTableEntry.getTableName() + "\"");
+
 		final GSFeatureTypeEncoder vertexFeatureTypeEncoder = getFeatureEncoder(vertexTableEntry, serverExtend, srs);
 		final GSLayerEncoder vertexLayerEncoder = new GSLayerEncoder();
 		vertexLayerEncoder.setDefaultStyle("STYLE_VERTICES_EXPIRATION");
 		if (!publisher.publishDBLayer(ws, ds, vertexFeatureTypeEncoder, vertexLayerEncoder)) {
 			LOGGER.debug("Could not register vertex layer \"" + vertexFeatureTypeEncoder.getName() + "\"");
+			performDbCleanup(connection, createdEntries);
 			throw new RuntimeException("Couldn't register vertex layer on the GeoServer");
 		}
 		LOGGER.debug("Successfully registered vertex layer \"" + vertexFeatureTypeEncoder.getName() + "\"");
 
+		// register area buffer table and layer
 		final TableEntry areaBufferTableEntry = configClient.getAreaBufferTableEntry();
 		DbUtility.deleteGeometryMetadata(connection, areaBufferTableEntry.getTableName());
 		DbUtility.createTargetBufferTable(connection, areaBufferTableEntry.getTableName());
 		DbUtility.insertGeometryMetadata(connection, areaBufferTableEntry, serverSrid);
 		DbUtility.createSpatialIndex(connection, areaBufferTableEntry);
+		createdEntries.add(areaBufferTableEntry);
+		LOGGER.debug("Successfully created areaBuffer table \"" + areaBufferTableEntry.getTableName() + "\"");
+
 		final GSFeatureTypeEncoder bufferFeatureTypeEncoder = getFeatureEncoder(areaBufferTableEntry, serverExtend, srs);
 		final GSLayerEncoder bufferLayerEncoder = new GSLayerEncoder();
 		bufferLayerEncoder.setDefaultStyle("STYLE_ISO_AREA");
 		if (!publisher.publishDBLayer(ws, ds, bufferFeatureTypeEncoder, bufferLayerEncoder)) {
 			LOGGER.warn("Could not register feature layer \"" + bufferFeatureTypeEncoder.getName() + "\"");
+			performDbCleanup(connection, createdEntries);
 			throw new RuntimeException("Couldn't register areaBuffer layer on the GeoServer");
 		}
 		LOGGER.debug("Successfully registered feature layer \"" + bufferFeatureTypeEncoder.getName() + "\"");
diff --git a/src/main/java/it/unibz/inf/isoga/web/JsonWebsocket.java b/src/main/java/it/unibz/inf/isoga/web/JsonWebsocket.java
index 052db368..26b35fe4 100644
--- a/src/main/java/it/unibz/inf/isoga/web/JsonWebsocket.java
+++ b/src/main/java/it/unibz/inf/isoga/web/JsonWebsocket.java
@@ -73,12 +73,14 @@ public class JsonWebsocket {
 		for (final ConfigClient clientDSetConfig : allClientDatasetConfigs) {
 			if (clientDSetConfig.isRegistered()) {
 				// unregister layers
-				for (final TableEntry layerName : clientDSetConfig.getLayers()) {
+				final Collection<TableEntry> layers = clientDSetConfig.getLayers();
+				for (final TableEntry layerName : layers) {
 					publisher.removeLayer(ws, layerName.getTableName());
 				}
 
 				// drop tables
-				for (final TableEntry tableEntry : clientDSetConfig.getTables()) {
+				final Collection<TableEntry> tables = clientDSetConfig.getTables();
+				for (final TableEntry tableEntry : tables) {
 					DbUtility.dropIndex(connection, tableEntry.getIndexName());
 					DbUtility.dropTable(connection, tableEntry.getTableName(), true);
 				}
diff --git a/src/main/java/it/unibz/inf/isoga/web/StartupListener.java b/src/main/java/it/unibz/inf/isoga/web/StartupListener.java
index ba660cc1..88465c08 100644
--- a/src/main/java/it/unibz/inf/isoga/web/StartupListener.java
+++ b/src/main/java/it/unibz/inf/isoga/web/StartupListener.java
@@ -52,7 +52,7 @@ public class StartupListener implements ServletContextListener {
 		final ConfigIsochrone isoConfig = ConfigIsochrone.getInstance();
 		final String prefixConf = isoConfig.getPrefix();
 		final boolean prefixSet = (prefixConf != null && prefixConf.length() > 0);
-		final String prefix = (prefixSet) ? ("^" + prefixConf + "\\_") : "^";
+		final String prefix = (prefixSet) ? (prefixConf + "\\_") : "";
 		final String[] regexpTables = new String[] {
 			prefix + "__\\_iso\\_edge%",
 			prefix + "__\\_iso\\_node%",
-- 
GitLab