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