package fitnesse.testsystems;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.SystemUtils;
public abstract class ClientBuilder<T> {
static final String COMMAND_PATTERN = "COMMAND_PATTERN";
static final String[] DEFAULT_COMMAND_PATTERN = {
javaExecutable(),
"-cp",
"%p",
"%m" };
static final String[] DEFAULT_JAVA_DEBUG_COMMAND = {
javaExecutable(),
"-Xdebug",
"-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000",
"-cp",
"%p",
"%m"};
static final String DEFAULT_CSHARP_DEBUG_RUNNER_FIND = "runner.exe";
static final String DEFAULT_CSHARP_DEBUG_RUNNER_REPLACE = "runnerw.exe";
static final String REMOTE_DEBUG_COMMAND = "REMOTE_DEBUG_COMMAND";
static final String TEST_RUNNER = "TEST_RUNNER";
static final String REMOTE_DEBUG_RUNNER = "REMOTE_DEBUG_RUNNER";
static final String CLASSPATH_PROPERTY = "CLASSPATH_PROPERTY";
private final Descriptor descriptor;
public ClientBuilder(Descriptor descriptor) {
this.descriptor = descriptor;
}
protected String[] buildCommand(String[] commandPattern, String testRunner, ClassPath classPath) {
ClassPath completeClassPath;
if (isJava(commandPattern[0])) {
completeClassPath = classPath.withLocationForClass(testRunner);
} else {
completeClassPath = classPath;
}
String[] command = new String[commandPattern.length];
for (int i = 0; i < commandPattern.length; i++) {
command[i] = replace(commandPattern[i], "%p", completeClassPath.toString());
command[i] = replace(command[i], "%m", testRunner);
if (SystemUtils.IS_OS_WINDOWS && command[i].contains(" ")) {
command[i] = "\"" + command[i] + "\"";
}
}
return command;
}
private boolean isJava(String command) {
return command.toLowerCase().contains("java");
}
protected static String replace(String value, String mark, String replacement) {
return value.replaceAll(mark, Matcher.quoteReplacement(replacement));
}
public abstract T build() throws IOException;
protected abstract String defaultTestRunner();
public String getTestSystemName() {
String testSystemName = descriptor.getTestSystem();
String testRunner = getTestRunnerNormal();
return String.format("%s:%s", testSystemName, testRunner);
}
private String getTestRunnerDebug() {
String program = getVariable(REMOTE_DEBUG_RUNNER);
if (program == null) {
program = getTestRunnerNormal();
if (program.toLowerCase().contains(DEFAULT_CSHARP_DEBUG_RUNNER_FIND))
program = program.toLowerCase().replace(DEFAULT_CSHARP_DEBUG_RUNNER_FIND,
DEFAULT_CSHARP_DEBUG_RUNNER_REPLACE);
}
return program;
}
public String getTestRunner() {
if (isDebug())
return getTestRunnerDebug();
else
return getTestRunnerNormal();
}
private String[] getRemoteDebugCommandPattern() {
String testRunner = getVariable(REMOTE_DEBUG_COMMAND);
if (testRunner != null)
return parseCommandLine(testRunner);
testRunner = getVariable(COMMAND_PATTERN);
if (testRunner == null || isJava(testRunner)) {
return DEFAULT_JAVA_DEBUG_COMMAND;
}
return parseCommandLine(testRunner);
}
public String[] getCommandPattern() {
if (isDebug())
return getRemoteDebugCommandPattern();
else
return getNormalCommandPattern();
}
private String[] getNormalCommandPattern() {
String testRunner = getVariable(COMMAND_PATTERN);
if (testRunner != null)
return parseCommandLine(testRunner);
return DEFAULT_COMMAND_PATTERN;
}
protected String[] parseCommandLine(String commandLine) {
Collection<String> result = new ArrayList<>();
Pattern p = Pattern.compile("\"([^\"]*)\"|[\\S]+");
Matcher m = p.matcher(commandLine);
while(m.find())
{
String token = (m.group(1)==null) ? m.group(0) : m.group(1);
result.add(token);
}
return result.toArray(new String[result.size()]);
}
public Map<String, String> createClasspathEnvironment(ClassPath classPath) {
String classpathProperty = getVariable(CLASSPATH_PROPERTY);
Map<String, String> environmentVariables = null;
if (classpathProperty != null) {
environmentVariables = Collections.singletonMap(classpathProperty, classPath.toString());
}
return environmentVariables;
}
public ClassPath getClassPath() {
return descriptor.getClassPath();
}
public boolean isDebug() {
return descriptor.isDebug();
}
public String getVariable(String name) {
return descriptor.getVariable(name);
}
public ExecutionLogListener getExecutionLogListener() {
return new DecoratingExecutionLogListener(getTestSystemName(), descriptor.getExecutionLogListener());
}
private String getTestRunnerNormal() {
String program = getVariable(TEST_RUNNER);
if (program == null)
program = defaultTestRunner();
return program;
}
protected static String javaExecutable() {
String javaHome = System.getenv("JAVA_HOME");
String result;
if (javaHome != null) {
result = javaHome + File.separator + "bin" + File.separator + "java";
} else {
result = "java";
}
return result;
}
private static class DecoratingExecutionLogListener implements ExecutionLogListener {
private final String testSystemName;
private final ExecutionLogListener executionLogListener;
private DecoratingExecutionLogListener(String testSystemName, ExecutionLogListener executionLogListener) {
this.testSystemName = testSystemName;
this.executionLogListener = executionLogListener;
}
@Override
public void commandStarted(final ExecutionContext context) {
executionLogListener.commandStarted(new ExecutionContext() {
@Override
public String getCommand() {
return context.getCommand();
}
@Override
public String getTestSystemName() {
return testSystemName;
}
});
}
@Override
public void stdOut(String output) {
executionLogListener.stdOut(output);
}
@Override
public void stdErr(String output) {
executionLogListener.stdErr(output);
}
@Override
public void exitCode(int exitCode) {
executionLogListener.exitCode(exitCode);
}
@Override
public void exceptionOccurred(Throwable e) {
executionLogListener.exceptionOccurred(e);
}
}
}