Skip to content

Instantly share code, notes, and snippets.

@helospark
Last active May 30, 2017 12:57
Show Gist options
  • Save helospark/68e1dbbbe432658ef13cda0bbb5f58e7 to your computer and use it in GitHub Desktop.
Save helospark/68e1dbbbe432658ef13cda0bbb5f58e7 to your computer and use it in GitHub Desktop.
Code to implement H2's ";AUTO_SERVER=true" functionality for HSQLDB
package hsql_test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Optional;
import org.hsqldb.Server;
import org.hsqldb.persist.HsqlProperties;
import org.hsqldb.server.ServerAcl.AclFormatException;
/**
* Code to implement H2's ";AUTO_SERVER=true" functionality for HSQLDB.
*/
public class HsqlAutoserverManager {
private static final String AUTOSTART_SERVER_FILE_LOCK_POSTFIX = "_autoserver_lock";
private final String databaseFileName;
private Optional<Server> ownedServer = Optional.empty();
/**
* Constructor.
* @param databaseFileName file to create connection to, eq. "D:\\\\dbtest\\database.db" (\ needs escaping)
*/
public HsqlAutoserverManager(String databaseFileName) {
this.databaseFileName = databaseFileName;
}
/**
* Starts a connection either by starting a new server and connect to it, or find the running server for the given file and connect to it.
* TODO proper exception handling
* @return JDBC connection, make sure to close it
*/
public synchronized Connection createConnection() {
System.out.println("Starting Database");
try {
String portToConnect;
File databasePortFile = new File(databaseFileName + AUTOSTART_SERVER_FILE_LOCK_POSTFIX);
if (!databasePortFile.exists()) {
portToConnect = startNewServer();
writeServerPortToFile(databasePortFile, portToConnect);
} else {
portToConnect = readServerPortFromFile(databasePortFile);
}
return createJdbcHsqlConnectionToPort(portToConnect);
} catch (Exception e) {
throw new RuntimeException("Unable to create DB connection", e);
}
}
/**
* If this JVM started the server, the server will be shut down, otherwise no operation.
*/
public synchronized void shutdown() throws SQLException {
if (ownedServer.isPresent()) {
ownedServer.get().shutdown();
File file = new File(databaseFileName + AUTOSTART_SERVER_FILE_LOCK_POSTFIX);
file.delete();
System.out.println("Database shutdown");
}
}
private String startNewServer() throws IOException, AclFormatException, FileNotFoundException {
String randomPortToStartServerServerOn = String.valueOf(findRandomOpenPort());
HsqlProperties properties = createHsqlProperties(randomPortToStartServerServerOn);
startServer(properties);
return randomPortToStartServerServerOn;
}
private HsqlProperties createHsqlProperties(String port) {
HsqlProperties properties = new HsqlProperties();
properties.setProperty("server.database.0", "file:" + databaseFileName + ";hsqldb.write_delay=false");
properties.setProperty("server.dbname.0", "mydb");
properties.setProperty("server.port", port);
return properties;
}
private void startServer(HsqlProperties p) throws IOException, AclFormatException {
Server dserver = new Server();
dserver.setProperties(p);
dserver.setLogWriter(null); // can use custom writer
dserver.setErrWriter(null); // can use custom writer
dserver.start();
ownedServer = Optional.of(dserver);
}
private String readServerPortFromFile(File file) throws FileNotFoundException, IOException {
String portToConnect;
BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
portToConnect = is.readLine();
is.close();
return portToConnect;
}
private void writeServerPortToFile(File file, String port) throws IOException, FileNotFoundException {
file.createNewFile();
PrintStream fs = new PrintStream(new FileOutputStream(file));
fs.print(port);
fs.close();
}
private Integer findRandomOpenPort() throws IOException {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
private Connection createJdbcHsqlConnectionToPort(String portToConnect) throws SQLException {
String connectionUri = "jdbc:hsqldb:hsql://localhost:" + portToConnect + "/mydb";
System.out.println("Connecting to server: " + connectionUri);
return DriverManager.getConnection(connectionUri, "SA", "");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment