package org.objectweb.celtix.testutil.common;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class ServerLauncher {
public static final int DEFAULT_TIMEOUT = 3 * 60 * 1000;
protected static final String SERVER_FAILED =
"server startup failed (not a log message)";
private static final boolean DEFAULT_IN_PROCESS = false;
private static final Logger LOG = Logger.getLogger(ServerLauncher.class.getName());
boolean serverPassed;
final String className;
private final boolean debug = false;
private boolean inProcess = DEFAULT_IN_PROCESS;
private AbstractTestServerBase inProcessServer;
private final String javaExe;
private Process process;
private boolean serverIsReady;
private boolean serverIsStopped;
private boolean serverLaunchFailed;
private Map<String, String> properties;
private String[] serverArgs;
private final Mutex mutex = new Mutex();
public ServerLauncher(String theClassName) {
this(theClassName, DEFAULT_IN_PROCESS);
}
public ServerLauncher(String theClassName, boolean inprocess) {
inProcess = inprocess;
className = theClassName;
javaExe = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
}
public ServerLauncher(String theClassName, Map<String, String> p, String[] args) {
this(theClassName, p, args, false);
}
public ServerLauncher(String theClassName, Map<String, String> p, String[] args, boolean inprocess) {
className = theClassName;
properties = p;
serverArgs = args;
inProcess = inprocess;
javaExe = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
}
private boolean waitForServerToStop() {
synchronized (mutex) {
while (!serverIsStopped) {
try {
TimeoutCounter tc = new TimeoutCounter(DEFAULT_TIMEOUT);
mutex.wait(DEFAULT_TIMEOUT);
if (tc.isTimeoutExpired()) {
System.out.println("destroying server process");
process.destroy();
break;
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
if (!inProcess) {
//wait for process to end...
TimeoutCounter tc = new TimeoutCounter(DEFAULT_TIMEOUT);
while (!tc.isTimeoutExpired()) {
try {
process.exitValue();
break;
} catch (IllegalThreadStateException ex) {
//ignore, process hasn't ended
try {
Thread.sleep(1000);
} catch (InterruptedException ex1) {
//ignore
}
}
}
if (tc.isTimeoutExpired()) {
process.destroy();
}
}
}
return serverIsStopped;
}
public void signalStop() throws IOException {
if (process != null) {
process.getOutputStream().write('q');
process.getOutputStream().write('\n');
process.getOutputStream().flush();
}
}
public boolean stopServer() throws IOException {
if (inProcess) {
try {
return inProcessServer.stopInProcess();
} catch (Exception ex) {
ex.printStackTrace();
throw new IOException(ex.getMessage());
}
} else {
if (process != null) {
if (!serverIsStopped) {
try {
signalStop();
} catch (IOException ex) {
//ignore
}
}
waitForServerToStop();
process.destroy();
}
}
return serverPassed;
}
public boolean launchServer() throws IOException {
serverIsReady = false;
serverLaunchFailed = false;
if (inProcess) {
Class<?> cls;
try {
cls = Class.forName(className);
Class<? extends AbstractTestServerBase> svcls =
cls.asSubclass(AbstractTestServerBase.class);
if (null == serverArgs) {
inProcessServer = svcls.newInstance();
} else {
Constructor ctor = svcls.getConstructor(serverArgs.getClass());
inProcessServer = (AbstractTestServerBase)ctor.newInstance(new Object[] {serverArgs});
}
inProcessServer.startInProcess();
serverIsReady = true;
} catch (Exception ex) {
ex.printStackTrace();
serverLaunchFailed = true;
}
} else {
List<String> cmd = getCommand();
if (debug) {
System.err.print("CMD: ");
}
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
process = pb.start();
launchOutputMonitorThread(process.getInputStream(), System.out);
synchronized (mutex) {
do {
TimeoutCounter tc = new TimeoutCounter(DEFAULT_TIMEOUT);
try {
mutex.wait(DEFAULT_TIMEOUT);
if (tc.isTimeoutExpired()) {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!serverIsReady && !serverLaunchFailed);
}
}
return serverIsReady;
}
public int waitForServer() {
int ret = -1;
try {
process.waitFor();
ret = process.exitValue();
} catch (InterruptedException e) {
e.printStackTrace();
}
return ret;
}
private void launchOutputMonitorThread(final InputStream in, final PrintStream out) {
Thread t = new OutputMonitorThread(in, out);
t.start();
}
private class OutputMonitorThread extends Thread {
InputStream in;
PrintStream out;
OutputMonitorThread(InputStream i, PrintStream o) {
in = i;
out = o;
}
public void run() {
try {
StringBuilder serverOutput = new StringBuilder();
String outputDir = System.getProperty("server.output.dir", "target/surefire-reports/");
FileOutputStream fos;
try {
fos = new FileOutputStream(outputDir + className + ".out");
} catch (FileNotFoundException fex) {
outputDir = System.getProperty("basedir") + "/target/surefire-reports/";
fos = new FileOutputStream(outputDir + className + ".out");
}
PrintStream ps = new PrintStream(fos);
boolean running = true;
for (int ch = in.read(); ch != -1; ch = in.read()) {
serverOutput.append((char)ch);
if (debug) {
System.err.print((char)ch);
}
String s = serverOutput.toString();
if (s.contains("server ready")) {
notifyServerIsReady();
} else if (s.contains("server passed")) {
serverPassed = true;
} else if (s.contains("server stopped")) {
notifyServerIsStopped();
running = false;
} else if (s.contains(SERVER_FAILED)) {
notifyServerFailed();
running = false;
}
if (ch == '\n' || !running) {
synchronized (out) {
ps.print(serverOutput.toString());
serverOutput = new StringBuilder();
ps.flush();
}
}
}
} catch (IOException ex) {
if (!ex.getMessage().contains("Stream closed")) {
ex.printStackTrace();
}
}
}
}
void notifyServerIsReady() {
synchronized (mutex) {
serverIsReady = true;
mutex.notifyAll();
}
}
void notifyServerIsStopped() {
synchronized (mutex) {
LOG.info("notify server stopped");
serverIsStopped = true;
mutex.notifyAll();
}
}
void notifyServerFailed() {
synchronized (mutex) {
serverIsStopped = true;
mutex.notifyAll();
}
}
private List<String> getCommand() {
List<String> cmd = new ArrayList<String>();
cmd.add(javaExe);
if (null != properties) {
for (Map.Entry<String, String> entry : properties.entrySet()) {
cmd.add("-D" + entry.getKey() + "=" + entry.getValue());
}
}
cmd.add("-ea");
cmd.add("-classpath");
ClassLoader loader = this.getClass().getClassLoader();
StringBuffer classpath = new StringBuffer(System.getProperty("java.class.path"));
if (loader instanceof URLClassLoader) {
URLClassLoader urlloader = (URLClassLoader)loader;
for (URL url : urlloader.getURLs()) {
classpath.append(File.pathSeparatorChar);
classpath.append(url.getFile());
}
}
cmd.add(classpath.toString());
cmd.add("-Djavax.xml.ws.spi.Provider=org.objectweb.celtix.bus.jaxws.spi.ProviderImpl");
String loggingPropertiesFile = System.getProperty("java.util.logging.config.file");
if (null != loggingPropertiesFile) {
cmd.add("-Djava.util.logging.config.file=" + loggingPropertiesFile);
}
cmd.add(className);
if (null != serverArgs) {
for (String s : serverArgs) {
cmd.add(s);
}
}
return cmd;
}
static class Mutex {
// empty
}
static class TimeoutCounter {
private final long expectedEndTime;
public TimeoutCounter(long theExpectedTimeout) {
expectedEndTime = System.currentTimeMillis() + theExpectedTimeout;
}
public boolean isTimeoutExpired() {
return System.currentTimeMillis() > expectedEndTime;
}
}
}