
com.github.slavaz.maven.plugin.postgresql.embedded.psql.IsolatedPgInstanceManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of embedded-postgresql-maven-plugin Show documentation
Show all versions of embedded-postgresql-maven-plugin Show documentation
This is a Maven plugin for running an embedded PostgreSQL server, mostly for integration tests.
The newest version!
package com.github.slavaz.maven.plugin.postgresql.embedded.psql;
import com.github.slavaz.maven.plugin.postgresql.embedded.psql.data.PgInstanceProcessData;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Starts a PostgreSQL instance in a separate thread using a separate classloader. This is necessary, because the
* Embedded PostgreSQL registers a shutdown hook which is run when the JVM shuts down, to shut down the process. When a
* build fails, this plugin's "stop" goal is never run, so we rely on the shutdown hook to shut down PostgreSQL and
* clean up resources. However, Maven plugins run in separate class loaders, which means the required classes to shut
* down PostgreSQL are not available any more in the shutdown hook. By starting a thread with our own class loader,
* we ensure that the classes are available during the shutdown hook.
*/
public class IsolatedPgInstanceManager {
private final ExecutorService executor = Executors.newSingleThreadExecutor(
new ThreadFactoryBuilder()
.setNameFormat("postgres-embedded-%d")
.build()
);
private final ClassLoader classLoader;
public IsolatedPgInstanceManager(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public void start(IPgInstanceProcessData data) {
Future> postgresTask = executor.submit(() -> {
Method startPostgres = getMethod(
"startPostgres", String.class, int.class, String.class, String.class, String.class, Path.class, String.class, String.class);
invokeStaticMethod(startPostgres, data.getPgServerVersion(), data.getPgPort(), data.getDbName(), data.getUserName(),
data.getPassword(), data.getPgDatabaseDir(), data.getPgLocale(), data.getPgCharset());
});
try {
postgresTask.get();
} catch (ExecutionException | InterruptedException e) {
throw new IllegalStateException("Embedded Postgres thread was unsuccessful.", e);
}
}
public void stop() {
invokeStaticMethod(getMethod("stopPostgres"));
executor.shutdown();
}
public static void startPostgres(String pgServerVersion, int pgPort, String dbName, String userName, String password,
Path pgDatabaseDir, String pgLocale, String pgCharset) throws Exception {
PgInstanceManager.start(new PgInstanceProcessData(pgServerVersion, pgPort, dbName, userName, password, pgDatabaseDir, pgLocale, pgCharset));
}
public static void stopPostgres() throws IOException {
PgInstanceManager.stop();
}
private Method getMethod(String methodName, Class>... parameterTypes) {
Class> managerClass = loadClass(IsolatedPgInstanceManager.class.getName());
try {
return managerClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException("No method " + methodName + " on " + managerClass, e);
}
}
private Class> loadClass(String className) {
try {
return classLoader.loadClass(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class not found: " + className, e);
}
}
private static void invokeStaticMethod(Method m, Object... arguments) {
try {
m.invoke(null, arguments);
} catch (IllegalAccessException e) {
throw new RuntimeException("Method " + m.getName() + " not accessible", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Invocation of method " + m.getName() + " threw exception", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy