KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > ejb > codegen > ProcessExecutor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.ejb.codegen;
24
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.util.logging.Logger JavaDoc;
28 import java.util.logging.Level JavaDoc;
29
30 import com.sun.enterprise.util.i18n.StringManager;
31
32 import com.sun.logging.LogDomains;
33
34 /**
35  * ProcessExecutor executes any OS specific commands as a sub process but does
36  * not wait more than a specified timeout value for the process to complete.
37  * This is a wrapper over java.lang.Runtime.getRuntime().exec()
38  */

39 public class ProcessExecutor {
40
41     private static final StringManager localStrings =
42             StringManager.getManager(ProcessExecutor.class);
43     static final Logger JavaDoc logger =
44             Logger.getLogger(LogDomains.DPL_LOGGER);
45
46     private String JavaDoc[] command;
47
48     private long timeout;
49
50     private ProcessRunner runner = null;
51
52     /**
53      * Create a new process executor object.
54      * @param cmd Command to be executed. See java.lang.Runtime.exec(String[])
55      * for more information.
56      * @param timeout time to wait for the process to complete. This is in
57      * milliseconds
58      * @throws IllegalArgumentException if cmd is null or zero length array
59      * or timeout is <= 0
60      */

61     public ProcessExecutor(String JavaDoc[] cmd, long timeout) {
62         if (cmd == null || cmd.length == 0) {
63             throw new IllegalArgumentException JavaDoc(
64                     localStrings.getString("process.null_or_empty_command"));
65         }
66         if (timeout <= 0) {
67             throw new IllegalArgumentException JavaDoc(
68                 localStrings.getString("process.invalid_timeout_value",
69                 new Long JavaDoc(timeout)));
70         }
71         this.command = cmd;
72         this.timeout= timeout;
73     }
74
75     /**
76      * Get command as a string.
77      */

78     public String JavaDoc getCommandString() {
79         String JavaDoc cmdString = null;
80         if (runner != null) {
81             cmdString = runner.getCommandString();
82         }
83         if (cmdString == null) {
84             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
85             for (int i = 0; i < command.length; i++) {
86                 buf.append(command[i] + " ");
87             }
88             cmdString = buf.toString();
89         }
90         return cmdString;
91     }
92
93     /**
94      * Get timeout value (in milliseconds)
95      */

96     public long getTimeout() {
97         return timeout;
98     }
99
100     /**
101      * Set timeout to specified value.
102      * @param timeout time to wait for process to complete execution (in
103      * milliseconds)
104      * @throws IllegalArgumentException if specified timeout <= 0
105      */

106     public void setTimeout(long timeout) {
107         if (timeout >= 0) {
108             this.timeout = timeout;
109         } else {
110             throw new IllegalArgumentException JavaDoc(
111                     localStrings.getString("process.invalid_timeout_value",
112                     new Long JavaDoc(timeout)));
113         }
114     }
115
116     /**
117      * Execute the command.
118      * @throws IllegalStateException if process already executed
119      * @throws ProcessExecutorException if process execution times out or if
120      * there is any error in execution
121      */

122     public String JavaDoc execute() throws ProcessExecutorException {
123         if (runner != null) {
124             throw new IllegalStateException JavaDoc(
125                     localStrings.getString("process.already_executed"));
126         }
127         runner = new ProcessRunner(command, timeout);
128         Thread JavaDoc runnerThread = new Thread JavaDoc(runner);
129         runnerThread.start();
130         try {
131             runnerThread.join(timeout);
132         } catch (InterruptedException JavaDoc ie) {
133             logger.log(Level.FINEST, "process.waiter_interrupted",
134                     getCommandString());
135         }
136         if (runnerThread.isAlive()) {
137             if (!runner.completed) {
138                 logger.log(Level.FINEST, "process.interrupting",
139                         new Object JavaDoc[] {new Long JavaDoc(timeout), getCommandString()});
140                 runnerThread.interrupt();
141                 try {
142                     // Wait for 500 ms for thread to terminate
143
runnerThread.join(500);
144                 } catch (InterruptedException JavaDoc ie) {
145                     // Ignore this exception. Interrupted while waiting for
146
// runner thread to respond to interrupt() call
147
}
148                 if (!runner.completed && !runner.interrupted) {
149                     // Thread did not finish, force the status to interrupted
150
runner.interrupted = true;
151                 }
152             }
153         }
154         if (runner.interrupted || runner.exception != null) {
155             if (runner.exception == null) {
156                 // Thread did not complete but there is no exception, assume
157
// it did not finish because of timeout
158
runner.makeTimeoutException();
159             }
160             throw runner.exception;
161         }
162         return runner.stdout.toString();
163     }
164
165     /**
166      * Is process execution complete.
167      * @returns true if process execution was completed, false otherwise
168      */

169     public boolean isCompleted() {
170         boolean completed = false;
171         if (runner != null) {
172             completed = runner.completed;
173         }
174         return completed;
175     }
176
177     /**
178      * Is (was) process execution interrupted.
179      * @returns true if the process execution was interrupted (typically
180      * because it did not finish in specified timeout), false otherwise
181      */

182     public boolean isInterrupted() {
183         boolean interrupted = false;
184         if (runner != null) {
185             interrupted = runner.interrupted;
186         }
187         return interrupted;
188     }
189
190     /**
191      * Get standard output of the process.
192      */

193     public String JavaDoc getStdout() {
194         String JavaDoc stdout = null;
195         if (runner != null) {
196             stdout = runner.stdout.toString();
197         }
198         return stdout;
199     }
200
201     /**
202      * Get standard error of the process.
203      */

204     public String JavaDoc getStderr() {
205         String JavaDoc stderr = null;
206         if (runner != null) {
207             stderr = runner.stderr.toString();
208         }
209         return stderr;
210     }
211
212     /**
213      * Get exit code of the process.
214      * @throws IllegalStateException if the process execution has not finished
215      * yet (or has not been started yet)
216      */

217     public int getExitCode() {
218         int exitCode = 0;
219         if (runner != null && runner.completed) {
220             exitCode = runner.exitCode;
221         } else {
222             throw new IllegalStateException JavaDoc(
223                     localStrings.getString("process.not_yet_executed"));
224         }
225         return exitCode;
226     }
227
228     /**
229      * Execute the process again. All results of previous execution are lost.
230      */

231     public String JavaDoc executeAgain() throws ProcessExecutorException {
232         runner = null;
233         return execute();
234     }
235 }
236
237 /**
238  * This class does the actual process execution. This is run in a different
239  * thread and the invoker thread waits on this thread.
240  */

241 class ProcessRunner implements Runnable JavaDoc {
242
243     static final Logger JavaDoc logger = ProcessExecutor.logger;
244     long timeout;
245     String JavaDoc[] cmd;
246     StringBuffer JavaDoc stdout = new StringBuffer JavaDoc();
247     StringBuffer JavaDoc stderr = new StringBuffer JavaDoc();
248     int exitCode;
249     boolean completed = false;
250     boolean interrupted = false;
251     ProcessExecutorException exception;
252     private String JavaDoc cmdString = null;
253
254
255     /**
256      * Create a new process runner for specified command. The timeout value
257      * passed in here is used only for creating log messages.
258      */

259     ProcessRunner(String JavaDoc[] cmd, long timeout) {
260         this.cmd = cmd;
261         this.timeout = timeout;
262     }
263
264     /**
265      * Run command by creating a sub process
266      */

267     public void run() {
268         Process JavaDoc process = null;
269         InputStream JavaDoc is = null;
270         InputStream JavaDoc es = null;
271         try {
272             try {
273                 process = Runtime.getRuntime().exec(cmd);
274             } catch (IOException JavaDoc ioe) {
275                 logger.log(Level.FINE, "process.creation_failed", ioe);
276                 makeOtherException(ioe);
277                 return;
278             }
279             if (checkInterrupted()) {
280                 return;
281             }
282             is = process.getInputStream();
283             es = process.getErrorStream();
284             readFromStream(es, stderr);
285             if (checkInterrupted()) {
286                 return;
287             }
288             readFromStream(is, stdout);
289             if (checkInterrupted()) {
290                 return;
291             }
292             try {
293                 is.close();
294                 es.close();
295                 is = null;
296                 es = null;
297             } catch (IOException JavaDoc ioe) {
298                 logger.log(Level.FINEST, "process.stream_close_error", ioe);
299             }
300             exitCode = process.waitFor();
301             if (exitCode != 0) {
302                 makeAbnormalTerminationException();
303             }
304             process.destroy();
305             process = null;
306             completed = true;
307         } catch (InterruptedException JavaDoc ie) {
308             logger.log(Level.FINEST, "process.interrupted");
309             interrupted = true;
310             makeTimeoutException();
311         } catch (Exception JavaDoc e) {
312             logger.log(Level.FINEST, "process.execution_failed", e);
313             makeOtherException(e);
314         } finally {
315             try {
316                 if (is != null) {
317                     is.close();
318                 }
319                 if (es != null) {
320                     es.close();
321                 }
322                 if (process != null) {
323                     process.destroy();
324                 }
325             } catch (Throwable JavaDoc t) {
326                 // Do nothing
327
}
328         }
329     }
330
331     /**
332      * Read data from specified stream and append it to buffer.
333      */

334     void readFromStream(InputStream JavaDoc stream, StringBuffer JavaDoc buffer) {
335         byte[] bytes = new byte[1024];
336         try {
337             int count = 0;
338             while ((count = stream.read(bytes)) != -1) {
339                 buffer.append(new String JavaDoc(bytes, 0 , count));
340                 if (checkInterrupted()) {
341                     return;
342                 }
343             }
344         } catch (IOException JavaDoc ioe) {
345             logger.log(Level.FINEST, "process.stream_read_error", ioe);
346         }
347     }
348
349     /**
350      * Check whether current thread has been interrupted and if so set
351      * exception appropriately (caused by timeout in this case)
352      */

353     private boolean checkInterrupted() {
354         if (Thread.currentThread().isInterrupted()) {
355             interrupted = true;
356             makeTimeoutException();
357         }
358         return interrupted;
359     }
360
361     /**
362      * Helper method to set ProcessExecutor exception
363      */

364     void makeTimeoutException() {
365         String JavaDoc outs = stderr.toString() + "\n" + stdout.toString();
366         exception = new ProcessExecutorException("process.timeout",
367                 "Process timed out.\nTimeout was {2} msecs\n"
368                 + "Attempted command: {0}\nOutput from command: {1}",
369                 new Object JavaDoc[] { getCommandString(), outs, new Long JavaDoc(timeout) });
370     }
371
372     /**
373      * Helper method to set ProcessExecutor exception
374      */

375     void makeAbnormalTerminationException() {
376         String JavaDoc outs = stderr.toString() + "\n" + stdout.toString();
377         exception = new ProcessExecutorException("process.abnormal_termination",
378                 "Abnormal process termination -- process returned: {0}\n"
379                 + "Attempted command: {1}\nOutput from command: {2}",
380                     new Object JavaDoc[] { new Integer JavaDoc(exitCode), getCommandString(),
381                     outs} );
382     }
383
384     /**
385      * Helper method to set ProcessExecutor exception
386      */

387     void makeOtherException(Throwable JavaDoc t) {
388         String JavaDoc outs = stderr.toString() + "\n" + stdout.toString();
389         exception = new ProcessExecutorException("process.unknown_exception",
390                 "Abnormal process termination -- process threw an Exception.\n"
391                 + "Attempted command: {0}\nOutput from command: {1}",
392                 new Object JavaDoc[] { getCommandString(), outs}, t );
393     }
394
395     /**
396      * Get command as a string
397      */

398     String JavaDoc getCommandString() {
399         if (cmdString == null) {
400             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
401             for (int i = 0; i < cmd.length; i++) {
402                 buf.append(cmd[i] + " ");
403             }
404             cmdString = buf.toString();
405         }
406         return cmdString;
407     }
408 }
409
Popular Tags