KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > diagnostics > collect > 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.enterprise.diagnostics.collect;
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 /**
36  * ProcessExecutor executes any OS specific commands as a sub process but does
37  * not wait more than a specified timeout value for the process to complete.
38  * This is a wrapper over java.lang.Runtime.getRuntime().exec()
39  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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