Java tutorial
/** * 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.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DaemonExecutor; import org.apache.commons.exec.DefaultExecuteResultHandler; import org.apache.commons.exec.OS; import org.apache.commons.exec.PumpStreamHandler; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Starts the event store. * */ @Mojo(name = "start", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresProject = false) public final class EventStoreStartMojo extends AbstractEventStoreMojo { private static final Logger LOG = LoggerFactory.getLogger(EventStoreStartMojo.class); /** * Name of the executable or shell script to start the event store. Defaults * to the OS specific name for Windows, Linux and Mac OS families. Other OS * families will cause an error if this value is not set. * */ @Parameter(name = "command") private String command; /** * Command line arguments to pass to the executable. If no arguments are set * this defaults to <code>--mem-db=TRUE</code>. * */ @Parameter(name = "arguments") private String[] arguments; /** * Number of times to wait for the server until it's up and running. After * this time passed, the build will fail. This means the mojo will wait * <code>maxWaitCycles</code> * <code>sleepMs</code> milliseconds for the * server to finish it's startup process. Defaults to 20 times. * */ @Parameter(name = "max-wait-cycles", defaultValue = "20") private int maxWaitCycles = 20; /** * Number of milliseconds to sleep while waiting for the server. This means * the mojo will wait <code>maxWaitCycles</code> * <code>sleepMs</code> * milliseconds for the server to finish it's startup process. Defaults to * 500 ms. * */ @Parameter(name = "sleep-ms", defaultValue = "500") private int sleepMs = 500; /** * Message from the event store log to wait for. * */ @Parameter(name = "up-message", defaultValue = "'admin' user account has been created") private String upMessage = "'admin' user account has been created"; @Override protected final void executeGoal() throws MojoExecutionException { init(); LOG.info("command={}", command); LOG.info("arguments={}", Arrays.toString(arguments)); final CommandLine cmdLine = createCommandLine(); final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); final DaemonExecutor executor = new DaemonExecutor(); try { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final PumpStreamHandler psh = new PumpStreamHandler(bos); executor.setStreamHandler(psh); executor.setWorkingDirectory(getEventStoreDir()); executor.execute(cmdLine, resultHandler); final List<String> messages = waitForHttpServer(resultHandler, bos); logDebug(messages); final String pid = extractPid(messages); LOG.info("Event store process ID: {}", pid); writePid(pid); } catch (final IOException ex) { throw new MojoExecutionException("Error executing the command line: " + cmdLine, ex); } } private List<String> waitForHttpServer(final DefaultExecuteResultHandler resultHandler, final ByteArrayOutputStream bos) throws MojoExecutionException { // Wait for result int wait = 0; while ((wait++ < maxWaitCycles) && !resultHandler.hasResult() && !bos.toString().contains(upMessage)) { sleep(sleepMs); } if (bos.toString().contains(upMessage)) { // Success return asList(bos.toString()); } // Failure final List<String> messages = asList(bos.toString()); logError(messages); // Exception if (resultHandler.hasResult()) { throw new MojoExecutionException("Error starting the server. Exit code=" + resultHandler.getExitValue(), resultHandler.getException()); } // Timeout throw new MojoExecutionException("Waited too long for the server to start!"); } private void sleep(final int ms) { try { Thread.sleep(ms); } catch (final InterruptedException ex) { LOG.info("Interrupted while sleeping", ex); } } private String extractPid(final List<String> messages) throws MojoExecutionException { if (messages.size() == 0) { throw new MojoExecutionException("Starting the event store didn't return any messages"); } final String first = messages.get(0); // Prefix looks like this: [19648,10,12:47:52.297] final int p0 = first.indexOf('['); if (p0 == -1) { throw new MojoExecutionException("Couldn't locate the starting bracket '[': " + first); } final int p1 = first.indexOf(',', p0 + 1); if (p1 == -1) { throw new MojoExecutionException("Couldn't locate the ending comma ',': " + first); } return first.substring(p0 + 1, p1); } private void init() throws MojoExecutionException { // Supply variables that are OS dependent if (OS.isFamilyWindows()) { if (command == null) { // For some strange reasons this does not work without the // path... command = getEventStoreDir() + File.separator + "EventStore.ClusterNode.exe"; } } else if (OS.isFamilyUnix()) { if (command == null) { command = "./run-node.sh"; } } else if (OS.isFamilyMac()) { if (command == null) { command = "./run-node.sh"; } } else { if (command == null) { throw new MojoExecutionException("Unknown OS - You must use the 'command' parameter"); } } // Use in-memory mode if nothing else is set if (arguments == null) { arguments = new String[1]; arguments[0] = "--mem-db=TRUE"; } } private CommandLine createCommandLine() throws MojoExecutionException { final CommandLine cmdLine = new CommandLine(command); if (arguments != null) { for (final String argument : arguments) { cmdLine.addArgument(argument); } } return cmdLine; } /** * Returns the name of the executable or shell script to start the event * store. * * @return Executable name. */ public final String getCommand() { return command; } /** * Sets the name of the executable or shell script to start the event store. * * @param command * Executable name to set. */ public final void setCommand(final String command) { this.command = command; } /** * Returns the command line arguments to pass to the executable. * * @return Command line arguments. */ public final String[] getArguments() { return arguments; } /** * Sets the command line arguments to pass to the executable. * * @param arguments * Arguments to set */ public final void setArguments(final String[] arguments) { this.arguments = arguments; } }