PageRenderTime 39ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/plugins-trunk/Console/console/ConsoleProcess.java

#
Java | 325 lines | 215 code | 41 blank | 69 comment | 33 complexity | 09f06e53d398ead6210d549fea4bb747 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * ConsoleProcess.java - A running process
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2004 Slava Pestov
  7. * With modifications Copyright (C) 2005,2007 Alan Ezust
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package console;
  24. // {{{ Imports
  25. import java.util.Map;
  26. import java.io.IOException;
  27. import java.io.PipedInputStream;
  28. import java.io.PipedOutputStream;
  29. import javax.swing.SwingUtilities;
  30. import org.gjt.sp.jedit.jEdit;
  31. import org.gjt.sp.util.Log;
  32. import org.gjt.sp.util.StringList;
  33. // }}}
  34. // {{{ ConsoleProcess class
  35. class ConsoleProcess
  36. {
  37. // {{{ Data members
  38. /** The running subprocess */
  39. Process process;
  40. private SystemShell.ConsoleState consoleState;
  41. private String currentDirectory;
  42. private Console console;
  43. private Output output;
  44. private Output error;
  45. private String[] args;
  46. // {{{ Threads for handling the streams of running subprocesses
  47. private InputThread stdin;
  48. private StreamThread stdout;
  49. private StreamThread stderr;
  50. // }}}
  51. private int threadDoneCount = 0;
  52. private int exitCode = 834;
  53. private boolean stopped;
  54. /*
  55. * AWT thread writes stdin to this pipe, and the input thread writes it to
  56. * the process.
  57. */
  58. private PipedInputStream pipeIn;
  59. private PipedOutputStream pipeOut;
  60. // }}}
  61. // {{{ ConsoleProcess constructor
  62. ConsoleProcess(final Console console, final Output output, final String[] args,
  63. Map<String, String> env, SystemShell.ConsoleState consoleState,
  64. boolean foreground)
  65. {
  66. this.args = args;
  67. this.currentDirectory = consoleState.currentDirectory;
  68. this.console = console;
  69. if (foreground)
  70. {
  71. this.output = output;
  72. this.error = new ErrorOutput(console);
  73. this.consoleState = consoleState;
  74. }
  75. try
  76. {
  77. // Streams for getting user input
  78. pipeIn = new PipedInputStream();
  79. pipeOut = new PipedOutputStream(pipeIn);
  80. process = ProcessRunner.getProcessRunner().exec(args, env,
  81. currentDirectory);
  82. if (process == null)
  83. {
  84. String str = StringList.join(args, " ");
  85. throw new RuntimeException( "Unrecognized command: " + str );
  86. }
  87. console.startAnimation();
  88. boolean merge = jEdit.getBooleanProperty("console.processrunner.mergeError", true);
  89. /* Yes, there is one more thread we created but do not "count" - otherwise it would be (merge ? 4 : 3)
  90. Console does not wait for the stdin stream/thread to be closed before considering the process
  91. "stopped". However, if the user does signal an EOF, that will still cause the stdin thread to
  92. terminate, and the count to decrease, which means that sometimes we may miss some trailing output
  93. from stdout or stderr (whichever stream is closed last). */
  94. threadDoneCount = merge ? 2 : 3;
  95. new Thread() {
  96. public void run() {
  97. try
  98. {
  99. exitCode = process.waitFor();
  100. showExit();
  101. // ConsoleProcess.this.stop();
  102. // console.getShell().printPrompt(console, output);
  103. threadDone();
  104. } catch (InterruptedException e)
  105. {
  106. exitCode = 1;
  107. Log.log(Log.ERROR, this, e);
  108. }
  109. }
  110. }.start();
  111. stdout = new StreamThread(this, process.getInputStream(), console.getPlainColor());
  112. stdout.start();
  113. if (merge)
  114. {
  115. stderr = null;
  116. }
  117. else
  118. {
  119. stderr = new StreamThread(this, process.getErrorStream(), console.getErrorColor());
  120. stderr.start();
  121. }
  122. stdin = new InputThread(this, process.getOutputStream());
  123. stdin.start();
  124. }
  125. catch (Exception ioe)
  126. {
  127. Log.log(Log.ERROR, ioe, "ConsoleProcess()");
  128. }
  129. } // }}}
  130. // {{{ methods
  131. // {{{ showExit method
  132. synchronized void showExit () {
  133. boolean showExitStatus = jEdit.getBooleanProperty("console.processrunner.showExitStatus", true);
  134. if (showExitStatus) {
  135. Object[] pp = { args[0], Integer.valueOf(exitCode) };
  136. String msg = jEdit.getProperty("console.shell.exited", pp);
  137. if (exitCode == 0)
  138. error.print(console.getInfoColor(), msg);
  139. else
  140. error.print(console.getErrorColor(), msg);
  141. }
  142. // console.getShell().printPrompt(console, output);
  143. } // }}}
  144. // {{{ detach() method
  145. void detach()
  146. {
  147. if (console != null)
  148. {
  149. Object[] pp = { args[0] };
  150. output.commandDone();
  151. if (error != null)
  152. {
  153. error.print(console.getErrorColor(),
  154. jEdit.getProperty("console.shell.detached", pp));
  155. error.commandDone();
  156. }
  157. }
  158. consoleState.setProcess(null);
  159. consoleState = null;
  160. console = null;
  161. } // }}}
  162. // {{{ stop() method
  163. synchronized void stop()
  164. {
  165. if (process != null)
  166. {
  167. if (stdin != null) stdin.abort();
  168. if (stdout != null) stdout.abort();
  169. if (stderr != null) stderr.abort();
  170. stopped = true;
  171. try
  172. {
  173. pipeOut.close();
  174. } catch (IOException e)
  175. {
  176. Log.log(Log.WARNING, this, e.getMessage());
  177. }
  178. try
  179. {
  180. process.destroy();
  181. output.commandDone();
  182. }
  183. catch (Exception e) {
  184. Log.log(Log.WARNING, this, e.getMessage());
  185. }
  186. process = null;
  187. if (console != null)
  188. {
  189. /* error.print(console.getErrorColor(), jEdit.getProperty(
  190. "console.shell.killed", pp)); */
  191. }
  192. }
  193. if (consoleState != null)
  194. consoleState.setProcess(null);
  195. // waitFor() might be waiting this.
  196. notifyAll();
  197. } // }}}
  198. // {{{ isRunning() method
  199. boolean isRunning()
  200. {
  201. if (process == null)
  202. return false;
  203. try
  204. {
  205. // should throw an exception of the thing is still running
  206. process.exitValue();
  207. }
  208. catch (IllegalThreadStateException itse)
  209. {
  210. return true;
  211. }
  212. return false;
  213. } // }}}
  214. // {{{ getExitStatus() method
  215. int getExitStatus()
  216. {
  217. return exitCode;
  218. } // }}}
  219. // {{{ getConsole() method
  220. Console getConsole()
  221. {
  222. return console;
  223. } // }}}
  224. // {{{ getOutput() method
  225. Output getOutput()
  226. {
  227. return output;
  228. } // }}}
  229. // {{{ getErrorOutput() method
  230. Output getErrorOutput()
  231. {
  232. return error;
  233. } // }}}
  234. // {{{ getCurrentDirectory() method
  235. String getCurrentDirectory()
  236. {
  237. return currentDirectory;
  238. } // }}}
  239. // {{{ getPipeInput() method
  240. public PipedInputStream getPipeInput()
  241. {
  242. return pipeIn;
  243. } // }}}
  244. // {{{ getArgs() method
  245. String[] getArgs() {
  246. return args;
  247. } // }}}
  248. // {{{ getPipeOutput() method
  249. public PipedOutputStream getPipeOutput()
  250. {
  251. return (process != null) ? pipeOut : null;
  252. } // }}}
  253. // {{{ waitFor() method
  254. /** @see Process.waitFor() */
  255. public synchronized int waitFor() throws InterruptedException
  256. {
  257. if (process != null)
  258. exitCode = process.waitFor();
  259. while (!stopped) {
  260. // wait for notifyAll() in stop().
  261. wait(100);
  262. }
  263. return exitCode;
  264. } // }}}
  265. // {{{ threadDone() method
  266. synchronized void threadDone()
  267. {
  268. threadDoneCount--;
  269. if (threadDoneCount > 0) return;
  270. if ((!stopped) && (process != null))
  271. {
  272. // we don't want unkillable processes to hang
  273. // jEdit
  274. stop();
  275. }
  276. SwingUtilities.invokeLater(new Runnable() {
  277. public void run() {
  278. jEdit.checkBufferStatus(console.getView());
  279. }
  280. });
  281. }
  282. // }}}
  283. // }}}
  284. } // }}}