001: package org.objectweb.celtix.testutil.common;
002:
003: import java.io.File;
004: import java.io.FileNotFoundException;
005: import java.io.FileOutputStream;
006: import java.io.IOException;
007: import java.io.InputStream;
008: import java.io.PrintStream;
009: import java.lang.reflect.Constructor;
010: import java.net.URL;
011: import java.net.URLClassLoader;
012: import java.util.ArrayList;
013: import java.util.List;
014: import java.util.Map;
015: import java.util.logging.Logger;
016:
017: public class ServerLauncher {
018:
019: public static final int DEFAULT_TIMEOUT = 3 * 60 * 1000;
020:
021: protected static final String SERVER_FAILED = "server startup failed (not a log message)";
022:
023: private static final boolean DEFAULT_IN_PROCESS = false;
024:
025: private static final Logger LOG = Logger
026: .getLogger(ServerLauncher.class.getName());
027:
028: boolean serverPassed;
029: final String className;
030:
031: private final boolean debug = false;
032: private boolean inProcess = DEFAULT_IN_PROCESS;
033: private AbstractTestServerBase inProcessServer;
034:
035: private final String javaExe;
036: private Process process;
037: private boolean serverIsReady;
038: private boolean serverIsStopped;
039: private boolean serverLaunchFailed;
040: private Map<String, String> properties;
041: private String[] serverArgs;
042:
043: private final Mutex mutex = new Mutex();
044:
045: public ServerLauncher(String theClassName) {
046: this (theClassName, DEFAULT_IN_PROCESS);
047: }
048:
049: public ServerLauncher(String theClassName, boolean inprocess) {
050: inProcess = inprocess;
051: className = theClassName;
052: javaExe = System.getProperty("java.home") + File.separator
053: + "bin" + File.separator + "java";
054: }
055:
056: public ServerLauncher(String theClassName, Map<String, String> p,
057: String[] args) {
058: this (theClassName, p, args, false);
059: }
060:
061: public ServerLauncher(String theClassName, Map<String, String> p,
062: String[] args, boolean inprocess) {
063: className = theClassName;
064: properties = p;
065: serverArgs = args;
066: inProcess = inprocess;
067: javaExe = System.getProperty("java.home") + File.separator
068: + "bin" + File.separator + "java";
069: }
070:
071: private boolean waitForServerToStop() {
072: synchronized (mutex) {
073: while (!serverIsStopped) {
074: try {
075: TimeoutCounter tc = new TimeoutCounter(
076: DEFAULT_TIMEOUT);
077: mutex.wait(DEFAULT_TIMEOUT);
078: if (tc.isTimeoutExpired()) {
079: System.out.println("destroying server process");
080: process.destroy();
081: break;
082: }
083: } catch (InterruptedException ex) {
084: ex.printStackTrace();
085: }
086: }
087: if (!inProcess) {
088: //wait for process to end...
089: TimeoutCounter tc = new TimeoutCounter(DEFAULT_TIMEOUT);
090: while (!tc.isTimeoutExpired()) {
091: try {
092: process.exitValue();
093: break;
094: } catch (IllegalThreadStateException ex) {
095: //ignore, process hasn't ended
096: try {
097: Thread.sleep(1000);
098: } catch (InterruptedException ex1) {
099: //ignore
100: }
101: }
102: }
103: if (tc.isTimeoutExpired()) {
104: process.destroy();
105: }
106: }
107: }
108: return serverIsStopped;
109: }
110:
111: public void signalStop() throws IOException {
112: if (process != null) {
113: process.getOutputStream().write('q');
114: process.getOutputStream().write('\n');
115: process.getOutputStream().flush();
116: }
117: }
118:
119: public boolean stopServer() throws IOException {
120: if (inProcess) {
121: try {
122: return inProcessServer.stopInProcess();
123: } catch (Exception ex) {
124: ex.printStackTrace();
125: throw new IOException(ex.getMessage());
126: }
127: } else {
128: if (process != null) {
129: if (!serverIsStopped) {
130: try {
131: signalStop();
132: } catch (IOException ex) {
133: //ignore
134: }
135: }
136: waitForServerToStop();
137: process.destroy();
138: }
139: }
140: return serverPassed;
141: }
142:
143: public boolean launchServer() throws IOException {
144:
145: serverIsReady = false;
146: serverLaunchFailed = false;
147:
148: if (inProcess) {
149: Class<?> cls;
150: try {
151: cls = Class.forName(className);
152: Class<? extends AbstractTestServerBase> svcls = cls
153: .asSubclass(AbstractTestServerBase.class);
154: if (null == serverArgs) {
155: inProcessServer = svcls.newInstance();
156: } else {
157: Constructor ctor = svcls.getConstructor(serverArgs
158: .getClass());
159: inProcessServer = (AbstractTestServerBase) ctor
160: .newInstance(new Object[] { serverArgs });
161: }
162: inProcessServer.startInProcess();
163: serverIsReady = true;
164: } catch (Exception ex) {
165: ex.printStackTrace();
166: serverLaunchFailed = true;
167: }
168: } else {
169: List<String> cmd = getCommand();
170:
171: if (debug) {
172: System.err.print("CMD: ");
173: }
174:
175: ProcessBuilder pb = new ProcessBuilder(cmd);
176: pb.redirectErrorStream(true);
177: process = pb.start();
178:
179: launchOutputMonitorThread(process.getInputStream(),
180: System.out);
181:
182: synchronized (mutex) {
183: do {
184: TimeoutCounter tc = new TimeoutCounter(
185: DEFAULT_TIMEOUT);
186: try {
187: mutex.wait(DEFAULT_TIMEOUT);
188: if (tc.isTimeoutExpired()) {
189: break;
190: }
191: } catch (InterruptedException e) {
192: e.printStackTrace();
193: }
194: } while (!serverIsReady && !serverLaunchFailed);
195: }
196: }
197: return serverIsReady;
198: }
199:
200: public int waitForServer() {
201: int ret = -1;
202: try {
203: process.waitFor();
204: ret = process.exitValue();
205: } catch (InterruptedException e) {
206: e.printStackTrace();
207: }
208: return ret;
209: }
210:
211: private void launchOutputMonitorThread(final InputStream in,
212: final PrintStream out) {
213: Thread t = new OutputMonitorThread(in, out);
214: t.start();
215: }
216:
217: private class OutputMonitorThread extends Thread {
218: InputStream in;
219: PrintStream out;
220:
221: OutputMonitorThread(InputStream i, PrintStream o) {
222: in = i;
223: out = o;
224: }
225:
226: public void run() {
227: try {
228: StringBuilder serverOutput = new StringBuilder();
229: String outputDir = System
230: .getProperty("server.output.dir",
231: "target/surefire-reports/");
232: FileOutputStream fos;
233: try {
234: fos = new FileOutputStream(outputDir + className
235: + ".out");
236: } catch (FileNotFoundException fex) {
237: outputDir = System.getProperty("basedir")
238: + "/target/surefire-reports/";
239: fos = new FileOutputStream(outputDir + className
240: + ".out");
241: }
242: PrintStream ps = new PrintStream(fos);
243: boolean running = true;
244: for (int ch = in.read(); ch != -1; ch = in.read()) {
245: serverOutput.append((char) ch);
246: if (debug) {
247: System.err.print((char) ch);
248: }
249: String s = serverOutput.toString();
250: if (s.contains("server ready")) {
251: notifyServerIsReady();
252: } else if (s.contains("server passed")) {
253: serverPassed = true;
254: } else if (s.contains("server stopped")) {
255: notifyServerIsStopped();
256: running = false;
257: } else if (s.contains(SERVER_FAILED)) {
258: notifyServerFailed();
259: running = false;
260: }
261: if (ch == '\n' || !running) {
262: synchronized (out) {
263: ps.print(serverOutput.toString());
264: serverOutput = new StringBuilder();
265: ps.flush();
266: }
267: }
268: }
269:
270: } catch (IOException ex) {
271: if (!ex.getMessage().contains("Stream closed")) {
272: ex.printStackTrace();
273: }
274: }
275: }
276: }
277:
278: void notifyServerIsReady() {
279: synchronized (mutex) {
280: serverIsReady = true;
281: mutex.notifyAll();
282: }
283: }
284:
285: void notifyServerIsStopped() {
286: synchronized (mutex) {
287: LOG.info("notify server stopped");
288: serverIsStopped = true;
289: mutex.notifyAll();
290: }
291: }
292:
293: void notifyServerFailed() {
294: synchronized (mutex) {
295: serverIsStopped = true;
296: mutex.notifyAll();
297: }
298: }
299:
300: private List<String> getCommand() {
301:
302: List<String> cmd = new ArrayList<String>();
303: cmd.add(javaExe);
304:
305: if (null != properties) {
306: for (Map.Entry<String, String> entry : properties
307: .entrySet()) {
308: cmd.add("-D" + entry.getKey() + "=" + entry.getValue());
309: }
310: }
311:
312: cmd.add("-ea");
313: cmd.add("-classpath");
314:
315: ClassLoader loader = this .getClass().getClassLoader();
316: StringBuffer classpath = new StringBuffer(System
317: .getProperty("java.class.path"));
318: if (loader instanceof URLClassLoader) {
319: URLClassLoader urlloader = (URLClassLoader) loader;
320: for (URL url : urlloader.getURLs()) {
321: classpath.append(File.pathSeparatorChar);
322: classpath.append(url.getFile());
323: }
324: }
325: cmd.add(classpath.toString());
326:
327: cmd
328: .add("-Djavax.xml.ws.spi.Provider=org.objectweb.celtix.bus.jaxws.spi.ProviderImpl");
329:
330: String loggingPropertiesFile = System
331: .getProperty("java.util.logging.config.file");
332: if (null != loggingPropertiesFile) {
333: cmd.add("-Djava.util.logging.config.file="
334: + loggingPropertiesFile);
335: }
336:
337: cmd.add(className);
338:
339: if (null != serverArgs) {
340: for (String s : serverArgs) {
341: cmd.add(s);
342: }
343: }
344:
345: return cmd;
346: }
347:
348: static class Mutex {
349: // empty
350: }
351:
352: static class TimeoutCounter {
353: private final long expectedEndTime;
354:
355: public TimeoutCounter(long theExpectedTimeout) {
356: expectedEndTime = System.currentTimeMillis()
357: + theExpectedTimeout;
358: }
359:
360: public boolean isTimeoutExpired() {
361: return System.currentTimeMillis() > expectedEndTime;
362: }
363: }
364: }
|