package org.pitest.process;
import static org.pitest.functional.prelude.Prelude.or;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.pitest.functional.FCollection;
import org.pitest.functional.FunctionalList;
import org.pitest.functional.Option;
import org.pitest.functional.predicate.Predicate;
public class WrappingProcess {
private final int port;
private final ProcessArgs processArgs;
private final Class<?> minionClass;
private JavaProcess process;
public WrappingProcess(int port, ProcessArgs args, Class<?> minionClass) {
this.port = port;
this.processArgs = args;
this.minionClass = minionClass;
}
public void start() throws IOException {
final String[] args = { "" + this.port };
ProcessBuilder processBuilder = createProcessBuilder(
this.processArgs.getJavaExecutable(), this.processArgs.getJvmArgs(),
this.minionClass, Arrays.asList(args),
this.processArgs.getJavaAgentFinder());
configureProcessBuilder(processBuilder, this.processArgs.getWorkingDir(),
this.processArgs.getLaunchClassPath(),
this.processArgs.getEnvironmentVariables());
Process process = processBuilder.start();
this.process = new JavaProcess(process, this.processArgs.getStdout(),
this.processArgs.getStdErr());
}
private void configureProcessBuilder(ProcessBuilder processBuilder,
File workingDirectory, String initialClassPath,
Map<String, String> environmentVariables) {
processBuilder.directory(workingDirectory);
Map<String, String> environment = processBuilder.environment();
environment.put("CLASSPATH", initialClassPath);
for (Map.Entry<String, String> entry : environmentVariables.entrySet()) {
environment.put(entry.getKey(), entry.getValue());
}
}
public void destroy() {
this.process.destroy();
}
private static ProcessBuilder createProcessBuilder(String javaProc,
List<String> args, Class<?> mainClass, List<String> programArgs,
JavaAgent javaAgent) {
List<String> cmd = createLaunchArgs(javaProc, javaAgent, args, mainClass,
programArgs);
// IBM jdk adds this, thereby breaking everything
removeClassPathProperties(cmd);
return new ProcessBuilder(cmd);
}
private static void removeClassPathProperties(List<String> cmd) {
for (int i = cmd.size() - 1; i >= 0; i--) {
if (cmd.get(i).startsWith("-Djava.class.path")) {
cmd.remove(i);
}
}
}
private static List<String> createLaunchArgs(String javaProcess,
JavaAgent agentJarLocator, List<String> args, Class<?> mainClass,
List<String> programArgs) {
List<String> cmd = new ArrayList<String>();
cmd.add(javaProcess);
cmd.addAll(args);
addPITJavaAgent(agentJarLocator, cmd);
addLaunchJavaAgents(cmd);
cmd.add(mainClass.getName());
cmd.addAll(programArgs);
return cmd;
}
private static void addPITJavaAgent(JavaAgent agentJarLocator,
List<String> cmd) {
Option<String> jarLocation = agentJarLocator.getJarLocation();
for (String each : jarLocation) {
cmd.add("-javaagent:" + each);
}
}
private static void addLaunchJavaAgents(List<String> cmd) {
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
@SuppressWarnings("unchecked")
FunctionalList<String> agents = FCollection.filter(rt.getInputArguments(),
or(isJavaAgentParam(), isEnvironmentSetting()));
cmd.addAll(agents);
}
private static Predicate<String> isEnvironmentSetting() {
return new Predicate<String>() {
@Override
public Boolean apply(String a) {
return a.startsWith("-D");
}
};
}
private static Predicate<String> isJavaAgentParam() {
return new Predicate<String>() {
@Override
public Boolean apply(String a) {
return a.toLowerCase().startsWith("-javaagent");
}
};
}
public JavaProcess getProcess() {
return this.process;
}
}