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

ru.yandex.qatools.camelot.maven.service.CamelotRunner Maven / Gradle / Ivy

The newest version!
package ru.yandex.qatools.camelot.maven.service;

import com.gc.iotools.stream.os.OutputStreamToInputStream;
import org.apache.commons.exec.*;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.qatools.camelot.maven.utils.CamelotRunnerUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.List;

import static java.lang.Thread.sleep;
import static org.eclipse.jetty.http.HttpMethod.POST;
import static ru.yandex.qatools.camelot.maven.utils.CamelotRunnerUtils.createJarWithClassPath;
import static ru.yandex.qatools.camelot.maven.utils.CamelotRunnerUtils.toUrlArray;

/**
 * @author Dmitry Baev [email protected]
 *         Date: 08.07.14
 *         

* Using this class you can configure and start camelot application at same or separate fork. */ public class CamelotRunner implements CtJetty, CtRun, CtJettyClassPath, CtApplicationClassPath { public static final String JETTY_SHUTDOWN_URL_PATTERN = "http://localhost:%d/shutdown?token=%s&_exitJvm=true"; public static final String LOG4J_IGNORE_TCL = "log4j.ignoreTCL"; public static final String RUNNER_MERHOD_NAME = "run"; private final Logger logger = LoggerFactory.getLogger(getClass()); private boolean forked = true; private boolean waitFor = true; private String[] jettyClassPath; private String[] applicationClassPath; private String jvmArgs; private int port; private String webAppDirectory; private String contextPath; private boolean release = false; /** * Use {@link #camelot()} for get instance of {@link ru.yandex.qatools.camelot.maven.service.CamelotRunner} */ CamelotRunner() { } /** * A fluent-api method to set {@link #jvmArgs} for separate jvm. Used only in forked mode * * @param jvmArgs given jvm arguments * @return */ @Override public CtRun jvmArgs(String jvmArgs) { this.jvmArgs = jvmArgs; return this; } /** * A fluent-api method to set {@link #forked} parameter. * * @param forked true if you need to start jetty server in separate fork, false otherwise */ @Override public CtRun forked(boolean forked) { this.forked = forked; return this; } /** * A fluent-api method to set {@link #waitFor} parameter. * * @param waitFor true if you need to wait util server is shutdown, false otherwise */ @Override public CtRun waitFor(boolean waitFor) { this.waitFor = waitFor; return this; } /** * Start Jetty server at http://localhost:{@link #port}/{@link #contextPath} * * @throws Exception if can't start Jetty server. */ @Override public void run() throws Exception { //NOSONAR if (forked) { runForked(); } else { runNotForked(); } } /** * A fluent-api method to configure jetty server * * @param webAppDirectory path to webapp * @param contextPath jetty context path * @param port jetty port */ @Override public CtJettyClassPath jetty(String webAppDirectory, String contextPath, int port) { this.port = port; this.webAppDirectory = webAppDirectory; this.contextPath = contextPath; return this; } /** * A fluent-api method to configure jetty server * * @param webAppDirectory {@link java.io.File} with webapp * @param contextPath jetty context path * @param port jetty port */ @Override public CtJettyClassPath jetty(File webAppDirectory, String contextPath, int port) { jetty(webAppDirectory.getAbsolutePath(), contextPath, port); return this; } /** * Send shutdown hook to server at specified port * * @param port given server port */ @Override public void shutdown(int port) { try { URL url = new URL(String.format(JETTY_SHUTDOWN_URL_PATTERN, port, CamelotJettyRunner.SHUTDOWN_PASSWORD)); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod(POST.asString()); final int responseCode = connection.getResponseCode(); if (responseCode == HttpStatus.OK_200) { logger.info(String.format("Server(%d) successfully shutdown", port)); } else { logger.error(String.format("Can't shutdown server(%d). Response code %d", port, responseCode)); } } catch (SocketException e) { logger.debug("Server is already not running", e); } catch (Exception e) { logger.error(String.format("Can't shutdown server(%d)", port), e); } } @Override public CtApplicationClassPath jettyClassPath(String... classpath) { this.jettyClassPath = classpath; return this; } /** * A fluent-api method to set the classpath for application * * @param cp specified classpath */ @Override public CtRun applicationClassPath(String... cp) { this.applicationClassPath = cp; return this; } /** * Create instance of {@link ru.yandex.qatools.camelot.maven.service.CamelotRunner} * * @return created instance of camelot runner */ public static CtJetty camelot() { return new CamelotRunner(); } /** * Run Jetty in separate fork at http://localhost:{@link #port}/{@link #contextPath}. Use {@link #webAppDirectory} * as web application context war. * * @throws Exception if can't start Jetty server. */ protected void runForked() throws Exception { //NOSONAR String commandLine = createCommandLine(); logger.info(String.format("Executing 'java %s'", commandLine)); CommandLine cmdLine = CommandLine.parse(commandLine); Executor executor = CamelotRunnerUtils.createExecutor(); DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); executor.setStreamHandler(createStreamHandler()); if (waitFor) { // shutdown process if we were killed while waiting for it executor.setProcessDestroyer(new ShutdownHookProcessDestroyer()); } executor.execute(cmdLine, resultHandler); if (waitFor) { logger.info("Waiting until process is finished..."); resultHandler.waitFor(); } else { logger.info("Waiting until camelot is deployed..."); while (!release) { sleep(2000); } logger.info(String.format(" ==== Camelot is STARTED at http://localhost:%s%s ==== ", port, contextPath)); } } /** * Create command line string for execute {@link ru.yandex.qatools.camelot.maven.service.CamelotJettyRunner#main(String[])} * * @return created command line string * @throws IOException if can't create temp jars {@link CamelotRunnerUtils#createJarWithClassPath(String, String...)} */ private String createCommandLine() throws IOException { logger.info("Jetty Class Path: " + Arrays.toString(jettyClassPath)); String jettyClassPathJar = createJarWithClassPath(CamelotJettyRunner.class.getName(), jettyClassPath).getAbsolutePath(); String appClassPathJar = createJarWithClassPath(CamelotJettyRunner.class.getName(), applicationClassPath).getAbsolutePath(); List params = Arrays.asList("java", jvmArgs, "-jar", jettyClassPathJar, webAppDirectory, contextPath, String.valueOf(port), appClassPathJar, String.valueOf(waitFor)); return StringUtils.join(params, " "); } /** * Create {@link org.apache.commons.exec.PumpStreamHandler} for handle output from child process. Handler * looking for {@link CamelotRunnerUtils#WAITFOR_TOKEN} * * @return created handler */ private PumpStreamHandler createStreamHandler() { OutputStreamToInputStream out = new OutputStreamToInputStream() { @Override protected String doRead(final InputStream is) throws Exception { //NOSONAR BufferedReader reader = new BufferedReader(new InputStreamReader(is)); //noinspection InfiniteLoopStatement while (true) { if (reader.ready()) { final String line = reader.readLine(); logger.info(line); if (line.contains(CamelotRunnerUtils.WAITFOR_TOKEN)) { release = true; } } sleep(50); } } }; return new PumpStreamHandler(out); } /** * Run Jetty in same fork at http://localhost:{@link #port}/{@link #contextPath}. Use {@link #webAppDirectory} * as web application context war. * * @throws Exception if can't start Jetty server. */ protected void runNotForked() throws Exception { //NOSONAR System.setProperty(LOG4J_IGNORE_TCL, Boolean.toString(true)); URLClassLoader classLoader = new URLClassLoader(toUrlArray(jettyClassPath)); Class clazz = classLoader .loadClass(CamelotJettyRunner.class.getName()); Object obj = clazz.getConstructor(String[].class).newInstance(new Object[]{applicationClassPath}); clazz.getMethod(RUNNER_MERHOD_NAME, String.class, String.class, int.class, boolean.class) .invoke(obj, webAppDirectory, contextPath, port, waitFor); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy