// // ======================================================================== // 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.ant; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintStream; 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.apache.tools.ant.DefaultLogger; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; public class AntBuild { private Thread _process; private String _ant; private int _port; private String _host; public AntBuild(String ant) { _ant = ant; } private class AntBuildProcess implements Runnable { List<String[]> connList; @Override public void run() { File buildFile = new File(_ant); Project antProject = new Project(); try { antProject.setBaseDir(MavenTestingUtils.getBaseDir()); antProject.setUserProperty("ant.file",buildFile.getAbsolutePath()); DefaultLogger logger = new DefaultLogger(); ConsoleParser parser = new ConsoleParser(); //connList = parser.newPattern(".*([0-9]+\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)",1); connList = parser.newPattern("Jetty AntTask Started",1); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); PipedOutputStream pose = new PipedOutputStream(); PipedInputStream pise = new PipedInputStream(pose); startPump("STDOUT",parser,pis); startPump("STDERR",parser,pise); logger.setErrorPrintStream(new PrintStream(pos)); logger.setOutputPrintStream(new PrintStream(pose)); logger.setMessageOutputLevel(Project.MSG_VERBOSE); antProject.addBuildListener(logger); antProject.fireBuildStarted(); antProject.init(); ProjectHelper helper = ProjectHelper.getProjectHelper(); antProject.addReference("ant.projectHelper",helper); helper.parse(antProject,buildFile); antProject.executeTarget("jetty.run"); parser.waitForDone(10000,TimeUnit.MILLISECONDS); } catch (Exception e) { antProject.fireBuildFinished(e); } } public void waitForStarted() throws Exception { while (connList == null || connList.isEmpty()) { Thread.sleep(10); } } } public void start() throws Exception { System.out.println("Starting Ant Build ..."); AntBuildProcess abp = new AntBuildProcess(); _process = new Thread(abp); _process.start(); abp.waitForStarted(); // once this has returned we should have the connection info we need //_host = abp.getConnectionList().get(0)[0]; //_port = Integer.parseInt(abp.getConnectionList().get(0)[1]); } public int getJettyPort() { return Integer.parseInt(System.getProperty("jetty.ant.server.port")); } public String getJettyHost() { return System.getProperty("jetty.ant.server.host"); } /** * Stop the jetty server */ public void stop() { System.out.println("Stopping Ant Build ..."); _process.interrupt(); } 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(); } /** * 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); } } }