au.net.causal.maven.plugins.boxdb.AbstractDatabaseMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of boxdb-maven-plugin Show documentation
Show all versions of boxdb-maven-plugin Show documentation
Maven plugin to start databases using Docker and VMs
package au.net.causal.maven.plugins.boxdb;
import au.net.causal.maven.plugins.boxdb.db.BoxConfiguration;
import au.net.causal.maven.plugins.boxdb.db.BoxContext;
import au.net.causal.maven.plugins.boxdb.db.BoxDatabase;
import au.net.causal.maven.plugins.boxdb.db.BoxDatabaseException;
import au.net.causal.maven.plugins.boxdb.db.BoxDatabaseFactory;
import au.net.causal.maven.plugins.boxdb.db.BoxLookup;
import au.net.causal.maven.plugins.boxdb.db.DatabaseStage;
import au.net.causal.maven.plugins.boxdb.db.DockerService;
import au.net.causal.maven.plugins.boxdb.db.ExecutionMode;
import au.net.causal.maven.plugins.boxdb.db.ProjectConfiguration;
import au.net.causal.maven.plugins.boxdb.db.ImageUpdateMode;
import au.net.causal.maven.plugins.boxdb.db.ScriptExecution;
import au.net.causal.maven.plugins.boxdb.db.ScriptSelection;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.shared.filtering.MavenReaderFilter;
import org.apache.maven.shared.filtering.MavenResourcesFiltering;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.RemoteRepository;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public abstract class AbstractDatabaseMojo extends AbstractDockerDbMojo
{
@Parameter(property = "db.type")
private String databaseType;
@Parameter(property = "db.version")
private String databaseVersion;
@Parameter(property = "db.name")
private String databaseName;
@Parameter(property = "db.containerName")
private String containerName;
@Parameter(property = "db.file")
private File databaseFile;
@Parameter(property = "db.restoreFile")
private File databaseRestoreFile;
@Parameter(property = "db.user")
private String databaseUser;
@Parameter(property = "db.password")
private String databasePassword;
@Parameter
private Map databaseConfiguration = new LinkedHashMap<>();
/**
* Only used to allow databaseConfiguration parameter to be set from the command line. In plugin
* configurations, only databaseConfiguration should be used.
*/
@Parameter(property = "db.configuration")
private List databaseConfigurationList = new ArrayList<>();
@Parameter(property = "db.initialize")
private Boolean databaseInitialize;
@Parameter(property = "boxdb.imageUpdateMode", defaultValue = "ON", required = true)
private ImageUpdateMode imageUpdateMode;
/**
* Maximum time to wait in seconds for database to start up.
*/
@Parameter(property = "boxdb.startupTimeout", defaultValue = "60", required = true)
protected long startupTimeout;
/**
* Maximum time in seconds a SQL script may run before it is terminated. Timeouts may not have effect on all database types.
*/
@Parameter(property = "boxdb.scriptTimeout", defaultValue = "3600", required = true)
protected long scriptTimeout;
/**
* Maximum time in seconds a database backup or restore may run before it is terminated. Timeouts may not have effect
* on all database types.
*/
@Parameter(property = "boxdb.backupTimeout", defaultValue = "3600", required = true)
protected long backupTimeout;
/**
* If true, passwords for connections are displayed in console output. If false (the default), they are not.
*/
@Parameter(property = "boxdb.displayPasswords", defaultValue = "false")
protected boolean displayPasswords;
@Parameter(defaultValue = "${project.build.directory}/boxdb", required = true)
protected File workDirectory;
@Parameter(defaultValue = "${user.home}/.boxdb", required = true)
protected File globalConfigDirectory;
@Parameter
protected BoxConfiguration box = new BoxConfiguration();
@Parameter(defaultValue = ScriptExecution.DEFAULT_BASE_DIRECTORY)
private File defaultScriptDirectory;
@Parameter(property = "db.deleteOnStop")
protected boolean deleteOnStop;
@Component
protected MavenResourcesFiltering resourcesFiltering;
@Component
protected MavenReaderFilter readerFilter;
@Component
protected RepositorySystem repositorySystem;
@Component
protected ArchiverManager archiverManager;
@Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
protected RepositorySystemSession repoSession;
@Parameter(defaultValue = "${project.remotePluginRepositories}", readonly = true)
protected List remoteRepos;
protected final List tempFilesCreated = new ArrayList<>();
@Override
public void execute() throws MojoExecutionException, MojoFailureException
{
//If we don't have a real project then use tempdir as work directory
boolean usingTempDirectory = false;
if (project == null || project.getFile() == null)
{
//Can't do this - to map scripts to docker machine they need to be inside user dir on Mac
//workDirectory = new File(System.getProperty("java.io.tmpdir"));
workDirectory = new File(".").getAbsoluteFile();
usingTempDirectory = true;
}
if (databaseType != null)
box.setDatabaseType(databaseType);
if (databaseVersion != null)
box.setDatabaseVersion(databaseVersion);
if (containerName != null)
box.setContainerName(containerName);
if (databaseName != null)
box.setDatabaseName(databaseName);
if (databaseFile != null)
box.setDatabaseFile(databaseFile.toPath());
if (databaseRestoreFile != null)
box.setRestoreFile(databaseRestoreFile);
if (databaseUser != null)
box.setDatabaseUser(databaseUser);
if (databasePassword != null)
box.setDatabasePassword(databasePassword);
if (settings.isOffline())
imageUpdateMode = ImageUpdateMode.OFF;
if (!databaseConfigurationList.isEmpty())
fillInMapFromListParameter(databaseConfiguration, databaseConfigurationList);
if (!databaseConfiguration.isEmpty())
box.getConfiguration().putAll(databaseConfiguration);
if (databaseInitialize != null)
box.setInitializeDatabase(databaseInitialize);
//Fill in box default scripts if needed
if (box.getScriptExecutions().isEmpty())
box.setScriptExecutions(defaultScriptExecutions());
try
{
super.execute();
}
finally
{
//If we don't have a project we have used the user's temp directory
//so try and clean this up after execution
if (usingTempDirectory)
{
//Delete in reverse order, so we get directories last
Collections.reverse(tempFilesCreated);
for (Path tempFile : tempFilesCreated)
{
try
{
getLog().info("Delete temp file " + tempFile);
Files.delete(tempFile);
}
catch (IOException e)
{
getLog().warn("Error deleting temp file " + tempFile);
}
}
}
}
}
private void fillInMapFromListParameter(Map super String, ? super String> map, List list)
{
for (String item : list)
{
String[] kv = item.split(Pattern.quote("="), 2);
if (kv.length == 2)
map.put(kv[0], kv[1]);
}
}
private List defaultScriptExecutions()
{
ScriptExecution createExecution = new ScriptExecution();
createExecution.setDirectory(defaultScriptDirectory);
createExecution.setIgnoreMissing(true);
createExecution.setSelection(ScriptSelection.FIRST);
createExecution.setStage(DatabaseStage.CREATE);
createExecution.setMode(ExecutionMode.NATIVE);
createExecution.getScripts().add("create-${box.databaseType}-${box.databaseVersion}.sql");
createExecution.getScripts().add("create-${box.databaseType}.sql");
createExecution.getScripts().add("create.sql");
ScriptExecution createJdbcExecution = new ScriptExecution();
createJdbcExecution.setDirectory(defaultScriptDirectory);
createJdbcExecution.setIgnoreMissing(true);
createJdbcExecution.setSelection(ScriptSelection.FIRST);
createJdbcExecution.setStage(DatabaseStage.CREATE);
createJdbcExecution.setMode(ExecutionMode.JDBC);
createJdbcExecution.getScripts().add("create-jdbc-${box.databaseType}-${box.databaseVersion}.sql");
createJdbcExecution.getScripts().add("create-jdbc-${box.databaseType}.sql");
createJdbcExecution.getScripts().add("create-jdbc.sql");
ScriptExecution setupExecution = new ScriptExecution();
setupExecution.setDirectory(defaultScriptDirectory);
setupExecution.setIgnoreMissing(true);
setupExecution.setSelection(ScriptSelection.FIRST);
setupExecution.setStage(DatabaseStage.SETUP);
setupExecution.setMode(ExecutionMode.NATIVE);
setupExecution.getScripts().add("setup-${box.databaseType}-${box.databaseVersion}.sql");
setupExecution.getScripts().add("setup-${box.databaseType}.sql");
setupExecution.getScripts().add("setup.sql");
ScriptExecution setupJdbcExecution = new ScriptExecution();
setupJdbcExecution.setDirectory(defaultScriptDirectory);
setupJdbcExecution.setIgnoreMissing(true);
setupJdbcExecution.setSelection(ScriptSelection.FIRST);
setupJdbcExecution.setStage(DatabaseStage.SETUP);
setupJdbcExecution.setMode(ExecutionMode.JDBC);
setupJdbcExecution.getScripts().add("setup-jdbc-${box.databaseType}-${box.databaseVersion}.sql");
setupJdbcExecution.getScripts().add("setup-jdbc-${box.databaseType}.sql");
setupJdbcExecution.getScripts().add("setup-jdbc.sql");
ScriptExecution postRestoreExecution = new ScriptExecution();
postRestoreExecution.setDirectory(defaultScriptDirectory);
postRestoreExecution.setIgnoreMissing(true);
postRestoreExecution.setSelection(ScriptSelection.FIRST);
postRestoreExecution.setStage(DatabaseStage.POST_RESTORE);
postRestoreExecution.setMode(ExecutionMode.NATIVE);
postRestoreExecution.getScripts().add("postrestore-${box.databaseType}-${box.databaseVersion}.sql");
postRestoreExecution.getScripts().add("postrestore-${box.databaseType}.sql");
postRestoreExecution.getScripts().add("postrestore.sql");
ScriptExecution postRestoreJdbcExecution = new ScriptExecution();
postRestoreJdbcExecution.setDirectory(defaultScriptDirectory);
postRestoreJdbcExecution.setIgnoreMissing(true);
postRestoreJdbcExecution.setSelection(ScriptSelection.FIRST);
postRestoreJdbcExecution.setStage(DatabaseStage.POST_RESTORE);
postRestoreJdbcExecution.setMode(ExecutionMode.JDBC);
postRestoreJdbcExecution.getScripts().add("postrestore-jdbc-${box.databaseType}-${box.databaseVersion}.sql");
postRestoreJdbcExecution.getScripts().add("postrestore-jdbc-${box.databaseType}.sql");
postRestoreJdbcExecution.getScripts().add("postrestore-jdbc.sql");
return Arrays.asList(createExecution, createJdbcExecution,
setupExecution, setupJdbcExecution,
postRestoreExecution, postRestoreJdbcExecution);
}
protected ImageUpdateMode getImageUpdateMode()
{
return imageUpdateMode;
}
protected BoxDatabaseFactory databaseFactory(ExceptionalSupplier serviceHub)
throws MojoExecutionException, BoxDatabaseException
{
String dbType = box.getDatabaseType();
BoxLookup lookup = new BoxLookup(getLog(), AbstractDatabaseMojo.class.getClassLoader());
BoxDatabaseFactory factory = lookup.findFactory(dbType);
if (factory == null)
{
throw new MojoExecutionException("Database type '" + dbType + "' not supported. Available database types: " +
lookup.getAvailableBoxFactoryNames());
}
return factory;
}
protected BoxDatabase database(ExceptionalSupplier serviceHub)
throws MojoExecutionException, BoxDatabaseException
{
BoxDatabaseFactory factory = databaseFactory(serviceHub);
BoxContext context = new BoxContext(serviceHub, authConfigFactory, workDirectory.toPath(), globalConfigDirectory.toPath(),
getImageUpdateMode(), getLog(), logSpecFactory, session, resourcesFiltering,
readerFilter, repositorySystem, repoSession, remoteRepos, archiverManager);
ProjectConfiguration projectConfiguration = new ProjectConfiguration(project, settings, Duration.ofSeconds(scriptTimeout), Duration.ofSeconds(backupTimeout));
return factory.create(box, projectConfiguration, context);
}
protected void stopDatabaseContainer(BoxDatabase boxDatabase)
throws MojoExecutionException, BoxDatabaseException
{
boolean exists = true;
if (!boxDatabase.exists())
{
getLog().warn("Database '" + boxDatabase.getName() + "' does not exist");
exists = false;
}
else if (!boxDatabase.isRunning())
getLog().info("Database '" + boxDatabase.getName() + "' is not running");
else
{
getLog().info("Stopping database '" + boxDatabase.getName() + "'");
boxDatabase.stop();
getLog().info("Database stopped.");
}
if (exists && deleteOnStop)
{
getLog().info("Deleting database '" + boxDatabase.getName() + "'");
boxDatabase.delete();
}
}
}