001 package jigcell.compare.views;
002
003 import EDU.oswego.cs.dl.util.concurrent.SynchronousChannel;
004 import bsh.ConsoleInterface;
005 import bsh.EvalError;
006 import bsh.Interpreter;
007 import bsh.TargetError;
008 import java.awt.BorderLayout;
009 import java.awt.EventQueue;
010 import java.awt.event.ActionEvent;
011 import java.io.IOException;
012 import java.io.InputStreamReader;
013 import java.io.PipedInputStream;
014 import java.io.PipedOutputStream;
015 import java.io.PrintStream;
016 import java.io.Reader;
017 import javax.swing.JScrollPane;
018 import javax.swing.JTextArea;
019 import javax.swing.JTextField;
020 import jigcell.compare.impl.Compare;
021 import jigcell.compare.impl.ProxyBuilder;
022 import jigcell.compare.ui.PanelTab;
023
024 /**
025 * A simple debugging interface giving scripted access to the internals of the Comparator.
026 *
027 * <p>
028 * This code is licensed under the DARPA BioCOMP Open Source License. See LICENSE for more details.
029 * </p>
030 *
031 * @author Nicholas Allen
032 */
033
034 public final class Console extends PanelTab implements ConsoleInterface {
035
036 /**
037 * Variable to attach to Comparator
038 */
039
040 public final static String VARIABLE_COMPARE = "compare";
041
042 /**
043 * Size of the communication buffer
044 */
045
046 private final static int SIZE_READBUFFER = 4096;
047
048 /**
049 * Text display for evaluation output
050 */
051
052 private JTextArea output;
053
054 /**
055 * Text box for command input
056 */
057
058 private JTextField input;
059
060 /**
061 * Text printer
062 */
063
064 private PrintStream printer;
065
066 /**
067 * Data coming in through the printer
068 */
069
070 private Reader reader;
071
072 /**
073 * Channel for sending console input to the evaluator
074 */
075
076 private SynchronousChannel inputChannel;
077
078 /**
079 * Channel for sending output to the display
080 */
081
082 private SynchronousChannel outputChannel;
083
084 public Console (Compare compare, String configMarker) {
085 super (compare, configMarker);
086 }
087
088 public void error (Object text) {
089 printer.println (text);
090 }
091
092 public PrintStream getErr () {
093 return printer;
094 }
095
096 public Reader getIn () {
097 return null;
098 }
099
100 public PrintStream getOut () {
101 return printer;
102 }
103
104 public void print (Object text) {
105 printer.print (text);
106 }
107
108 public void println (Object text) {
109 printer.println (text);
110 }
111
112 /**
113 * {@inheritDoc}
114 */
115
116 protected void createUI () {
117 setLayout (new BorderLayout ());
118 output = new JTextArea ();
119 output.setEditable (false);
120 output.setLineWrap (true);
121 output.setTabSize (1);
122 add (new JScrollPane (output), BorderLayout.CENTER);
123 input = new JTextField ();
124 input.addActionListener (ProxyBuilder.proxyActionListener (this, "pumpInput"));
125 add (input, BorderLayout.SOUTH);
126 }
127
128 /**
129 * {@inheritDoc}
130 */
131
132 protected void initialize () {
133 super.initialize ();
134 inputChannel = new SynchronousChannel ();
135 new Thread (ProxyBuilder.proxyRunnable (this, "executeCommands")).start ();
136 PipedInputStream pipe = new PipedInputStream ();
137 try {
138 printer = new PrintStream (new PipedOutputStream (pipe), true);
139 } catch (IOException e) {
140 Compare.assertion (Compare.getString ("Console.outputInitializeError"), e);
141 }
142 reader = new InputStreamReader (pipe);
143 new Thread (ProxyBuilder.proxyRunnable (this, "pumpOutput")).start ();
144 }
145
146 /**
147 * Displays a line of output on the console.
148 */
149
150 private void displayOutput () {
151 try {
152 output.append ((String) outputChannel.take ());
153 } catch (Exception e) {
154 Compare.assertion (Compare.getString ("Console.outputDisplayError"), e);
155 }
156 }
157
158 /**
159 * Performs command evaluations off of the event thread.
160 */
161
162 private void executeCommands () {
163 Interpreter beanshell = new Interpreter (this);
164 try {
165 beanshell.set (VARIABLE_COMPARE, compare);
166 } catch (EvalError e) {
167 String message = Compare.getString ("Console.interpreterInitializeError");
168 error (message);
169 Compare.assertion (message, e);
170 }
171 while (true)
172 try {
173 println (beanshell.eval ((String) inputChannel.take ()));
174 } catch (TargetError e) {
175 error (e.getMessage ());
176 if (e.inNativeCode ()) {
177 Throwable t = e.getTarget ();
178 if (t != null)
179 t.printStackTrace (printer);
180 }
181 } catch (Exception e) {
182 error (e.getMessage ());
183 }
184 }
185
186 /**
187 * Runs a single command.
188 *
189 * @param e Event on the input field
190 */
191
192 private void pumpInput (ActionEvent e) {
193 if (e.getSource () != input)
194 return;
195 String text = input.getText ();
196 println (Compare.getString ("Console.prompt") + text);
197 try {
198 inputChannel.put (text);
199 } catch (Exception _e) {
200 Compare.assertion (Compare.getString ("Console.inputReadError"), _e);
201 }
202 input.setText ("");
203 }
204
205 /**
206 * Posts events to write text back to the console.
207 */
208
209 private void pumpOutput () {
210 outputChannel = new SynchronousChannel ();
211 char buffer [] = new char [SIZE_READBUFFER];
212 while (true)
213 try {
214 int read = reader.read (buffer);
215 if (read < 1)
216 continue;
217 EventQueue.invokeLater (ProxyBuilder.proxyRunnable (this, "displayOutput"));
218 outputChannel.put (new String (buffer, 0, read));
219 } catch (Exception e) {
220 Compare.assertion (Compare.getString ("Console.outputDisplayError"), e);
221 }
222 }
223 }