PageRenderTime 87ms CodeModel.GetById 62ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

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

#
Java | 325 lines | 215 code | 41 blank | 69 comment | 33 complexity | 09f06e53d398ead6210d549fea4bb747 MD5 | raw file
  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
 24package console;
 25
 26// {{{ Imports
 27import java.util.Map;
 28import java.io.IOException;
 29import java.io.PipedInputStream;
 30import java.io.PipedOutputStream;
 31
 32import javax.swing.SwingUtilities;
 33
 34import org.gjt.sp.jedit.jEdit;
 35import org.gjt.sp.util.Log;
 36import org.gjt.sp.util.StringList;
 37
 38// }}}
 39
 40// {{{ ConsoleProcess class
 41class ConsoleProcess
 42{
 43	// {{{ Data members
 44	/** The running subprocess */
 45	Process process;
 46	private SystemShell.ConsoleState consoleState;
 47	private String currentDirectory;
 48	private Console console;
 49	private Output output;
 50	private Output error;
 51	private String[] args;
 52	// {{{ Threads for handling the streams of running subprocesses
 53	private InputThread stdin;
 54	private StreamThread stdout;
 55	private StreamThread stderr;
 56	// }}}
 57	private int threadDoneCount = 0;
 58	private int exitCode = 834;
 59	private boolean stopped;
 60
 61	/*
 62	 * AWT thread writes stdin to this pipe, and the input thread writes it to
 63	 * the process.
 64	 */
 65	private PipedInputStream pipeIn;
 66
 67	private PipedOutputStream pipeOut;
 68	// }}}
 69
 70	// {{{ ConsoleProcess constructor
 71	ConsoleProcess(final Console console, final Output output, final String[] args,
 72			Map<String, String> env,  SystemShell.ConsoleState consoleState,
 73			boolean foreground)
 74	{
 75		this.args = args;
 76		this.currentDirectory = consoleState.currentDirectory;
 77		this.console = console;
 78
 79		if (foreground)
 80		{
 81			this.output = output;
 82			this.error = new ErrorOutput(console);
 83			this.consoleState = consoleState;
 84		}
 85
 86		try
 87		{
 88			// Streams for getting user input
 89			pipeIn = new PipedInputStream();
 90			pipeOut = new PipedOutputStream(pipeIn);
 91			process = ProcessRunner.getProcessRunner().exec(args, env,
 92					currentDirectory);
 93			if (process == null)
 94			{
 95				String str = StringList.join(args, " ");
 96				throw new RuntimeException( "Unrecognized command: " + str );
 97			}
 98			console.startAnimation();
 99			boolean merge = jEdit.getBooleanProperty("console.processrunner.mergeError", true);
100			/* Yes, there is one more thread we created but do not "count" - otherwise it would be (merge ? 4 : 3) 
101			   Console does not wait for the stdin stream/thread to be closed before considering the process
102			   "stopped". However, if the user does signal an EOF, that will still cause the stdin thread to
103			   terminate, and the count to decrease, which means that sometimes we may miss some trailing output
104			   from stdout or stderr (whichever stream is closed last). */
105			threadDoneCount = merge ? 2 : 3;
106			new Thread() {
107				public void run() {
108					try
109					{
110						exitCode = process.waitFor();
111						showExit();
112						// ConsoleProcess.this.stop();
113						// console.getShell().printPrompt(console, output);
114						threadDone();
115					} catch (InterruptedException e)
116					{
117						exitCode = 1;
118						Log.log(Log.ERROR, this, e);
119					}
120				}
121			}.start();
122
123
124			stdout = new StreamThread(this, process.getInputStream(), console.getPlainColor());
125			stdout.start();
126			if (merge)
127			{
128				stderr = null;
129			}
130			else
131			{
132				stderr = new StreamThread(this, process.getErrorStream(), console.getErrorColor());
133				stderr.start();
134			}
135
136			
137			stdin = new InputThread(this, process.getOutputStream());
138			stdin.start();
139
140		}
141		catch (Exception ioe)
142		{
143			Log.log(Log.ERROR, ioe, "ConsoleProcess()");
144		}
145
146	} // }}}
147
148	// {{{ methods
149	// {{{ showExit method
150	synchronized void showExit () {
151		boolean showExitStatus = jEdit.getBooleanProperty("console.processrunner.showExitStatus", true);
152		if (showExitStatus) {
153			Object[] pp = { args[0], Integer.valueOf(exitCode) };
154			String msg = jEdit.getProperty("console.shell.exited", pp);
155			if (exitCode == 0)
156				error.print(console.getInfoColor(), msg);
157			else
158				error.print(console.getErrorColor(), msg);
159		}
160
161		// console.getShell().printPrompt(console, output);
162	} // }}}
163
164	// {{{ detach() method
165	void detach()
166	{
167		if (console != null)
168		{
169			Object[] pp = { args[0] };
170			output.commandDone();
171			if (error != null)
172			{
173				error.print(console.getErrorColor(),
174					jEdit.getProperty("console.shell.detached", pp));
175				error.commandDone();
176			}
177		}
178
179		consoleState.setProcess(null);
180		consoleState = null;
181		console = null;
182	} // }}}
183
184	// {{{ stop() method
185	synchronized void stop()
186	{
187
188		if (process != null)
189		{
190			if (stdin != null) stdin.abort();
191			if (stdout != null) stdout.abort();
192			if (stderr != null) stderr.abort();
193			stopped = true;
194			try
195			{
196				pipeOut.close();
197			} catch (IOException e)
198			{
199				Log.log(Log.WARNING, this, e.getMessage());
200			}
201
202			try
203			{
204				process.destroy();
205				output.commandDone();
206			}
207			catch (Exception e) {
208				Log.log(Log.WARNING, this, e.getMessage());
209			}
210			process = null;
211			
212			if (console != null)
213			{
214/*				error.print(console.getErrorColor(), jEdit.getProperty(
215						"console.shell.killed", pp)); */
216			}
217		}
218
219		if (consoleState != null)
220			consoleState.setProcess(null);
221
222		// waitFor() might be waiting this.
223		notifyAll();
224	} // }}}
225
226	// {{{ isRunning() method
227	boolean isRunning()
228	{
229		if (process == null)
230			return false;
231		try
232		{
233			// should throw an exception of the thing is still running
234			process.exitValue();
235		}
236		catch (IllegalThreadStateException itse)
237		{
238			return true;
239		}
240		return false;
241	} // }}}
242
243	// {{{ getExitStatus() method
244	int getExitStatus()
245	{
246		return exitCode;
247	} // }}}
248
249	// {{{ getConsole() method
250	Console getConsole()
251	{
252		return console;
253	} // }}}
254
255	// {{{ getOutput() method
256	Output getOutput()
257	{
258		return output;
259	} // }}}
260
261	// {{{ getErrorOutput() method
262	Output getErrorOutput()
263	{
264		return error;
265	} // }}}
266
267	// {{{ getCurrentDirectory() method
268	String getCurrentDirectory()
269	{
270		return currentDirectory;
271	} // }}}
272
273	// {{{ getPipeInput() method
274	public PipedInputStream getPipeInput()
275	{
276		return pipeIn;
277	} // }}}
278
279	// {{{ getArgs() method
280	String[] getArgs() {
281		return args;
282	} // }}}
283
284	// {{{ getPipeOutput() method
285	public PipedOutputStream getPipeOutput()
286	{
287		return (process != null) ? pipeOut : null;
288	} // }}}
289
290	// {{{ waitFor() method
291	/** @see Process.waitFor() */
292	public synchronized int waitFor() throws InterruptedException
293	{
294		if (process != null) 
295			exitCode = process.waitFor();
296		while (!stopped) {
297			// wait for notifyAll() in stop().
298			wait(100);
299		}
300		return exitCode;
301	} // }}}
302
303	// {{{ threadDone() method
304	synchronized void threadDone()
305	{
306
307		threadDoneCount--;
308                if (threadDoneCount > 0) return;
309
310                if ((!stopped) && (process != null))
311		{
312
313			// we don't want unkillable processes to hang
314			// jEdit
315			stop();
316		}
317		SwingUtilities.invokeLater(new Runnable() {
318			public void run() {
319				jEdit.checkBufferStatus(console.getView());				
320			}
321		});
322	}
323	// }}}
324	// }}}
325} // }}}