/** * Copyright (C) 2015 Michael Schnell. All rights reserved. * http://www.fuin.org/ * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) any * later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see http://www.gnu.org/licenses/. */ package org.fuin.esmp; import java.io.File; import java.io.IOException; import java.io.LineNumberReader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import org.apache.commons.exec.OS; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Parameter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.impl.StaticLoggerBinder; /** * Base class for all mojos. */ public abstract class AbstractEventStoreMojo extends AbstractMojo { private static final Logger LOG = LoggerFactory.getLogger(AbstractEventStoreMojo.class); private static final String PID_FILE_NAME = "event-store-pid"; /** * Full URL where the event store file to download is located. If set, this * always overrides the <code>base-url</code>, <code>archive-name</code>, * <code>archive-version</code> and <code>archive-extension</code> * parameters. */ @Parameter(name = "download-url") private String downloadUrl; /** * Base URl where the event store archives are located. This is used to * construct an archive URl for the OS where the build script is executed. */ @Parameter(name = "base-url", defaultValue = "http://download.geteventstore.com/binaries/") private String baseUrl = "http://download.geteventstore.com/binaries/"; /** * Name of the archive (Like "EventStore-OSS-Win" or "EventStore-OSS-Linux") * without version and file extension. This is used to construct an archive * URl for the OS where the build script is executed. */ @Parameter(name = "archive-name") private String archiveName; /** * Version of the archive (Like "3.8.1"). This is used to construct an * archive URl for the OS where the build script is executed. If it's not * set, the latest version will be used by default. */ @Parameter(name = "archive-version") private String archiveVersion; /** * File extension of the archive (Like "zip" or "tar.gz"). This is used to * construct an archive URl for the OS where the build script is executed. */ @Parameter(name = "archive-extension") private String archiveExtension; /** * The target build directory. */ @Parameter(name = "target-dir", property = "project.build.directory") private File targetDir = new File("./target"); /** * Directory where the event store should be installed. The downloaded * archive will be uncompressed into this directory. */ @Parameter(name = "event-store-dir") private File eventStoreDir; /** * Checks if a variable is not <code>null</code> and throws an * <code>IllegalNullArgumentException</code> if this rule is violated. * * @param name * Name of the variable to be displayed in an error message. * @param value * Value to check for <code>null</code>. * * @throws MojoExecutionException * Checked value was NULL. */ protected final void checkNotNull(final String name, final Object value) throws MojoExecutionException { if (value == null) { throw new MojoExecutionException(name + " cannot be null!"); } } @Override public final void execute() throws MojoExecutionException { StaticLoggerBinder.getSingleton().setMavenLog(getLog()); init(); LOG.info("download-url={}", downloadUrl); LOG.info("base-url={}", baseUrl); LOG.info("archive-name={}", archiveName); LOG.info("archive-version={}", archiveVersion); LOG.info("archive-extension={}", archiveExtension); LOG.info("target-dir={}", targetDir); LOG.info("event-store-dir={}", eventStoreDir); executeGoal(); } // CHECKSTYLE:OFF Cyclomatic complexity - Not nice, but OK for now private void init() throws MojoExecutionException { // Only initialize other stuff if no full URL is provided if (downloadUrl == null) { if (archiveVersion == null) { initUsingLatest(); } else { initUsingVersion(); } } // If it's not explicitly set, create it with target directory if (eventStoreDir == null) { if (downloadUrl.endsWith(".zip")) { eventStoreDir = new File(canonicalFile(targetDir), FilenameUtils.getBaseName(downloadUrl)); } else if (downloadUrl.endsWith(".tar.gz")) { eventStoreDir = new File(canonicalFile(targetDir), FilenameUtils.getBaseName(FilenameUtils.getBaseName(downloadUrl))); } else { throw new MojoExecutionException("Cannot handle archive with this extension: " + downloadUrl); } } } // CHECKSTYLE:ON private void initUsingLatest() throws MojoExecutionException { try { final File jsonVersionFile = new File(canonicalFile(targetDir), "event-store-versions.json"); final Downloads downloads = new Downloads(jsonVersionFile); downloads.parse(); final String os; if (OS.isFamilyWindows()) { os = "win"; } else if (OS.isFamilyMac()) { os = "osx-10.10"; } else if (OS.isFamilyUnix()) { os = "ubuntu-14.04"; } else { throw new MojoExecutionException("Unknown OS - You must use the 'archive-name' parameter"); } final DownloadOS downloadOS = downloads.findOS(os); if (downloadOS == null) { throw new MojoExecutionException( "Couldn't find OS '" + os + "' in '" + downloads.getJsonDownloadsFile() + "'"); } final DownloadVersion version = downloadOS.getLatestVersion(); if (version == null) { throw new MojoExecutionException("No latest version found for OS '" + os + "'"); } downloadUrl = version.getUrl(); } catch (final IOException ex) { throw new MojoExecutionException("Error parsing the event store version file", ex); } } // CHECKSTYLE:OFF Cyclomatic Complexity - Code is no highlight, but OK for now private void initUsingVersion() throws MojoExecutionException { // Make sure base URL always ends with a slash if (!baseUrl.endsWith("/")) { baseUrl = baseUrl + "/"; } // Supply variables that are OS dependent if (OS.isFamilyWindows()) { if (archiveName == null) { archiveName = "EventStore-OSS-Win"; } if (archiveExtension == null) { archiveExtension = "zip"; } } else if (OS.isFamilyMac()) { if (archiveName == null) { archiveName = "EventStore-OSS-Mac"; } if (archiveExtension == null) { archiveExtension = "tar.gz"; } } else if (OS.isFamilyUnix()) { if (archiveName == null) { if (isUbuntuVersion()) { archiveName = "EventStore-OSS-Ubuntu-14.04"; } else { archiveName = "EventStore-OSS-Linux"; } } if (archiveExtension == null) { archiveExtension = "tar.gz"; } } else { if (archiveName == null) { throw new MojoExecutionException("Unknown OS - You must use the 'archive-name' parameter"); } if (archiveExtension == null) { throw new MojoExecutionException("Unknown OS - You must use the 'archive-ext' parameter"); } } downloadUrl = baseUrl + archiveName + "-v" + archiveVersion + "." + archiveExtension; } // CHECKSTYLE:ON private boolean isUbuntuVersion() { if (archiveVersion == null) { return true; } // Filename has changed from 3.1.x on if (archiveVersion.startsWith("3.0.") || archiveVersion.startsWith("2.0.") || archiveVersion.startsWith("1.0.")) { return false; } return true; } private File canonicalFile(final File file) throws MojoExecutionException { try { return file.getCanonicalFile(); } catch (final IOException ex) { throw new MojoExecutionException("Error creating canonical file: " + file, ex); } } /** * Returns the full URL where the event store file to download is located. * * @return Download archive URL. * * @throws MojoExecutionException * Error initializing the variable. */ public final String getDownloadUrl() throws MojoExecutionException { if (downloadUrl == null) { init(); } return downloadUrl; } /** * Sets the full URL where the event store file to download is located. * * @param downloadUrl * Download archive URL to set */ public final void setDownloadUrl(final String downloadUrl) { this.downloadUrl = downloadUrl; } /** * Returns the base URl where the event store archives are located. * * @return Base URL where archives are located. * * @throws MojoExecutionException * Error initializing the variable. */ public final String getBaseUrl() throws MojoExecutionException { if (baseUrl == null) { init(); } return baseUrl; } /** * Sets the base URl where the event store archives are located. * * @param baseUrl * Base URL where archives are located to set */ public final void setBaseUrl(final String baseUrl) { this.baseUrl = baseUrl; } /** * Returns the name of the archive (Like "EventStore-OSS-Win" or * "EventStore-OSS-Linux") without version and file extension. * * @return the archiveName * * @throws MojoExecutionException * Error initializing the variable. */ public final String getArchiveName() throws MojoExecutionException { if (archiveName == null) { init(); } return archiveName; } /** * Sets the name of the archive (Like "EventStore-OSS-Win" or * "EventStore-OSS-Linux") without version and file extension. * * @param archiveName * Archive name to set. */ public final void setArchiveName(final String archiveName) { this.archiveName = archiveName; } /** * Returns the version of the archive (Like "3.0.5"). * * @return Event store version. */ public final String getArchiveVersion() { return archiveVersion; } /** * Sets the version of the archive (Like "3.0.5"). * * @param archiveVersion * The event store version to set. */ public final void setArchiveVersion(final String archiveVersion) { this.archiveVersion = archiveVersion; } /** * Returns the file extension of the archive (Like "zip" or "tar.gz"). * * @return Archive file extension. * * @throws MojoExecutionException * Error initializing the variable. */ public final String getArchiveExtension() throws MojoExecutionException { if (archiveExtension == null) { init(); } return archiveExtension; } /** * Sets the file extension of the archive (Like "zip" or "tar.gz"). * * @param archiveExtension * Archive file extension to set. */ public final void setArchiveExtension(final String archiveExtension) { this.archiveExtension = archiveExtension; } /** * Returns the directory where the event store should be installed. The * downloaded archive will be uncompressed into this directory. * * @return Target directory. * * @throws MojoExecutionException * Error initializing the variable. */ public final File getEventStoreDir() throws MojoExecutionException { if (eventStoreDir == null) { init(); } return eventStoreDir; } /** * Sets the directory where the event store should be installed. The * downloaded archive will be uncompressed into this directory. * * @param eventStoreDir * Target directory to set */ public final void setEventStoreDir(final File eventStoreDir) { this.eventStoreDir = eventStoreDir; } /** * Returns the target build directory. * * @return The build directory. */ public final File getTargetDir() { return targetDir; } /** * Sets the target build directory. * * @param targetDir * The build directory to set */ public final void setTargetDir(final File targetDir) { this.targetDir = targetDir; } /** * Writes the process ID of the event store to a file in the target * directory. * * @param pid * PID to write. * * @throws MojoExecutionException * Error writing the PID to file. */ protected final void writePid(final String pid) throws MojoExecutionException { try { FileUtils.write(getPidFile(), pid); } catch (final IOException ex) { throw new MojoExecutionException("Couldn't write the PID '" + pid + "' to file: " + getPidFile(), ex); } } /** * Reads the process ID of the event store from a file in the target * directory. * * @return PID from file. * * @throws MojoExecutionException * Error reading the PID from file. */ protected final String readPid() throws MojoExecutionException { try { return FileUtils.readFileToString(getPidFile()); } catch (final IOException ex) { throw new MojoExecutionException("Couldn't read the PID from file: " + getPidFile(), ex); } } /** * Deletes the process ID file in the target directory. * * @throws MojoExecutionException * Error deleting the PID file. */ protected final void deletePid() throws MojoExecutionException { final boolean ok = getPidFile().delete(); if (!ok) { throw new MojoExecutionException("Couldn't delete the PID file: " + getPidFile()); } } /** * Returns the PID file. * * @return Process ID file. */ protected final File getPidFile() { return new File(getTargetDir(), PID_FILE_NAME); } /** * Returns the string as list. * * @param str * String to split into lines. * * @return List of lines. * * @throws MojoExecutionException * Error splitting the string into lines. */ protected final List<String> asList(final String str) throws MojoExecutionException { try { final List<String> lines = new ArrayList<String>(); final LineNumberReader reader = new LineNumberReader(new StringReader(str)); String line; while ((line = reader.readLine()) != null) { lines.add(line); } return lines; } catch (final IOException ex) { throw new MojoExecutionException("Error creating string list", ex); } } /** * Logs all lines in debug mode. * * @param messages * Lines to log. */ protected final void logDebug(final List<String> messages) { if (LOG.isDebugEnabled()) { for (final String message : messages) { LOG.debug(message); } } } /** * Logs all lines in error mode. * * @param messages * Lines to log. */ protected final void logError(final List<String> messages) { if (LOG.isErrorEnabled()) { for (final String message : messages) { LOG.error(message); } } } /** * Executes the goal code. * * @throws MojoExecutionException * if goal execution failed */ protected abstract void executeGoal() throws MojoExecutionException; }