/******************************************************************************* * Copyright (c) 2011, 2012 Anton Gorenkov * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Anton Gorenkov - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.testsrunner.internal.launcher; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.OutputStream; /** * Wraps the underline process and prevent accessing to its output or error stream. * This wrapping is necessary to prevent handling the test module output by Console * because we want to handle it here. * */ class ProcessWrapper extends Process { /** The real underlying process. */ private Process wrappedProcess; /** The flag shows whether input stream should be replaced with empty dummy. */ private boolean hideInputStream; /** The flag shows whether error stream should be replaced with empty dummy. */ private boolean hideErrorStream; /** Buffer for empty dummy stream. */ private byte buffer[] = new byte[0]; /** Empty dummy stream. */ private InputStream emptyInputStream = new ByteArrayInputStream(buffer); /** * The synchronization event: before it happens <code>waitFor()</code> will * not be called on underlying process object. See also the comments in * <code>waitFor()</code>. */ private Object waitForSync = new Object(); /** * Flag that shows that process output was not processed yet so the IO * streams could not be closed yet. */ private boolean streamsClosingIsAllowed = false; /** * The constructor * * @param wrappedProcess underlying process * @param hideInputStream process input stream should be hidden * @param hideErrorStream process error stream should be hidden */ public ProcessWrapper(Process wrappedProcess, boolean hideInputStream, boolean hideErrorStream) { this.wrappedProcess = wrappedProcess; this.hideInputStream = hideInputStream; this.hideErrorStream = hideErrorStream; } @Override public void destroy() { wrappedProcess.destroy(); } @Override public int exitValue() { return wrappedProcess.exitValue(); } @Override public InputStream getErrorStream() { return hideErrorStream ? emptyInputStream : wrappedProcess.getErrorStream(); } @Override public InputStream getInputStream() { return hideInputStream ? emptyInputStream : wrappedProcess.getInputStream(); } @Override public OutputStream getOutputStream() { return wrappedProcess.getOutputStream(); } @Override public int waitFor() throws InterruptedException { // NOTE: implementation of waitFor() in Spawner will close streams after process is terminated, // so we should wait with this operation until we process all stream data synchronized (waitForSync) { if (!streamsClosingIsAllowed) { waitForSync.wait(); } } return wrappedProcess.waitFor(); } /** * Sets up the flag the allows IO streams closing. */ public void allowStreamsClosing() { synchronized (waitForSync) { streamsClosingIsAllowed = true; waitForSync.notifyAll(); } } }