001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Copyright 2002 Jan Blok
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021:
022: package com.izforge.izpack.util;
023:
024: import java.awt.Dimension;
025: import java.awt.Font;
026: import java.awt.Toolkit;
027: import java.awt.event.KeyEvent;
028: import java.awt.event.KeyListener;
029: import java.io.BufferedOutputStream;
030: import java.io.BufferedReader;
031: import java.io.IOException;
032: import java.io.InputStream;
033: import java.io.InputStreamReader;
034: import java.io.OutputStreamWriter;
035: import java.io.PipedInputStream;
036: import java.io.PipedOutputStream;
037: import java.io.PrintStream;
038: import java.io.PrintWriter;
039: import java.util.Vector;
040:
041: import javax.swing.JFrame;
042: import javax.swing.JScrollPane;
043: import javax.swing.JTextArea;
044: import javax.swing.SwingUtilities;
045: import javax.swing.event.DocumentEvent;
046: import javax.swing.event.DocumentListener;
047: import javax.swing.text.Document;
048: import javax.swing.text.Segment;
049:
050: public final class Console {
051:
052: public static final int INITIAL_WIDTH = 800;
053:
054: public static final int INITIAL_HEIGHT = 600;
055:
056: public static void main(String[] args) {
057: Runtime rt = Runtime.getRuntime();
058: Process p = null;
059: try {
060:
061: /*
062: * Start a new process in which to execute the commands in cmd, using the environment in
063: * env and use pwd as the current working directory.
064: */
065: p = rt.exec(args);// , env, pwd);
066: new Console(p);
067: System.exit(p.exitValue());
068: } catch (IOException e) {
069: /*
070: * Couldn't even get the command to start. Most likely it couldn't be found because of a
071: * typo.
072: */
073: System.out.println("Error starting: " + args[0]);
074: System.out.println(e);
075: }
076: }
077:
078: private StdOut so;
079:
080: private StdOut se;
081:
082: public String getOutputData() {
083: if (so != null) {
084: return so.getData();
085: } else {
086: return "";
087: }
088: }
089:
090: public String getErrorData() {
091: if (se != null) {
092: return se.getData();
093: } else {
094: return "";
095: }
096: }
097:
098: public Console(Process p) {
099: JFrame frame = new JFrame();
100: frame.setTitle("Console");
101: Dimension screenSize = Toolkit.getDefaultToolkit()
102: .getScreenSize();
103: frame.setLocation(screenSize.width / 2 - INITIAL_WIDTH / 2,
104: screenSize.height / 2 - INITIAL_HEIGHT / 2);
105: ConsoleTextArea cta = new ConsoleTextArea();
106: JScrollPane scroll = new JScrollPane(cta);
107: scroll.setPreferredSize(new Dimension(INITIAL_WIDTH,
108: INITIAL_HEIGHT));
109: frame.getContentPane().add(scroll);
110: frame.pack();
111:
112: // From here down your shell should be pretty much
113: // as it is written here!
114: /*
115: * Start up StdOut, StdIn and StdErr threads that write the output generated by the process
116: * p to the screen, and feed the keyboard input into p.
117: */
118: so = new StdOut(p, cta);
119: se = new StdOut(p, cta);
120: StdIn si = new StdIn(p, cta);
121: so.start();
122: se.start();
123: si.start();
124:
125: // Wait for the process p to complete.
126: try {
127: frame.setVisible(true);
128: p.waitFor();
129: } catch (InterruptedException e) {
130: /*
131: * Something bad happened while the command was executing.
132: */
133: System.out.println("Error during execution");
134: System.out.println(e);
135: }
136:
137: /*
138: * Now signal the StdOut, StdErr and StdIn threads that the process is done, and wait for
139: * them to complete.
140: */
141: try {
142: so.done();
143: se.done();
144: si.done();
145: so.join();
146: se.join();
147: si.join();
148: } catch (InterruptedException e) {
149: // Something bad happend to one of the Std threads.
150: System.out.println("Error in StdOut, StdErr or StdIn.");
151: System.out.println(e);
152: }
153: frame.setVisible(false);
154: }
155: }
156:
157: class StdIn extends Thread {
158:
159: private BufferedReader kb;
160:
161: private boolean processRunning;
162:
163: private PrintWriter op;
164:
165: public StdIn(Process p, ConsoleTextArea cta) {
166: setDaemon(true);
167: InputStreamReader ir = new InputStreamReader(cta.getIn());
168: kb = new BufferedReader(ir);
169:
170: BufferedOutputStream os = new BufferedOutputStream(p
171: .getOutputStream());
172: op = new PrintWriter((new OutputStreamWriter(os)), true);
173: processRunning = true;
174: }
175:
176: public void run() {
177: try {
178: while (kb.ready() || processRunning) {
179: if (kb.ready()) {
180: op.println(kb.readLine());
181: }
182: }
183: } catch (IOException e) {
184: System.err.println("Problem reading standard input.");
185: System.err.println(e);
186: }
187: }
188:
189: public void done() {
190: processRunning = false;
191: }
192: }
193:
194: class StdOut extends Thread {
195:
196: private InputStreamReader output;
197:
198: private boolean processRunning;
199:
200: private ConsoleTextArea cta;
201:
202: private StringBuffer data;
203:
204: public StdOut(Process p, ConsoleTextArea cta) {
205: setDaemon(true);
206: output = new InputStreamReader(p.getInputStream());
207: this .cta = cta;
208: processRunning = true;
209: data = new StringBuffer();
210: }
211:
212: public void run() {
213: try {
214: /*
215: * Loop as long as there is output from the process to be displayed or as long as the
216: * process is still running even if there is presently no output.
217: */
218: while (output.ready() || processRunning) {
219:
220: // If there is output get it and display it.
221: if (output.ready()) {
222: char[] array = new char[255];
223: int num = output.read(array);
224: if (num != -1) {
225: String s = new String(array, 0, num);
226: data.append(s);
227: SwingUtilities.invokeAndWait(new ConsoleWrite(
228: cta, s));
229: }
230: }
231: }
232: } catch (Exception e) {
233: System.err.println("Problem writing to standard output.");
234: System.err.println(e);
235: }
236: }
237:
238: public void done() {
239: processRunning = false;
240: }
241:
242: public String getData() {
243: return data.toString();
244: }
245: }
246:
247: class ConsoleWrite implements Runnable {
248:
249: private ConsoleTextArea textArea;
250:
251: private String str;
252:
253: public ConsoleWrite(ConsoleTextArea textArea, String str) {
254: this .textArea = textArea;
255: this .str = str;
256: }
257:
258: public void run() {
259: textArea.write(str);
260: }
261: }
262:
263: class ConsoleWriter extends java.io.OutputStream {
264:
265: private ConsoleTextArea textArea;
266:
267: private StringBuffer buffer;
268:
269: public ConsoleWriter(ConsoleTextArea textArea) {
270: this .textArea = textArea;
271: buffer = new StringBuffer();
272: }
273:
274: public synchronized void write(int ch) {
275: buffer.append((char) ch);
276: if (ch == '\n') {
277: flushBuffer();
278: }
279: }
280:
281: public synchronized void write(char[] data, int off, int len) {
282: for (int i = off; i < len; i++) {
283: buffer.append(data[i]);
284: if (data[i] == '\n') {
285: flushBuffer();
286: }
287: }
288: }
289:
290: public synchronized void flush() {
291: if (buffer.length() > 0) {
292: flushBuffer();
293: }
294: }
295:
296: public void close() {
297: flush();
298: }
299:
300: private void flushBuffer() {
301: String str = buffer.toString();
302: buffer.setLength(0);
303: SwingUtilities.invokeLater(new ConsoleWrite(textArea, str));
304: }
305: }
306:
307: class ConsoleTextArea extends JTextArea implements KeyListener,
308: DocumentListener {
309:
310: /**
311: *
312: */
313: private static final long serialVersionUID = 3258410625414475827L;
314:
315: private ConsoleWriter console1;
316:
317: private PrintStream out;
318:
319: private PrintStream err;
320:
321: private PrintWriter inPipe;
322:
323: private PipedInputStream in;
324:
325: private Vector<String> history;
326:
327: private int historyIndex = -1;
328:
329: private int outputMark = 0;
330:
331: public void select(int start, int end) {
332: requestFocus();
333: super .select(start, end);
334: }
335:
336: public ConsoleTextArea() {
337: super ();
338: history = new java.util.Vector<String>();
339: console1 = new ConsoleWriter(this );
340: ConsoleWriter console2 = new ConsoleWriter(this );
341: out = new PrintStream(console1);
342: err = new PrintStream(console2);
343: PipedOutputStream outPipe = new PipedOutputStream();
344: inPipe = new PrintWriter(outPipe);
345: in = new PipedInputStream();
346: try {
347: outPipe.connect(in);
348: } catch (IOException exc) {
349: exc.printStackTrace();
350: }
351: getDocument().addDocumentListener(this );
352: addKeyListener(this );
353: setLineWrap(true);
354: setFont(new Font("Monospaced", 0, 12));
355: }
356:
357: void returnPressed() {
358: Document doc = getDocument();
359: int len = doc.getLength();
360: Segment segment = new Segment();
361: try {
362: synchronized (doc) {
363: doc.getText(outputMark, len - outputMark, segment);
364: }
365: } catch (javax.swing.text.BadLocationException ignored) {
366: ignored.printStackTrace();
367: }
368: if (segment.count > 0) {
369: history.addElement(segment.toString());
370: }
371: historyIndex = history.size();
372: inPipe.write(segment.array, segment.offset, segment.count);
373: append("\n");
374: synchronized (doc) {
375: outputMark = doc.getLength();
376: }
377: inPipe.write("\n");
378: inPipe.flush();
379: console1.flush();
380: }
381:
382: public void eval(String str) {
383: inPipe.write(str);
384: inPipe.write("\n");
385: inPipe.flush();
386: console1.flush();
387: }
388:
389: public void keyPressed(KeyEvent e) {
390: int code = e.getKeyCode();
391: if (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_LEFT) {
392: if (outputMark == getCaretPosition()) {
393: e.consume();
394: }
395: } else if (code == KeyEvent.VK_HOME) {
396: int caretPos = getCaretPosition();
397: if (caretPos == outputMark) {
398: e.consume();
399: } else if (caretPos > outputMark) {
400: if (!e.isControlDown()) {
401: if (e.isShiftDown()) {
402: moveCaretPosition(outputMark);
403: } else {
404: setCaretPosition(outputMark);
405: }
406: e.consume();
407: }
408: }
409: } else if (code == KeyEvent.VK_ENTER) {
410: returnPressed();
411: e.consume();
412: } else if (code == KeyEvent.VK_UP) {
413: historyIndex--;
414: if (historyIndex >= 0) {
415: if (historyIndex >= history.size()) {
416: historyIndex = history.size() - 1;
417: }
418: if (historyIndex >= 0) {
419: String str = history.elementAt(historyIndex);
420: int len = getDocument().getLength();
421: replaceRange(str, outputMark, len);
422: int caretPos = outputMark + str.length();
423: select(caretPos, caretPos);
424: } else {
425: historyIndex++;
426: }
427: } else {
428: historyIndex++;
429: }
430: e.consume();
431: } else if (code == KeyEvent.VK_DOWN) {
432: int caretPos = outputMark;
433: if (history.size() > 0) {
434: historyIndex++;
435: if (historyIndex < 0) {
436: historyIndex = 0;
437: }
438: int len = getDocument().getLength();
439: if (historyIndex < history.size()) {
440: String str = history.elementAt(historyIndex);
441: replaceRange(str, outputMark, len);
442: caretPos = outputMark + str.length();
443: } else {
444: historyIndex = history.size();
445: replaceRange("", outputMark, len);
446: }
447: }
448: select(caretPos, caretPos);
449: e.consume();
450: }
451: }
452:
453: public void keyTyped(KeyEvent e) {
454: int keyChar = e.getKeyChar();
455: if (keyChar == 0x8 /* KeyEvent.VK_BACK_SPACE */) {
456: if (outputMark == getCaretPosition()) {
457: e.consume();
458: }
459: } else if (getCaretPosition() < outputMark) {
460: setCaretPosition(outputMark);
461: }
462: }
463:
464: public void keyReleased(KeyEvent e) {
465: }
466:
467: public synchronized void write(String str) {
468: insert(str, outputMark);
469: int len = str.length();
470: outputMark += len;
471: select(outputMark, outputMark);
472: }
473:
474: public synchronized void insertUpdate(DocumentEvent e) {
475: int len = e.getLength();
476: int off = e.getOffset();
477: if (outputMark > off) {
478: outputMark += len;
479: }
480: }
481:
482: public synchronized void removeUpdate(DocumentEvent e) {
483: int len = e.getLength();
484: int off = e.getOffset();
485: if (outputMark > off) {
486: if (outputMark >= off + len) {
487: outputMark -= len;
488: } else {
489: outputMark = off;
490: }
491: }
492: }
493:
494: public void postUpdateUI() {
495: // this attempts to cleanup the damage done by updateComponentTreeUI
496: requestFocus();
497: setCaret(getCaret());
498: synchronized (this ) {
499: select(outputMark, outputMark);
500: }
501: }
502:
503: public void changedUpdate(DocumentEvent e) {
504: }
505:
506: public InputStream getIn() {
507: return in;
508: }
509:
510: public PrintStream getOut() {
511: return out;
512: }
513:
514: public PrintStream getErr() {
515: return err;
516: }
517:
518: }
|