Commit 430a0630 authored by Luna Riegel's avatar Luna Riegel
Browse files

Feat: Implement in-memory and fallback of database

Adds the handling and creation of the embedded database in RAM, which is
used for the in-memory and fallback modes.
parent 99763e56
package de.hft.stuttgart.citydoctor2.database; package de.hft.stuttgart.citydoctor2.database;
import java.io.File; import java.io.File;
import java.util.StringJoiner;
/** /**
* Record containing the configuration parameters for the setup of the embedded database * Record containing the configuration parameters for the setup of the embedded database
...@@ -20,8 +21,10 @@ import java.io.File; ...@@ -20,8 +21,10 @@ import java.io.File;
public record EmbeddedDatabaseConfiguration(String databaseName, String databaseDirectory, int connectionPoolSize, public record EmbeddedDatabaseConfiguration(String databaseName, String databaseDirectory, int connectionPoolSize,
boolean inMemoryMode, boolean attemptFallback, boolean debugMode, boolean tempFileMode) { boolean inMemoryMode, boolean attemptFallback, boolean debugMode, boolean tempFileMode) {
private static final String IN_MEMORY_PREFIX= "mem:"; private static final String IN_MEMORY_PREFIX = "mem:";
private static final String AUTO_SERVER_PARAMETER = ";AUTO_SERVER=TRUE"; private static final String JDBC_DRIVER_PREFIX = "jdbc:h2:";
private static final String AUTO_SERVER_PARAMETER = "AUTO_SERVER=TRUE";
private static final String KEEP_ALIVE_PARAMETER = "DB_CLOSE_DELAY=-1";
private static final String FILE_PREFIX = "file://"; private static final String FILE_PREFIX = "file://";
/** /**
* Instantiates the default configuration for the embedded database. * Instantiates the default configuration for the embedded database.
...@@ -36,20 +39,31 @@ public record EmbeddedDatabaseConfiguration(String databaseName, String database ...@@ -36,20 +39,31 @@ public record EmbeddedDatabaseConfiguration(String databaseName, String database
true, true, true, false); true, true, true, false);
} }
public String wrapUrlWithH2JdbcDriver(String Url){
return JDBC_DRIVER_PREFIX + Url + getH2ParametersSuffix();
}
public String getInMemoryH2Url() { public String getInMemoryH2Url() {
return IN_MEMORY_PREFIX + databaseName; return wrapUrlWithH2JdbcDriver(IN_MEMORY_PREFIX + databaseName);
}
public String getFallbackH2Url(){
return getInMemoryH2Url() + ";" + KEEP_ALIVE_PARAMETER;
} }
public String getH2FileUrl(){ public String getH2FileUrl(){
return FILE_PREFIX + databaseDirectory + databaseName; return wrapUrlWithH2JdbcDriver(databaseDirectory + databaseName);
} }
public String getH2ParametersSuffix(){ public String getH2ParametersSuffix(){
StringJoiner joiner = new StringJoiner(";",";","");
if (debugMode){ if (debugMode){
return AUTO_SERVER_PARAMETER; joiner.add(AUTO_SERVER_PARAMETER);
} else { }
return ";"; if (inMemoryMode){
joiner.add(KEEP_ALIVE_PARAMETER);
} }
return joiner.toString();
} }
} }
...@@ -14,10 +14,9 @@ import org.apache.commons.lang3.SerializationException; ...@@ -14,10 +14,9 @@ import org.apache.commons.lang3.SerializationException;
import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.SerializationUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.h2gis.functions.factory.H2GISDBFactory;
import org.h2gis.utilities.wrapper.DataSourceWrapper; import org.h2gis.utilities.wrapper.DataSourceWrapper;
import org.h2gis.functions.factory.H2GISFunctions;
import javax.sql.DataSource;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
...@@ -26,6 +25,7 @@ import java.io.InvalidClassException; ...@@ -26,6 +25,7 @@ import java.io.InvalidClassException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -41,20 +41,21 @@ public class EmbeddedDatabaseHandler { ...@@ -41,20 +41,21 @@ public class EmbeddedDatabaseHandler {
private static final Logger logger = LogManager.getLogger(EmbeddedDatabaseHandler.class); private static final Logger logger = LogManager.getLogger(EmbeddedDatabaseHandler.class);
private final EmbeddedDatabaseConfiguration config; private final EmbeddedDatabaseConfiguration config;
private DataSourceWrapper dataSource; private DataSourceWrapper dataSource;
private File tempLoc = null; private File tempFileDBLocation = null;
public EmbeddedDatabaseHandler(EmbeddedDatabaseConfiguration dbConfig){ public EmbeddedDatabaseHandler(EmbeddedDatabaseConfiguration dbConfig){
config = dbConfig; config = dbConfig;
String jdbcUrl; String jdbcUrl;
try { try {
if (config.inMemoryMode()) { if (config.inMemoryMode()) {
jdbcUrl = createEmbeddedDataBase(config.getInMemoryH2Url()); jdbcUrl = setupInMemoryDataBase(config.getInMemoryH2Url());
} else if (config.tempFileMode()){ } else if (config.tempFileMode()){
Path tmpDir = Files.createTempDirectory(config.databaseDirectory()); Path tmpDir = Files.createTempDirectory(config.databaseDirectory());
tmpDir.toFile().deleteOnExit(); tmpDir.toFile().deleteOnExit();
String tempFileUrl = tmpDir.resolve(config.databaseName()).toFile().getAbsolutePath(); String tempFileUrl = tmpDir.resolve(config.databaseName()).toFile().getCanonicalPath();
jdbcUrl = createEmbeddedDataBase(tempFileUrl); jdbcUrl = createEmbeddedDataBase(config.wrapUrlWithH2JdbcDriver(tempFileUrl));
tempLoc = new File(tempFileUrl); tempFileDBLocation = new File(tempFileUrl+".mv.db");
tempFileDBLocation.deleteOnExit();
} else { } else {
jdbcUrl = createEmbeddedDataBase(config.getH2FileUrl()); jdbcUrl = createEmbeddedDataBase(config.getH2FileUrl());
} }
...@@ -66,7 +67,7 @@ public class EmbeddedDatabaseHandler { ...@@ -66,7 +67,7 @@ public class EmbeddedDatabaseHandler {
if (config.attemptFallback()){ if (config.attemptFallback()){
logger.info("Attempting fallback to in-memory database"); logger.info("Attempting fallback to in-memory database");
try { try {
jdbcUrl = createEmbeddedDataBase(config.getInMemoryH2Url()); jdbcUrl = setupInMemoryDataBase(config.getFallbackH2Url());
} catch (Exception e1) { } catch (Exception e1) {
throw new EmbeddedDatabaseHandlerException("Fallback to in-memory database failed, embedded database could not be created", e1); throw new EmbeddedDatabaseHandlerException("Fallback to in-memory database failed, embedded database could not be created", e1);
} }
...@@ -93,15 +94,26 @@ public class EmbeddedDatabaseHandler { ...@@ -93,15 +94,26 @@ public class EmbeddedDatabaseHandler {
} }
private String createEmbeddedDataBase(String dbUrl) throws SQLException { private String createEmbeddedDataBase(String dbUrl) throws SQLException {
DataSource source = H2GISDBFactory.createDataSource(dbUrl, // DataSource source = H2GISDBFactory.createDataSource("file://"+dbUrl,
true, config.getH2ParametersSuffix()); // true, config.getH2ParametersSuffix());
try (Connection con = source.getConnection()) { // try (Connection con = source.getConnection()) {
// return con.getMetaData().getURL();
// }
try (Connection con = DriverManager.getConnection(dbUrl,"sa","sa")){
H2GISFunctions.load(con);
return con.getMetaData().getURL(); return con.getMetaData().getURL();
} }
} }
public File getTempLoc(){ private String setupInMemoryDataBase(String dbUrl) throws SQLException{
return this.tempLoc; try (Connection con = DriverManager.getConnection(dbUrl,"sa","sa")){
H2GISFunctions.load(con);
return con.getMetaData().getURL();
}
}
public File getTempFileDBLocation(){
return this.tempFileDBLocation;
} }
......
...@@ -16,7 +16,6 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; ...@@ -16,7 +16,6 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import org.citygml4j.core.model.building.AbstractBuilding; import org.citygml4j.core.model.building.AbstractBuilding;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
...@@ -33,37 +32,38 @@ import static org.junit.Assert.fail; ...@@ -33,37 +32,38 @@ import static org.junit.Assert.fail;
public class EmbeddedDataBaseHandlerTest { public class EmbeddedDataBaseHandlerTest {
private EmbeddedDatabaseHandler handler = new EmbeddedDatabaseHandler(new EmbeddedDatabaseConfiguration()); private EmbeddedDatabaseHandler handler = new EmbeddedDatabaseHandler(new EmbeddedDatabaseConfiguration());
@Before
public void resetDatabase() {
try {
handler.setupFeaturesTable();
} catch (Exception e) {
fail(e.getMessage());
}
}
//TODO: FIX Test failures
@Test @Test
public void testTempFileConfiguration(){ public void testTempFileConfiguration(){
EmbeddedDatabaseConfiguration tempFileconfig = new EmbeddedDatabaseConfiguration("database", EmbeddedDatabaseConfiguration tempFileconfig = new EmbeddedDatabaseConfiguration("database",
"inTempConfig",1, false,false, "inTempConfig",1, false,false,
false,true); false,true);
assertNull(handler.getTempLoc());
EmbeddedDatabaseHandler tempHandler = new EmbeddedDatabaseHandler(tempFileconfig); EmbeddedDatabaseHandler tempHandler = new EmbeddedDatabaseHandler(tempFileconfig);
assertTrue(tempHandler.getTempLoc().exists()); assertTrue(tempHandler.getTempFileDBLocation().exists());
} }
@Test @Test
public void testInMemoryConfiguration(){ public void testInMemoryConfiguration() throws CityGmlParseException, InvalidGmlFileException {
EmbeddedDatabaseConfiguration inMemoryConfig = new EmbeddedDatabaseConfiguration("database", EmbeddedDatabaseConfiguration inMemoryConfig = new EmbeddedDatabaseConfiguration("database",
"irrelevant",1, true,false, "irrelevant",1, true,false,
false,false); false,false);
EmbeddedDatabaseHandler memHandler = new EmbeddedDatabaseHandler(inMemoryConfig); EmbeddedDatabaseHandler memHandler = new EmbeddedDatabaseHandler(inMemoryConfig);
assertFalse(memHandler.getTempLoc().exists()); assertNull(memHandler.getTempFileDBLocation());
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = CityGmlParser.nestedCityGmlFileParse("src/test/resources/SimpleSolid_SrefBS.gml", config);
Building b = model.getBuildings().toList().get(0);
assertEquals(0, memHandler.getFeatureCount());
memHandler.marshallCityObject(b);
assertEquals(1, memHandler.getFeatureCount());
CityObject co = memHandler.unmarshallCityObject(b.getGmlId());
assertNotNull(co);
assertTrue(co instanceof Building);
} }
@Test @Test
public void testGetBboxIntersectingObjects() { public void testGetBboxIntersectingObjects() {
handler.setupFeaturesTable();
Building b = new Building(); Building b = new Building();
Building b2 = new Building(); Building b2 = new Building();
b2.setGmlObject(Mockito.mock(AbstractBuilding.class)); b2.setGmlObject(Mockito.mock(AbstractBuilding.class));
...@@ -144,6 +144,7 @@ public class EmbeddedDataBaseHandlerTest { ...@@ -144,6 +144,7 @@ public class EmbeddedDataBaseHandlerTest {
@Test @Test
public void testGetBboxBufferIntersectingObjects() { public void testGetBboxBufferIntersectingObjects() {
handler.setupFeaturesTable();
Building b = new Building(); Building b = new Building();
Building b2 = new Building(); Building b2 = new Building();
b2.setGmlObject(Mockito.mock(AbstractBuilding.class)); b2.setGmlObject(Mockito.mock(AbstractBuilding.class));
...@@ -230,6 +231,7 @@ public class EmbeddedDataBaseHandlerTest { ...@@ -230,6 +231,7 @@ public class EmbeddedDataBaseHandlerTest {
Building b = model.getBuildings().toList().get(0); Building b = model.getBuildings().toList().get(0);
assertNotNull(b); assertNotNull(b);
assertEquals(1, handler.getFeatureCount());
handler.marshallCityObject(b); handler.marshallCityObject(b);
assertEquals(1, handler.getFeatureCount()); assertEquals(1, handler.getFeatureCount());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment