001: /*
002: * AsynchronousShellCommand.java
003: *
004: * Copyright (C) 2000-2002 Peter Graves
005: * $Id: AsynchronousShellCommand.java,v 1.4 2003/04/04 14:03:04 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.util.List;
027: import javax.swing.SwingUtilities;
028:
029: public final class AsynchronousShellCommand implements Constants,
030: Runnable {
031: private final String command;
032: private final File directory;
033: private final String cmdline;
034: private final ShellCommandOutputBuffer outputBuffer;
035: private final Position posEndOfBuffer;
036:
037: private Process process;
038: private Thread thread;
039: private ProcessTable processTable;
040:
041: public AsynchronousShellCommand(String command, File directory,
042: ShellCommandOutputBuffer buf) {
043: this .command = command;
044: this .directory = directory;
045: cmdline = "(\\cd " + directory.canonicalPath() + " && "
046: + command + ")";
047: this .outputBuffer = buf;
048: this .posEndOfBuffer = new Position(buf.getFirstLine(), 0);
049: buf.setShellCommand(this );
050: }
051:
052: private void start() {
053: thread = new Thread(this );
054: thread.start();
055: }
056:
057: public void run() {
058: if (!Platform.isPlatformUnix()) {
059: Debug.bug();
060: return;
061: }
062: try {
063: if (cmdline != null) {
064: String[] cmdarray = { "/bin/sh", "-c", cmdline };
065: process = Runtime.getRuntime().exec(cmdarray);
066: }
067: } catch (IOException e) {
068: Log.error(e);
069: }
070: if (process != null) {
071: ShellCommandReaderThread stdoutThread = new ShellCommandReaderThread(
072: process.getInputStream());
073: stdoutThread.start();
074: ShellCommandReaderThread stderrThread = new ShellCommandReaderThread(
075: process.getErrorStream());
076: stderrThread.start();
077: processTable = ProcessTable.getProcessTable();
078: try {
079: process.waitFor();
080: } catch (InterruptedException e) {
081: // User has closed the output buffer.
082: killProcess();
083: }
084: }
085: }
086:
087: private void interrupt() {
088: if (thread != null)
089: thread.interrupt();
090: }
091:
092: private void killProcess() {
093: if (processTable != null) {
094: List entries = processTable.findMatchingEntries(cmdline);
095: if (entries != null && entries.size() > 0) {
096: // We want the last matching entry.
097: ProcessTableEntry parent = (ProcessTableEntry) entries
098: .get(entries.size() - 1);
099: if (parent != null) {
100: List children = processTable
101: .findChildren(parent.pid);
102: if (children != null) {
103: for (int i = 0; i < children.size(); i++) {
104: ProcessTableEntry entry = (ProcessTableEntry) children
105: .get(i);
106: Utilities.kill(entry.pid);
107: }
108: }
109: }
110: }
111: try {
112: process.waitFor();
113: } catch (InterruptedException e) {
114: Log.debug(e);
115: }
116: }
117: }
118:
119: private void appendLater(final String s) {
120: Runnable runnable = new Runnable() {
121: public void run() {
122: outputBuffer.insertString(posEndOfBuffer, s);
123: if (outputBuffer.needsRenumbering())
124: outputBuffer.renumber();
125: outputBuffer
126: .enforceOutputLimit(Property.SHELL_OUTPUT_LIMIT);
127: for (EditorIterator it = new EditorIterator(); it
128: .hasNext();) {
129: Editor ed = it.nextEditor();
130: if (ed.getBuffer() == outputBuffer) {
131: ed.eob();
132: ed.getDisplay().setReframe(-2);
133: ed.setUpdateFlag(REPAINT);
134: ed.updateDisplay();
135: }
136: }
137: }
138: };
139: SwingUtilities.invokeLater(runnable);
140: }
141:
142: private class ShellCommandReaderThread extends ReaderThread {
143: public ShellCommandReaderThread(InputStream inputStream) {
144: super (inputStream);
145: }
146:
147: public void update(final String s) {
148: appendLater(s);
149: }
150: }
151:
152: private static class ShellCommandOutputBuffer extends Buffer {
153: private AsynchronousShellCommand shellCommand;
154:
155: public ShellCommandOutputBuffer() {
156: supportsUndo = false;
157: type = TYPE_OUTPUT;
158: mode = PlainTextMode.getMode();
159: formatter = new PlainTextFormatter(this );
160: lineSeparator = System.getProperty("line.separator");
161: readOnly = true;
162: setTransient(true);
163: setProperty(Property.VERTICAL_RULE, 0);
164: setProperty(Property.SHOW_CHANGE_MARKS, false);
165: setProperty(Property.SHOW_LINE_NUMBERS, false);
166: setProperty(Property.HIGHLIGHT_MATCHING_BRACKET, false);
167: setProperty(Property.HIGHLIGHT_BRACKETS, false);
168: try {
169: lockWrite();
170: } catch (InterruptedException e) {
171: Log.debug(e);
172: return;
173: }
174: try {
175: appendLine("");
176: renumber();
177: } finally {
178: unlockWrite();
179: }
180: setInitialized(true);
181: }
182:
183: public void setShellCommand(
184: AsynchronousShellCommand shellCommand) {
185: this .shellCommand = shellCommand;
186: }
187:
188: public int load() {
189: return LOAD_COMPLETED;
190: }
191:
192: public String getFileNameForDisplay() {
193: return title != null ? title : "";
194: }
195:
196: public boolean isModified() {
197: return false;
198: }
199:
200: public void dispose() {
201: if (shellCommand != null)
202: shellCommand.interrupt();
203: }
204: }
205:
206: public static void startShellCommand(Editor editor, String command) {
207: final File dir = editor.getCurrentDirectory();
208: if (dir == null || !dir.isDirectory())
209: return;
210: ShellCommandOutputBuffer buf = new ShellCommandOutputBuffer();
211: buf.setTitle(command);
212: editor.makeNext(buf);
213: editor.activateInOtherWindow(buf);
214: AsynchronousShellCommand shellCommand = new AsynchronousShellCommand(
215: command, dir, buf);
216: shellCommand.start();
217: }
218: }
|