Skip to content

Commit

Permalink
[Fixed #67]: Added OverthereExecutionOutputHandler, deprecated Overth…
Browse files Browse the repository at this point in the history
…ereProcessOutputHandler
  • Loading branch information
hierynomus committed Jan 30, 2013
1 parent 9008ad3 commit f032f7c
Show file tree
Hide file tree
Showing 20 changed files with 532 additions and 207 deletions.
23 changes: 23 additions & 0 deletions src/main/java/com/xebialabs/overthere/OverthereConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,32 @@ public interface OverthereConnection extends Closeable {
* @param commandLine
* the command line to execute.
* @return the exit value of the executed command. Usually 0 on successful execution.
* @deprecated use {@link #execute(OverthereExecutionOutputHandler, OverthereExecutionOutputHandler, CmdLine)}
*/
int execute(OverthereProcessOutputHandler handler, CmdLine commandLine);

/**
* Executes a command with its arguments and prints all the output on stdout and stderr to the console.
*
* @param commandLine
* the command line to execute.
* @return the exit value of the executed command. Usually 0 on successful execution.
*/
int execute(CmdLine commandLine);

/**
* Executes a command with its arguments.
*
* @param stdoutHandler
* the handler that will be invoked when the executed command generated output on stdout.
* @param stderrHandler
* the handler that will be invoked when the executed command generated output on stderr.
* @param commandLine
* the command line to execute.
* @return the exit value of the executed command. Usually 0 on successful execution.
*/
int execute(OverthereExecutionOutputHandler stdoutHandler, OverthereExecutionOutputHandler stderrHandler, CmdLine commandLine);

/**
* Starts a command with its argument and returns control to the caller.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.xebialabs.overthere;

public interface OverthereExecutionOutputHandler {
/**
* Invoked when an executed command generates a single character of output.
*
* @param c
* the character of output generated.
*/
void handleChar(char c);

/**
* Invoked when an executed command generated a line of output.
*
* @param line
* the line of output generated.
*/
void handleLine(String line);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@

/**
* Handler that gets sent the output (stdout and stderr) of an {@link OverthereProcess}.
* @deprecated Replaced with the {@link OverthereExecutionOutputHandler}
*/
@Deprecated
public interface OverthereProcessOutputHandler {

/**
Expand Down
174 changes: 73 additions & 101 deletions src/main/java/com/xebialabs/overthere/spi/BaseOverthereConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,26 @@
*/
package com.xebialabs.overthere.spi;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xebialabs.overthere.CmdLine;
import com.xebialabs.overthere.ConnectionOptions;
import com.xebialabs.overthere.OperatingSystemFamily;
import com.xebialabs.overthere.OverthereConnection;
import com.xebialabs.overthere.OverthereFile;
import com.xebialabs.overthere.OverthereProcess;
import com.xebialabs.overthere.OverthereProcessOutputHandler;
import com.xebialabs.overthere.RuntimeIOException;
import com.xebialabs.overthere.*;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.io.Closeables.closeQuietly;
import static com.xebialabs.overthere.ConnectionOptions.CONNECTION_TIMEOUT_MILLIS;
import static com.xebialabs.overthere.ConnectionOptions.DEFAULT_CONNECTION_TIMEOUT_MILLIS;
import static com.xebialabs.overthere.ConnectionOptions.DEFAULT_TEMPORARY_DIRECTORY_DELETE_ON_DISCONNECT;
import static com.xebialabs.overthere.ConnectionOptions.DEFAULT_TEMPORARY_FILE_CREATION_RETRIES;
import static com.xebialabs.overthere.ConnectionOptions.OPERATING_SYSTEM;
import static com.xebialabs.overthere.ConnectionOptions.TEMPORARY_DIRECTORY_DELETE_ON_DISCONNECT;
import static com.xebialabs.overthere.ConnectionOptions.TEMPORARY_DIRECTORY_PATH;
import static com.xebialabs.overthere.ConnectionOptions.TEMPORARY_FILE_CREATION_RETRIES;
import static com.xebialabs.overthere.ConnectionOptions.*;
import static com.xebialabs.overthere.util.ConsoleOverthereExecutionOutputHandler.syserrHandler;
import static com.xebialabs.overthere.util.ConsoleOverthereExecutionOutputHandler.sysoutHandler;
import static com.xebialabs.overthere.util.OverthereProcessOutputHandlerWrapper.wrapStderr;
import static com.xebialabs.overthere.util.OverthereProcessOutputHandlerWrapper.wrapStdout;
import static com.xebialabs.overthere.util.OverthereUtils.getBaseName;
import static com.xebialabs.overthere.util.OverthereUtils.getExtension;

Expand Down Expand Up @@ -267,83 +257,22 @@ public void setWorkingDirectory(OverthereFile workingDirectory) {
this.workingDirectory = workingDirectory;
}

/**
* Executes a command with its arguments.
*
* @param handler
* the handler that will be invoked when the executed command generated output.
* @param commandLine
* the command line to execute.
* @return the exit value of the executed command. Usually 0 on successful execution.
*/
@Override
public int execute(final OverthereProcessOutputHandler handler, final CmdLine commandLine) {
public final int execute(final CmdLine commandLine) {
return execute(sysoutHandler(), syserrHandler(), commandLine);
}

@Override
public int execute(final OverthereExecutionOutputHandler stdoutHandler, final OverthereExecutionOutputHandler stderrHandler, final CmdLine commandLine) {
final OverthereProcess process = startProcess(commandLine);
Thread stdoutReaderThread = null;
Thread stderrReaderThread = null;
final CountDownLatch latch = new CountDownLatch(2);
try {
stdoutReaderThread = new Thread("Stdout reader thread for command " + commandLine + " on " + this) {
@Override
public void run() {
StringBuilder lineBuffer = new StringBuilder();
InputStreamReader stdoutReader = new InputStreamReader(process.getStdout());
latch.countDown();
try {
int cInt = stdoutReader.read();
while (cInt > -1) {
char c = (char) cInt;
handler.handleOutput(c);
if (c != '\r' && c != '\n') {
lineBuffer.append(c);
}
if (c == '\n') {
handler.handleOutputLine(lineBuffer.toString());
lineBuffer.setLength(0);
}
cInt = stdoutReader.read();
}
} catch (Exception exc) {
logger.error("An exception occured while reading from stdout", exc);
} finally {
closeQuietly(stdoutReader);
if (lineBuffer.length() > 0) {
handler.handleOutputLine(lineBuffer.toString());
}
}
}
};
stdoutReaderThread = getThread("stdout", commandLine.toString(), stdoutHandler, process.getStdout(), latch);
stdoutReaderThread.start();

stderrReaderThread = new Thread("Stderr reader thread for command " + commandLine + " on " + this) {
@Override
public void run() {
StringBuilder lineBuffer = new StringBuilder();
InputStreamReader stderrReader = new InputStreamReader(process.getStderr());
latch.countDown();
try {
int readInt = stderrReader.read();
while (readInt > -1) {
char c = (char) readInt;
if (c != '\r' && c != '\n') {
lineBuffer.append(c);
}
if (c == '\n') {
handler.handleErrorLine(lineBuffer.toString());
lineBuffer.setLength(0);
}
readInt = stderrReader.read();
}
} catch (Exception exc) {
logger.error("An exception occured while reading from stderr", exc);
} finally {
closeQuietly(stderrReader);
if (lineBuffer.length() > 0) {
handler.handleErrorLine(lineBuffer.toString());
}
}
}
};
stderrReaderThread = getThread("stderr", commandLine.toString(), stderrHandler, process.getStderr(), latch);
stderrReaderThread.start();

try {
Expand All @@ -358,26 +287,69 @@ public void run() {
throw new RuntimeIOException("Execution interrupted", exc);
}
} finally {
if (stdoutReaderThread != null) {
try {
// interrupt the stdout reader thread in case it is stuck waiting for output that will never come
stdoutReaderThread.interrupt();
stdoutReaderThread.join();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
quietlyJoinThread(stdoutReaderThread);
quietlyJoinThread(stderrReaderThread);
}
}

private void quietlyJoinThread(final Thread thread) {
if (thread != null) {
try {
// interrupt the thread in case it is stuck waiting for output that will never come
thread.interrupt();
thread.join();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
if (stderrReaderThread != null) {
}
}

private Thread getThread(final String streamName, final String commandLine, final OverthereExecutionOutputHandler outputHandler, final InputStream stream, final CountDownLatch latch) {
return new Thread(streamName + " reader thread for command " + commandLine + " on " + this) {
@Override
public void run() {
StringBuilder lineBuffer = new StringBuilder();
InputStreamReader stdoutReader = new InputStreamReader(stream);
latch.countDown();
try {
// interrupt the stdout reader thread in case it is stuck waiting for output that will never come
stderrReaderThread.interrupt();
stderrReaderThread.join();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
int cInt = stdoutReader.read();
while (cInt > -1) {
char c = (char) cInt;
outputHandler.handleChar(c);
if (c != '\r' && c != '\n') {
lineBuffer.append(c);
}
if (c == '\n') {
outputHandler.handleLine(lineBuffer.toString());
lineBuffer.setLength(0);
}
cInt = stdoutReader.read();
}
} catch (Exception exc) {
logger.error("An exception occured while reading from " + streamName, exc);
} finally {
closeQuietly(stdoutReader);
if (lineBuffer.length() > 0) {
outputHandler.handleLine(lineBuffer.toString());
}
}
}
}
};
}

/**
* Executes a command with its arguments.
*
* @param handler
* the handler that will be invoked when the executed command generated output.
* @param commandLine
* the command line to execute.
* @return the exit value of the executed command. Usually 0 on successful execution.
* @deprecated use {@link BaseOverthereConnection#execute(com.xebialabs.overthere.OverthereExecutionOutputHandler, com.xebialabs.overthere.OverthereExecutionOutputHandler, com.xebialabs.overthere.CmdLine)}
*/
@Override
public final int execute(final OverthereProcessOutputHandler handler, final CmdLine commandLine) {
return execute(wrapStdout(handler), wrapStderr(handler), commandLine);
}

/**
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/com/xebialabs/overthere/ssh/SshFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@

import static com.xebialabs.overthere.OperatingSystemFamily.WINDOWS;

import com.xebialabs.overthere.CmdLine;
import com.xebialabs.overthere.OverthereFile;
import com.xebialabs.overthere.OverthereProcessOutputHandler;
import com.xebialabs.overthere.RuntimeIOException;
import com.xebialabs.overthere.*;
import com.xebialabs.overthere.spi.BaseOverthereFile;

/**
Expand Down Expand Up @@ -106,8 +103,8 @@ public void delete() throws RuntimeIOException {

protected abstract void deleteDirectory();

protected int executeCommand(OverthereProcessOutputHandler handler, CmdLine commandLine) {
return connection.execute(handler, commandLine);
protected int executeCommand(OverthereExecutionOutputHandler outHandler, OverthereExecutionOutputHandler errHandler, CmdLine commandLine) {
return connection.execute(outHandler, errHandler, commandLine);
}

@Override
Expand Down
Loading

0 comments on commit f032f7c

Please sign in to comment.