/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 2.1 of * the License, or (at your option) any later version. * * This software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.test.integration.domain.management.util; import org.jboss.as.process.protocol.StreamUtils; import org.wildfly.core.launcher.CommandBuilder; import org.wildfly.core.launcher.Launcher; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Map; /** * Basic process test wrapper. * * @author Emanuel Muckenhuber */ class ProcessWrapper { private final String processName; private final CommandBuilder commandBuilder; private final Map<String, String> env; private final String workingDirectory; private Process process; private volatile boolean stopped; ProcessWrapper(final String processName, final CommandBuilder commandBuilder, final Map<String, String> env, final String workingDirectory) { assert processName != null; assert commandBuilder != null; assert env != null; assert workingDirectory != null; this.processName = processName; this.commandBuilder = commandBuilder; this.env = env; this.workingDirectory = workingDirectory; Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { ProcessWrapper.this.stop(); } }); } int getExitValue() { synchronized (this) { try { return process.exitValue(); } catch (IllegalThreadStateException e) { return -1; } } } void start() throws Exception { synchronized (this) { if(stopped) { throw new IllegalStateException(); } process = Launcher.of(commandBuilder) .setRedirectErrorStream(true) .addEnvironmentVariables(env) .setDirectory(workingDirectory) .launch(); final Runnable consoleConsumer = new ConsoleConsumer(process.getInputStream(), System.out); new Thread(consoleConsumer, "Console consumer " + processName).start(); } } int waitFor() throws InterruptedException { final Process process; synchronized (this) { process = this.process; } if(process != null) { return process.waitFor(); } return 0; } void stop() { synchronized (this) { boolean stopped = this.stopped; if(! stopped) { this.stopped = true; final Process process = this.process; if(process != null) { process.destroy(); } } } } @Override public String toString() { return "ProcessWrapper [processName=" + processName + ", command=" + commandBuilder + ", env=" + env + ", workingDirectory=" + workingDirectory + ", stopped=" + stopped + "]"; } /** * Runnable that consumes the output of the process. If nothing consumes the output the AS will hang on some platforms * * @author Stuart Douglas * */ private class ConsoleConsumer implements Runnable { private final InputStream source; private final PrintStream target; private final boolean writeOutput; { writeOutput = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { // this needs a better name String val = System.getProperty("org.jboss.as.writeconsole"); return val == null || !"false".equals(val); } }); } private ConsoleConsumer(final InputStream source, final PrintStream target) { this.source = source; this.target = target; } public void run() { final InputStream source = this.source; try { byte[] buf = new byte[32]; int num; // Do not try reading a line cos it considers '\r' end of line while((num = source.read(buf)) != -1){ if (writeOutput) System.out.write(buf, 0, num); } } catch (IOException e) { if(! ProcessWrapper.this.stopped) { e.printStackTrace(target); } } finally { StreamUtils.safeClose(source); } } } }