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    }