All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.net.causal.maven.plugins.boxdb.AbstractDatabaseMojo Maven / Gradle / Ivy

There is a newer version: 3.3
Show newest version
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.DatabaseLog;
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 org.eclipse.aether.resolution.DependencyResolutionException;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
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;

    /**
     * The collation to use for creating the database.  Default is dependent on database type.
     * 
     * @since 2.0
     */
    @Parameter(property = "db.collation")
    private String databaseCollation;

    /**
     * The encoding to use for creating the database.  Default is dependent on database type.
     * 
     * @since 2.0
     */
    @Parameter(property = "db.encoding")
    private String databaseEncoding;

    /**
     * Shortcut for setting additional box database configuration options globally.  Available options are dependent on database type.
     */
    @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.  Each entry is in the form key=value.
     */
    @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 = "600", 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;

    /**
     * Time to wait in milliseconds during graceful database stop before doing a forced kill.  Timeouts may not have effect on all database types.
     * Timeout of zero means wait indefinitely.
     */
    @Parameter(property = "boxdb.killTimeout", defaultValue = "0", required = true)
    protected long killTimeout;
    
    /**
     * Amount of time in milliseconds to wait between polling when checking database operations, scripts, etc.
     * When polling is used depends on database type.
     */
    @Parameter(property = "boxdb.pollTimeMillis", defaultValue = "300", required = true)
    protected long pollTimeMillis;
    
    /**
     * 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;

    /**
     * Additional Maven artifacts to search for BoxDatabase implementations.
     * Each element in the list is a string in the form groupId:artifactId:version.
     * 

* * This can be a handy alternative to specifying additional dependency elements when configuring the * plugin, especially when running this Maven plugin without a Maven project. */ @Parameter(property = "boxdb.artifacts") private List additionalBoxArtifacts = new ArrayList<>(); /** * If true, completely skip execution of BoxDB. Useful for skipping execution from command line. */ @Parameter(property = "boxdb.skip", defaultValue = "false") private boolean skipExecution; @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<>(); /** * Cache to create classloaders at static level to prevent as much as possible to create too many classloaders. */ protected static final ClassLoaderCache classLoaderCache = new ClassLoaderCache(); @Override public void execute() throws MojoExecutionException, MojoFailureException { if (skipExecution) { getLog().info("Skipping execution"); return; } //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 (databaseCollation != null) box.setDatabaseCollation(databaseCollation); if (databaseEncoding != null) box.setDatabaseEncoding(databaseEncoding); 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 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}-${box.databaseVersion.major}.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}-${box.databaseVersion.major}.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}-${box.databaseVersion.major}.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}-${box.databaseVersion.major}.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}-${box.databaseVersion.major}.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}-${box.databaseVersion.major}.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 ClassLoader createBoxClassLoader() throws MojoExecutionException { getLog().debug("Additional artifacts: " + additionalBoxArtifacts); if (additionalBoxArtifacts == null || additionalBoxArtifacts.isEmpty()) return AbstractDatabaseMojo.class.getClassLoader(); try { List jarFiles = DependencyUtils.resolveDependenciesFromStrings(additionalBoxArtifacts, repositorySystem, repoSession, remoteRepos); List jarUrls = new ArrayList<>(jarFiles.size()); for (Path jarFile : jarFiles) { jarUrls.add(jarFile.toUri().toURL()); } URL[] jarUrlArray = jarUrls.stream().toArray(URL[]::new); return URLClassLoader.newInstance(jarUrlArray, AbstractDatabaseMojo.class.getClassLoader()); } catch (DependencyResolutionException e) { throw new MojoExecutionException("Failed to resolve additional box artifacts: " + e.getMessage(), e); } catch (MalformedURLException e) { throw new MojoExecutionException("Failed to generate URLs from dependency JARs: " + e, e); } } protected BoxDatabaseFactory databaseFactory(ExceptionalSupplier serviceHub) throws MojoExecutionException, BoxDatabaseException { ClassLoader boxClassLoader = createBoxClassLoader(); String dbType = box.getDatabaseType(); BoxLookup lookup = new BoxLookup(getLog(), boxClassLoader); 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, classLoaderCache); ProjectConfiguration projectConfiguration = new ProjectConfiguration(project, settings, Duration.ofSeconds(scriptTimeout), Duration.ofSeconds(backupTimeout), Duration.ofMillis(pollTimeMillis), killTimeout == 0 ? null : Duration.ofMillis(killTimeout)); 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(); } } protected void dumpLog(DatabaseLog dbLog) throws BoxDatabaseException, IOException { getLog().info(dbLog.getName() + ":"); try (StringWriter w = new StringWriter()) { dbLog.save(w); getLog().info(w.getBuffer()); } } protected void dumpLogToError(DatabaseLog dbLog) throws BoxDatabaseException, IOException { getLog().error(dbLog.getName() + ":"); try (StringWriter w = new StringWriter()) { dbLog.save(w); getLog().error(w.getBuffer()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy