001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.db4ounit.util;
022:
023: import java.io.*;
024:
025: import com.db4o.foundation.*;
026: import com.db4o.foundation.io.Path4;
027:
028: /**
029: * @sharpen.ignore
030: */
031: public class IOServices {
032:
033: public static String buildTempPath(String fname) {
034: return Path4.combine(Path4.getTempPath(), fname);
035: }
036:
037: public static String safeCanonicalPath(String path) {
038: try {
039: return new File(path).getCanonicalPath();
040: } catch (IOException e) {
041: e.printStackTrace();
042: return path;
043: }
044: }
045:
046: public static String exec(String program) throws IOException,
047: InterruptedException {
048: return exec(program, null);
049: }
050:
051: public static String exec(String program, String[] arguments)
052: throws IOException, InterruptedException {
053: ProcessRunner runner = new ProcessRunner(program, arguments);
054: runner.waitFor();
055: return runner.formattedResult();
056: }
057:
058: public static String execAndDestroy(String program,
059: String[] arguments, String expectedOutput, long timeout)
060: throws IOException {
061: ProcessRunner runner = new ProcessRunner(program, arguments);
062: runner.destroy(expectedOutput, timeout);
063: return runner.formattedResult();
064: }
065:
066: public static class DestroyTimeoutException extends
067: RuntimeException {
068: }
069:
070: public static class ProcessTerminatedBeforeDestroyException extends
071: RuntimeException {
072: }
073:
074: static class ProcessRunner {
075:
076: final long _startTime;
077:
078: private final String _command;
079:
080: private final StreamReader _inputReader;
081:
082: private final StreamReader _errorReader;
083:
084: private final Process _process;
085:
086: private int _result;
087:
088: public ProcessRunner(String program, String[] arguments)
089: throws IOException {
090: _command = generateCommand(program, arguments);
091: _process = Runtime.getRuntime().exec(_command);
092: _inputReader = new StreamReader(_process.getInputStream());
093: _errorReader = new StreamReader(_process.getErrorStream());
094: _startTime = System.currentTimeMillis();
095: }
096:
097: private String generateCommand(String program,
098: String[] arguments) {
099: String command = program;
100: if (arguments != null) {
101: for (int i = 0; i < arguments.length; i++) {
102: command += " " + arguments[i];
103: }
104: }
105: return command;
106: }
107:
108: public int waitFor() throws InterruptedException {
109: _result = _process.waitFor();
110: stopReaders();
111: return _result;
112: }
113:
114: private boolean outputHasStarted() {
115: return _inputReader.outputHasStarted()
116: || _errorReader.outputHasStarted();
117: }
118:
119: private boolean outputContains(String str) {
120: return _inputReader.outputContains(str)
121: || _errorReader.outputContains(str);
122: }
123:
124: private void checkTimeOut(long time) {
125: Cool.sleepIgnoringInterruption(10);
126: if (System.currentTimeMillis() - _startTime > time) {
127: throw new DestroyTimeoutException();
128: }
129: }
130:
131: public void destroy(String expectedOutput, long timeout) {
132: try {
133: checkIfStarted(expectedOutput, timeout);
134: checkIfTerminated();
135:
136: // Race condition: If the process is terminated right here , it may
137: // terminate successfully before being destroyed.
138:
139: } finally {
140: _process.destroy();
141: stopReaders();
142: }
143: }
144:
145: private void checkIfStarted(String expectedOutput, long timeout) {
146: while (!outputHasStarted()) {
147: checkTimeOut(timeout);
148: }
149: while (!outputContains(expectedOutput)) {
150: checkTimeOut(timeout);
151: }
152: }
153:
154: private void checkIfTerminated() {
155: boolean ok = false;
156: try {
157: _process.exitValue();
158: } catch (IllegalThreadStateException ex) {
159: ok = true;
160: }
161: if (!ok) {
162: throw new ProcessTerminatedBeforeDestroyException();
163: }
164: }
165:
166: private void stopReaders() {
167: _inputReader.stop();
168: _errorReader.stop();
169: }
170:
171: public String formattedResult() {
172: String res = formatOutput("IOServices.exec", _command);
173:
174: if (_inputReader.hasResult()) {
175: res += formatOutput("out", _inputReader.result());
176: }
177: if (_errorReader.hasResult()) {
178: res += formatOutput("err", _errorReader.result());
179: }
180:
181: res += formatOutput("result", new Integer(_result)
182: .toString());
183:
184: return res;
185:
186: }
187:
188: private String formatOutput(String task, String output) {
189: return headLine(task) + output + "\n";
190: }
191:
192: private String headLine(String task) {
193: return "\n" + task + "\n----------------\n";
194: }
195:
196: }
197:
198: static class StreamReader implements Runnable {
199:
200: private final Object _lock = new Object();
201:
202: private final InputStream _stream;
203:
204: private final Thread _thread;
205:
206: private final StringBuffer _stringBuffer = new StringBuffer();
207:
208: private boolean _stopped;
209:
210: private String _result;
211:
212: StreamReader(InputStream stream) {
213: _stream = stream;
214: _thread = new Thread(this );
215: _thread.start();
216: }
217:
218: public void run() {
219: final InputStream bufferedStream = new BufferedInputStream(
220: _stream);
221: try {
222: while (!_stopped) {
223: int i = bufferedStream.read();
224: if (i >= 0) {
225: synchronized (_lock) {
226: _stringBuffer.append((char) i);
227: }
228: }
229: }
230: } catch (IOException e) {
231: e.printStackTrace();
232: }
233: _result = _stringBuffer.toString();
234: }
235:
236: public boolean outputHasStarted() {
237: synchronized (_lock) {
238: return _stringBuffer.length() > 0;
239: }
240: }
241:
242: public boolean outputContains(String str) {
243: synchronized (_lock) {
244: return _stringBuffer.toString().indexOf(str) >= 0;
245: }
246: }
247:
248: public void stop() {
249: _stopped = true;
250: try {
251: _thread.join();
252: } catch (InterruptedException e) {
253: e.printStackTrace();
254: }
255: }
256:
257: public boolean hasResult() {
258: return _result != null && _result.length() > 0;
259: }
260:
261: public String result() {
262: return _result;
263: }
264:
265: }
266:
267: }
|