| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.test.support; |
| // |
| //======================================================================== |
| //------------------------------------------------------------------------ |
| //All rights reserved. This program and the accompanying materials |
| //are made available under the terms of the Eclipse Public License v1.0 |
| //and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| //You may elect to redistribute this code under either of these licenses. |
| //======================================================================== |
| // |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.jetty.toolchain.test.FS; |
| import org.eclipse.jetty.toolchain.test.IO; |
| import org.eclipse.jetty.toolchain.test.JAR; |
| import org.eclipse.jetty.toolchain.test.MavenTestingUtils; |
| import org.eclipse.jetty.toolchain.test.OS; |
| import org.eclipse.jetty.toolchain.test.PathAssert; |
| import org.eclipse.jetty.toolchain.test.TestingDir; |
| import org.junit.Assert; |
| |
| /** |
| * Basic process based executor for using the Jetty Distribution along with custom configurations to perform basic |
| * <p> |
| * Allows for a test specific directory, that is a copied jetty-distribution, and then modified for the test specific testing required. |
| * <p> |
| * Requires that you setup the maven-dependency-plugin appropriately for the base distribution you want to use, along with any other dependencies (wars, libs, |
| * etc..) that you may need from other maven projects. |
| * <p> |
| * Maven Dependency Plugin Setup: |
| * |
| * <pre> |
| * <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| * xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
| * |
| * <!-- Common Destination Directories --> |
| * |
| * <properties> |
| * <test-wars-dir>${project.build.directory}/test-wars</test-wars-dir> |
| * <test-libs-dir>${project.build.directory}/test-libs</test-libs-dir> |
| * <test-distro-dir>${project.build.directory}/test-dist</test-distro-dir> |
| * </properties> |
| * |
| * <build> |
| * <plugins> |
| * <plugin> |
| * <groupId>org.apache.maven.plugins</groupId> |
| * <artifactId>maven-dependency-plugin</artifactId> |
| * <version>2.1</version> |
| * <executions> |
| * |
| * <!-- Copy LIB and WAR dependencies into place that JettyDistro can use them --> |
| * |
| * <execution> |
| * <id>test-lib-war-copy</id> |
| * <phase>process-test-resources</phase> |
| * <goals> |
| * <goal>copy</goal> |
| * </goals> |
| * <configuration> |
| * <artifactItems> |
| * <artifactItem> |
| * <groupId>org.mortbay.jetty.testwars</groupId> |
| * <artifactId>test-war-java_util_logging</artifactId> |
| * <version>7.3.0</version> |
| * <type>war</type> |
| * <outputDirectory>${test-wars-dir}</outputDirectory> |
| * </artifactItem> |
| * <artifactItem> |
| * <groupId>org.mortbay.jetty</groupId> |
| * <artifactId>jetty-aspect-servlet-api-2.5</artifactId> |
| * <version>7.3.0</version> |
| * <type>jar</type> |
| * <outputDirectory>${test-libs-dir}</outputDirectory> |
| * </artifactItem> |
| * </artifactItems> |
| * <overWriteIfNewer>true</overWriteIfNewer> |
| * <overWrite>true</overWrite> |
| * <stripVersion>true</stripVersion> |
| * </configuration> |
| * </execution> |
| * |
| * <!-- Extract Jetty DISTRIBUTION into place that JettyDistro can use it --> |
| * |
| * <execution> |
| * <id>unpack-test-dist</id> |
| * <phase>process-test-resources</phase> |
| * <goals> |
| * <goal>unpack</goal> |
| * </goals> |
| * <configuration> |
| * <artifactItems> |
| * <artifactItem> |
| * <groupId>org.eclipse.jetty</groupId> |
| * <artifactId>jetty-distribution</artifactId> |
| * <version>7.3.0</version> |
| * <type>zip</type> |
| * <overWrite>true</overWrite> |
| * </artifactItem> |
| * </artifactItems> |
| * <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename> |
| * <outputDirectory>${test-distro-dir}</outputDirectory> |
| * <overWriteSnapshots>true</overWriteSnapshots> |
| * <overWriteIfNewer>true</overWriteIfNewer> |
| * </configuration> |
| * </execution> |
| * </executions> |
| * </plugin> |
| * </plugins> |
| * </build> |
| * |
| * </project> |
| * </pre> |
| * <p> |
| * If you have a specific configuration you want to setup, you'll want to prepare this configuration in an overlay directory underneath the |
| * <code>src/test/resources/</code> directory. <br> |
| * Notes: |
| * <ol> |
| * <li>The {@link JettyDistro} sets up a unique test directory (based on the constructor {@link #JettyDistro(Class)} or {@link #JettyDistro(TestingDir)}), by |
| * ensuring the directory is empty, then copying the <code>target/test-dist</code> directory into this new testing directory prior to the test specific changes |
| * to the configuration.<br> |
| * Note: this testing directory is a complete jetty distribution, suitable for executing via the command line for additional testing needs.</li> |
| * <li>The directory name you choose in <code>src/test/resources</code> will be the name you use in the {@link #overlayConfig(String)} method to provide |
| * replacement configurations for the Jetty Distribution.</li> |
| * <li>You'll want to {@link #delete(String)} any files and/or directories from the standard distribution prior to using the {@link #overlayConfig(String)} |
| * method.</li> |
| * <li>Use the {@link #copyLib(String, String)} method to copy JAR files from the <code>target/test-libs</code> directory (created and managed above using the |
| * <code>maven-dependency-plugin</code>) to copy the lib into the test specific.</li> |
| * <li>Use the {@link #copyTestWar(String)} method to copy WAR files from the <code>target/test-wars</code> directory (created and managed above using the |
| * <code>maven-dependency-plugin</code>) to copy the WAR into the test specific directory.</li> |
| * </ol> |
| * <p> |
| * Next you'll want to use Junit 4.8+ and the <code>@BeforeClass</code> and <code>@AfterClass</code> annotations to setup the <code>JettyDistro</code> |
| * class for setting up your testing configuration. |
| * <p> |
| * Example Test Case using {@link JettyDistro} class |
| * |
| * <pre> |
| * public class MySampleTest |
| * { |
| * private static JettyDistro jetty; |
| * |
| * @BeforeClass |
| * public static void initJetty() throws Exception |
| * { |
| * jetty = new JettyDistro(MySampleTest.class); |
| * |
| * jetty.copyTestWar("test-war-java_util_logging.war"); |
| * jetty.copyTestWar("test-war-policy.war"); |
| * |
| * jetty.delete("webapps/test.war"); |
| * jetty.delete("contexts/test.d"); |
| * jetty.delete("contexts/javadoc.xml"); |
| * jetty.delete("contexts/test.xml"); |
| * |
| * jetty.overlayConfig("no_security"); |
| * |
| * jetty.setDebug(true); |
| * |
| * jetty.start(); |
| * } |
| * |
| * @AfterClass |
| * public static void shutdownJetty() throws Exception |
| * { |
| * if (jetty != null) |
| * { |
| * jetty.stop(); |
| * } |
| * } |
| * |
| * @Test |
| * public void testRequest() throws Exception |
| * { |
| * SimpleRequest request = new SimpleRequest(jetty.getBaseUri()); |
| * String path = "/test-war-policy/security/PRACTICAL/testFilsystem"); |
| * String response = request.getString(path); |
| * Assert.assertEquals("Success", response); |
| * } |
| * } |
| * </pre> |
| */ |
| public class JettyDistro |
| { |
| private String artifactName = "jetty-distribution"; |
| private long startTime = 60; |
| private TimeUnit timeUnit = TimeUnit.SECONDS; |
| |
| private File jettyHomeDir; |
| private Process pid; |
| private URI baseUri; |
| |
| private String jmxUrl; |
| |
| private boolean _debug = false; |
| |
| /** |
| * Setup the JettyHome as belonging in a testing directory associated with a testing clazz. |
| * |
| * @param clazz |
| * the testing class using this JettyDistro |
| * @throws IOException |
| * if unable to copy unpacked distribution into place for the provided testing directory |
| */ |
| public JettyDistro(Class<?> clazz) throws IOException |
| { |
| this(clazz,null); |
| } |
| |
| /** |
| * Setup the JettyHome as belonging in a testing directory associated with a testing clazz. |
| * |
| * @param clazz |
| * the testing class using this JettyDistro |
| * @param artifact |
| * name of jetty distribution artifact |
| * @throws IOException |
| * if unable to copy unpacked distribution into place for the provided testing directory |
| */ |
| public JettyDistro(Class<?> clazz, String artifact) throws IOException |
| { |
| this.jettyHomeDir = MavenTestingUtils.getTargetTestingDir(clazz,"jettyHome"); |
| if (artifact != null) |
| { |
| this.artifactName = artifact; |
| } |
| |
| copyBaseDistro(); |
| } |
| |
| /** |
| * Setup the JettyHome as belonging to a specific testing method directory |
| * |
| * @param testdir |
| * the testing directory to use as the JettyHome for this JettyDistro |
| * @throws IOException |
| * if unable to copy unpacked distribution into place for the provided testing directory |
| */ |
| public JettyDistro(TestingDir testdir) throws IOException |
| { |
| this.jettyHomeDir = testdir.getPath().toFile(); |
| copyBaseDistro(); |
| } |
| |
| /** |
| * Setup the JettyHome as belonging to a specific testing method directory |
| * |
| * @param testdir |
| * the testing directory to use as the JettyHome for this JettyDistro |
| * @param artifact |
| * name of jetty distribution artifact |
| * @throws IOException |
| * if unable to copy unpacked distribution into place for the provided testing directory |
| */ |
| public JettyDistro(TestingDir testdir, String artifact) throws IOException |
| { |
| this.jettyHomeDir = testdir.getPath().toFile(); |
| if (artifact != null) |
| { |
| this.artifactName = artifact; |
| } |
| |
| copyBaseDistro(); |
| } |
| |
| /** |
| * |
| * @throws IOException |
| * if unable to copy unpacked distribution into place for the provided testing directory |
| */ |
| private void copyBaseDistro() throws IOException |
| { |
| // The outputDirectory for the maven side dependency:unpack goal. |
| File distroUnpackDir = MavenTestingUtils.getTargetFile("test-dist"); |
| PathAssert.assertDirExists(artifactName + " dependency:unpack",distroUnpackDir); |
| |
| // The actual jetty-distribution-${version} directory is under this directory. |
| // Lets find it. |
| File subdirs[] = distroUnpackDir.listFiles(new FileFilter() |
| { |
| public boolean accept(File path) |
| { |
| if (!path.isDirectory()) |
| { |
| return false; |
| } |
| |
| return path.getName().startsWith(artifactName + "-"); |
| } |
| }); |
| |
| if (subdirs.length == 0) |
| { |
| // No jetty-distribution found. |
| StringBuilder err = new StringBuilder(); |
| err.append("No target/test-dist/"); |
| err.append(artifactName); |
| err.append("-${version} directory found."); |
| err.append("\n To fix this, run 'mvn process-test-resources' to create the directory."); |
| throw new IOException(err.toString()); |
| } |
| |
| if (subdirs.length != 1) |
| { |
| // Too many jetty-distributions found. |
| StringBuilder err = new StringBuilder(); |
| err.append("Too many target/test-dist/"); |
| err.append(artifactName); |
| err.append("-${version} directories found."); |
| for (File dir : subdirs) |
| { |
| err.append("\n ").append(dir.getAbsolutePath()); |
| } |
| err.append("\n To fix this, run 'mvn clean process-test-resources' to recreate the target/test-dist directory."); |
| throw new IOException(err.toString()); |
| } |
| |
| File distroSrcDir = subdirs[0]; |
| FS.ensureEmpty(jettyHomeDir); |
| System.out.printf("Copying Jetty Distribution: %s%n",distroSrcDir.getAbsolutePath()); |
| System.out.printf(" To Testing Dir: %s%n",jettyHomeDir.getAbsolutePath()); |
| IO.copyDir(distroSrcDir,jettyHomeDir); |
| } |
| |
| /** |
| * Return the $(jetty.home) directory being used for this JettyDistro |
| * |
| * @return the jetty.home directory being used |
| */ |
| public File getJettyHomeDir() |
| { |
| return this.jettyHomeDir; |
| } |
| |
| /** |
| * Copy a war file from ${project.basedir}/target/test-wars/${testWarFilename} into the ${jetty.home}/webapps/ directory |
| * |
| * @param testWarFilename |
| * the war file to copy (must exist) |
| * @throws IOException |
| * if unable to copy the war file. |
| */ |
| public void copyTestWar(String testWarFilename) throws IOException |
| { |
| File srcWar = MavenTestingUtils.getTargetFile("test-wars/" + testWarFilename); |
| File destWar = new File(jettyHomeDir,OS.separators("webapps/" + testWarFilename)); |
| FS.ensureDirExists(destWar.getParentFile()); |
| IO.copyFile(srcWar,destWar); |
| } |
| |
| /** |
| * Copy an arbitrary file from <code>src/test/resources/${resourcePath}</code> to the testing directory. |
| * |
| * @param resourcePath |
| * the relative path for file content within the <code>src/test/resources</code> directory. |
| * @param outputPath |
| * the testing directory relative output path for the file output (will result in a file with the outputPath name being created) |
| * @throws IOException |
| * if unable to copy resource file |
| */ |
| public void copyResource(String resourcePath, String outputPath) throws IOException |
| { |
| File srcFile = MavenTestingUtils.getTestResourceFile(resourcePath); |
| File destFile = new File(jettyHomeDir,OS.separators(outputPath)); |
| FS.ensureDirExists(destFile.getParentFile()); |
| IO.copyFile(srcFile,destFile); |
| } |
| |
| /** |
| * Copy an arbitrary file from <code>target/test-libs/${libFilename}</code> to the testing directory. |
| * |
| * @param libFilename |
| * the <code>target/test-libs/${libFilename}</code> to copy |
| * @param outputPath |
| * the destination testing directory relative output path for the lib. (will result in a file with the outputPath name being created) |
| * @throws IOException |
| * if unable to copy lib |
| */ |
| public void copyLib(String libFilename, String outputPath) throws IOException |
| { |
| File srcLib = MavenTestingUtils.getTargetFile("test-libs/" + libFilename); |
| File destLib = new File(jettyHomeDir,OS.separators(outputPath)); |
| FS.ensureDirExists(destLib.getParentFile()); |
| IO.copyFile(srcLib,destLib); |
| } |
| |
| /** |
| * Copy the <code>${project.basedir}/src/main/config/</code> tree into the testing directory. |
| * |
| * @throws IOException |
| * if unable to copy the directory tree |
| */ |
| public void copyProjectMainConfig() throws IOException |
| { |
| File srcDir = MavenTestingUtils.getProjectDir("src/main/config"); |
| IO.copyDir(srcDir,jettyHomeDir); |
| } |
| |
| /** |
| * Create a <code>${jetty.home}/lib/self/${jarFilename}</code> jar file from the content in the <code>${project.basedir}/target/classes/</code> directory. |
| * |
| * @throws IOException |
| * if unable to copy the directory tree |
| */ |
| public void createProjectLib(String jarFilename) throws IOException |
| { |
| File srcDir = MavenTestingUtils.getTargetFile("classes"); |
| File libSelfDir = new File(jettyHomeDir,OS.separators("lib/self")); |
| FS.ensureDirExists(libSelfDir); |
| File jarFile = new File(libSelfDir,jarFilename); |
| JAR.create(srcDir,jarFile); |
| } |
| |
| /** |
| * Unpack an arbitrary config from <code>target/test-configs/${configFilename}</code> to the testing directory. |
| * |
| * @param configFilename |
| * the <code>target/test-configs/${configFilename}</code> to copy |
| * @throws IOException |
| * if unable to unpack config file |
| */ |
| public void unpackConfig(String configFilename) throws IOException |
| { |
| File srcConfig = MavenTestingUtils.getTargetFile("test-configs/" + configFilename); |
| JAR.unpack(srcConfig,jettyHomeDir); |
| } |
| |
| /** |
| * Delete a File or Directory found in the ${jetty.home} directory. |
| * |
| * @param path |
| * the path to delete. (can be a file or directory) |
| */ |
| public void delete(String path) |
| { |
| File jettyPath = new File(jettyHomeDir,OS.separators(path)); |
| FS.delete(jettyPath); |
| } |
| |
| /** |
| * Return the baseUri being used for this Jetty Process Instance. |
| * |
| * @return the base URI for this Jetty Process Instance. |
| */ |
| public URI getBaseUri() |
| { |
| return this.baseUri; |
| } |
| |
| /** |
| * Return the JMX URL being used for this Jetty Process Instance. |
| * |
| * @return the JMX URL for this Jetty Process Instance. |
| */ |
| public String getJmxUrl() |
| { |
| return this.jmxUrl; |
| } |
| |
| /** |
| * Take the directory contents from ${project.basedir}/src/test/resources/${testConfigName}/ and copy it over whatever happens to be at ${jetty.home} |
| * |
| * @param testConfigName |
| * the src/test/resources/ directory name to use as the source diretory for the configuration we are interested in. |
| * @throws IOException |
| * if unable to copy directory. |
| */ |
| public void overlayConfig(String testConfigName) throws IOException |
| { |
| File srcDir = MavenTestingUtils.getTestResourceDir(testConfigName); |
| IO.copyDir(srcDir,jettyHomeDir); |
| } |
| |
| /** |
| * Start the jetty server |
| * |
| * @throws IOException |
| * if unable to start the server. |
| */ |
| public void start() throws IOException |
| { |
| List<String> commands = new ArrayList<String>(); |
| commands.add(getJavaBin()); |
| |
| commands.add("-Djetty.home=" + jettyHomeDir.getAbsolutePath()); |
| |
| // Do a dry run first to get the exact command line for Jetty process |
| commands.add("-jar"); |
| commands.add("start.jar"); |
| commands.add("jetty.http.port=0"); |
| if (_debug) |
| { |
| commands.add("-D.DEBUG=true"); |
| } |
| commands.add("--dry-run"); |
| |
| ProcessBuilder pbCmd = new ProcessBuilder(commands); |
| pbCmd.directory(jettyHomeDir); |
| |
| String cmdLine = null; |
| Process pidCmd = pbCmd.start(); |
| try |
| { |
| cmdLine = readOutputLine(pidCmd); |
| } |
| finally |
| { |
| pidCmd.destroy(); |
| } |
| |
| if (cmdLine == null || !cmdLine.contains("XmlConfiguration")) |
| { |
| Assert.fail("Unable to get Jetty command line"); |
| } |
| |
| // Need to breakdown commandline into parts, as spaces in command line will cause failures. |
| List<String> execCommands = splitAndUnescapeCommandLine(cmdLine); |
| |
| System.out.printf("Executing: %s%n",cmdLine); |
| System.out.printf("Working Dir: %s%n",jettyHomeDir.getAbsolutePath()); |
| |
| pbCmd = new ProcessBuilder(execCommands); |
| pid = pbCmd.start(); |
| |
| ConsoleParser parser = new ConsoleParser(); |
| List<String[]> jmxList = parser.newPattern("JMX Remote URL: (.*)",0); |
| List<String[]> connList = parser.newPattern("Started [A-Za-z]*Connector@([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)",1); |
| // DISABLED: This is what exists in Jetty 9+ |
| // List<String[]> connList = parser.newPattern("Started [A-Za-z]*Connector@.*[\\({]([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)[\\)}].*",1); |
| |
| startPump("STDOUT",parser,this.pid.getInputStream()); |
| startPump("STDERR",parser,this.pid.getErrorStream()); |
| |
| try |
| { |
| parser.waitForDone(this.startTime,this.timeUnit); |
| |
| if (!jmxList.isEmpty()) |
| { |
| this.jmxUrl = jmxList.get(0)[0]; |
| System.out.printf("## Found JMX connector at %s%n",this.jmxUrl); |
| } |
| |
| if (!connList.isEmpty()) |
| { |
| String[] params = connList.get(0); |
| if (params.length == 2) |
| { |
| this.baseUri = URI.create("http://localhost:" + params[1] + "/"); |
| } |
| System.out.printf("## Found Jetty connector at host: %s port: %s%n",(Object[])params); |
| } |
| |
| } |
| catch (InterruptedException e) |
| { |
| pid.destroy(); |
| Assert.fail("Unable to get required information within time limit"); |
| } |
| } |
| |
| public static List<String> splitAndUnescapeCommandLine(CharSequence rawCmdLine) |
| { |
| List<String> cmds = new ArrayList<String>(); |
| |
| int len = rawCmdLine.length(); |
| StringBuilder arg = new StringBuilder(); |
| boolean escaped = false; |
| boolean inQuote = false; |
| char c; |
| for (int i = 0; i < len; i++) |
| { |
| c = rawCmdLine.charAt(i); |
| if (escaped) |
| { |
| switch (c) |
| { |
| case 'r': |
| arg.append('\r'); |
| break; |
| case 'f': |
| arg.append('\f'); |
| break; |
| case 't': |
| arg.append('\t'); |
| break; |
| case 'n': |
| arg.append('\n'); |
| break; |
| case 'b': |
| arg.append('\b'); |
| break; |
| default: |
| arg.append(c); |
| break; |
| } |
| escaped = false; |
| continue; |
| } |
| |
| if (c == '\\') |
| { |
| escaped = true; |
| } |
| else |
| { |
| if ((c == ' ') && (!inQuote)) |
| { |
| // the delim! |
| cmds.add(String.valueOf(arg.toString())); |
| arg.setLength(0); |
| } |
| else if (c == '"') |
| { |
| inQuote = !inQuote; |
| } |
| else |
| { |
| arg.append(c); |
| } |
| } |
| } |
| cmds.add(String.valueOf(arg.toString())); |
| |
| return cmds; |
| } |
| |
| private String readOutputLine(Process pidCmd) throws IOException |
| { |
| InputStream in = null; |
| InputStreamReader reader = null; |
| BufferedReader buf = null; |
| try |
| { |
| in = pidCmd.getInputStream(); |
| reader = new InputStreamReader(in); |
| buf = new BufferedReader(reader); |
| return buf.readLine(); |
| } |
| finally |
| { |
| IO.close(buf); |
| IO.close(reader); |
| IO.close(in); |
| } |
| } |
| |
| private static class ConsoleParser |
| { |
| private List<ConsolePattern> patterns = new ArrayList<ConsolePattern>(); |
| private CountDownLatch latch; |
| private int count; |
| |
| public List<String[]> newPattern(String exp, int cnt) |
| { |
| ConsolePattern pat = new ConsolePattern(exp,cnt); |
| patterns.add(pat); |
| count += cnt; |
| |
| return pat.getMatches(); |
| } |
| |
| public void parse(String line) |
| { |
| for (ConsolePattern pat : patterns) |
| { |
| Matcher mat = pat.getMatcher(line); |
| if (mat.find()) |
| { |
| int num = 0, count = mat.groupCount(); |
| String[] match = new String[count]; |
| while (num++ < count) |
| { |
| match[num - 1] = mat.group(num); |
| } |
| pat.getMatches().add(match); |
| |
| if (pat.getCount() > 0) |
| { |
| getLatch().countDown(); |
| } |
| } |
| } |
| } |
| |
| public void waitForDone(long timeout, TimeUnit unit) throws InterruptedException |
| { |
| getLatch().await(timeout,unit); |
| } |
| |
| private CountDownLatch getLatch() |
| { |
| synchronized (this) |
| { |
| if (latch == null) |
| { |
| latch = new CountDownLatch(count); |
| } |
| } |
| |
| return latch; |
| } |
| } |
| |
| private static class ConsolePattern |
| { |
| private Pattern pattern; |
| private List<String[]> matches; |
| private int count; |
| |
| ConsolePattern(String exp, int cnt) |
| { |
| pattern = Pattern.compile(exp); |
| matches = new ArrayList<String[]>(); |
| count = cnt; |
| } |
| |
| public Matcher getMatcher(String line) |
| { |
| return pattern.matcher(line); |
| } |
| |
| public List<String[]> getMatches() |
| { |
| return matches; |
| } |
| |
| public int getCount() |
| { |
| return count; |
| } |
| } |
| |
| private void startPump(String mode, ConsoleParser parser, InputStream inputStream) |
| { |
| ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream); |
| pump.setParser(parser); |
| Thread thread = new Thread(pump,"ConsoleStreamer/" + mode); |
| thread.start(); |
| } |
| |
| /** |
| * enable debug on the jetty process |
| * |
| * @param debug |
| */ |
| public void setDebug(boolean debug) |
| { |
| _debug = debug; |
| } |
| |
| private String getJavaBin() |
| { |
| String javaexes[] = new String[] |
| { "java", "java.exe" }; |
| |
| File javaHomeDir = new File(System.getProperty("java.home")); |
| for (String javaexe : javaexes) |
| { |
| File javabin = new File(javaHomeDir,OS.separators("bin/" + javaexe)); |
| if (javabin.exists() && javabin.isFile()) |
| { |
| return javabin.getAbsolutePath(); |
| } |
| } |
| |
| Assert.fail("Unable to find java bin"); |
| return "java"; |
| } |
| |
| /** |
| * Stop the jetty server |
| */ |
| public void stop() |
| { |
| System.out.println("Stopping JettyDistro ..."); |
| if (pid != null) |
| { |
| // TODO: maybe issue a STOP instead? |
| pid.destroy(); |
| } |
| } |
| |
| /** |
| * Simple streamer for the console output from a Process |
| */ |
| private static class ConsoleStreamer implements Runnable |
| { |
| private String mode; |
| private BufferedReader reader; |
| private ConsoleParser parser; |
| |
| public ConsoleStreamer(String mode, InputStream is) |
| { |
| this.mode = mode; |
| this.reader = new BufferedReader(new InputStreamReader(is)); |
| } |
| |
| public void setParser(ConsoleParser connector) |
| { |
| this.parser = connector; |
| } |
| |
| public void run() |
| { |
| String line; |
| // System.out.printf("ConsoleStreamer/%s initiated%n",mode); |
| try |
| { |
| while ((line = reader.readLine()) != (null)) |
| { |
| if (parser != null) |
| { |
| parser.parse(line); |
| } |
| System.out.println("[" + mode + "] " + line); |
| } |
| } |
| catch (IOException ignore) |
| { |
| /* ignore */ |
| } |
| finally |
| { |
| IO.close(reader); |
| } |
| // System.out.printf("ConsoleStreamer/%s finished%n",mode); |
| } |
| } |
| |
| public void setStartTime(long startTime, TimeUnit timeUnit) |
| { |
| this.startTime = startTime; |
| this.timeUnit = timeUnit; |
| } |
| } |