KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > model > repl > InteractionsModel


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32 END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.model.repl;
35
36 import java.io.*;
37 import java.net.ServerSocket JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.net.URL JavaDoc;
41
42 import edu.rice.cs.drjava.CodeStatus;
43 import edu.rice.cs.util.FileOpenSelector;
44 import edu.rice.cs.util.OperationCanceledException;
45 import edu.rice.cs.util.*;
46 import edu.rice.cs.util.swing.Utilities;
47 import edu.rice.cs.util.text.EditDocumentInterface;
48 import edu.rice.cs.util.text.ConsoleDocument;
49 import edu.rice.cs.util.text.EditDocumentException;
50
51 /** A model which can serve as the glue between an InteractionsDocument and a JavaInterpreter. This
52  * abstract class provides common functionality for all such models.
53  * @version $Id: InteractionsModel.java 4057 2007-01-16 00:06:10Z dlsmith $
54  */

55 public abstract class InteractionsModel implements InteractionsModelCallback {
56   
57   /** Banner prefix. */
58   public static final String JavaDoc BANNER_PREFIX = "Welcome to DrJava.";
59   
60   /** Keeps track of any listeners to the model. */
61   protected final InteractionsEventNotifier _notifier = new InteractionsEventNotifier();
62
63   /** System-dependent newline string. */
64   protected static final String JavaDoc _newLine = System.getProperty("line.separator");
65
66   /** InteractionsDocument containing the commands and history. */
67   protected final InteractionsDocument _document;
68
69   /** Whether we are waiting for the interpreter to register for the first time. */
70   protected volatile boolean _waitingForFirstInterpreter;
71
72   /** The working directory for the current interpreter. */
73   protected volatile File _workingDirectory;
74
75   /** A lock object to prevent multiple threads from interpreting at once. */
76   private final Object JavaDoc _interpreterLock;
77
78   /** A lock object to prevent print calls to System.out or System.err from flooding
79    * the JVM, ensuring the UI remains responsive. */

80   private final Object JavaDoc _writerLock;
81
82   /** Number of milliseconds to wait after each println, to prevent the JVM from being flooded with print calls. */
83   private final int _writeDelay;
84
85   /** Port used by the debugger to connect to the Interactions JVM. Uniquely created in getDebugPort(). */
86   private volatile int _debugPort;
87
88   /** Whether the debug port has already been set. If not, calling getDebugPort will generate an available port. */
89   private volatile boolean _debugPortSet;
90   
91   /** The String added to history when the interaction is complete or an error is thrown */
92   private volatile String JavaDoc _toAddToHistory = "";
93
94   /** The input listener to listen for requests to System.in. */
95   protected volatile InputListener _inputListener;
96
97   protected final EditDocumentInterface _adapter;
98   
99   /** Banner displayed at top of the interactions document */
100   private volatile String JavaDoc _banner;
101   
102   /** Constructs an InteractionsModel.
103    * @param adapter DocumentAdapter to use in the InteractionsDocument
104    * @param wd Working directory for the interpreter
105    * @param historySize Number of lines to store in the history
106    * @param writeDelay Number of milliseconds to wait after each println
107    */

108   public InteractionsModel(EditDocumentInterface adapter, File wd, int historySize, int writeDelay) {
109     _writeDelay = writeDelay;
110     _document = new InteractionsDocument(adapter, historySize, getBanner(wd));
111     _adapter = adapter;
112     _waitingForFirstInterpreter = true;
113     _workingDirectory = wd;
114     _interpreterLock = new Object JavaDoc();
115     _writerLock = new Object JavaDoc();
116     _debugPort = -1;
117     _debugPortSet = false;
118     _inputListener = NoInputListener.ONLY;
119   }
120
121   /** Add a JavadocListener to the model.
122    * @param listener a listener that reacts to Interactions events */

123   public void addListener(InteractionsListener listener) { _notifier.addListener(listener); }
124
125   /** Remove an InteractionsListener from the model. If the listener is not currently listening to this model, this
126    * method has no effect.
127    * @param listener a listener that reacts to Interactions events
128    */

129   public void removeListener(InteractionsListener listener) { _notifier.removeListener(listener); }
130
131   /** Removes all InteractionsListeners from this model. */
132   public void removeAllInteractionListeners() { _notifier.removeAllListeners(); }
133
134   /** Returns the InteractionsDocument stored by this model. */
135   public InteractionsDocument getDocument() { return _document; }
136
137   public void interactionContinues() {
138     _document.setInProgress(false);
139     _notifyInteractionEnded();
140     _notifyInteractionIncomplete();
141   }
142   
143   /** Sets this model's notion of whether it is waiting for the first interpreter to connect. The interactionsReady
144    * event is not fired for the first interpreter.
145    */

146   public void setWaitingForFirstInterpreter(boolean waiting) { _waitingForFirstInterpreter = waiting; }
147
148   /** Interprets the current given text at the prompt in the interactions doc. */
149   public void interpretCurrentInteraction() {
150     synchronized(_interpreterLock) {
151       // Don't start a new interaction while one is in progress
152
if (_document.inProgress()) return;
153       
154       String JavaDoc text = _document.getCurrentInteraction();
155       String JavaDoc toEval = text.trim();
156       if (toEval.startsWith("java ")) toEval = _testClassCall(toEval);
157
158       _prepareToInterpret(text);
159       interpret(toEval);
160     }
161   }
162
163   /** Performs pre-interpretation preparation of the interactions document and notifies the view. */
164   private void _prepareToInterpret(String JavaDoc text) {
165     addNewLine();
166     _notifyInteractionStarted();
167     _document.setInProgress(true);
168     _toAddToHistory = text; // _document.addToHistory(text);
169
//Do not add to history immediately in case the user is not finished typing when they press return
170
}
171   
172   public void addNewLine() { append(_newLine, InteractionsDocument.DEFAULT_STYLE); }
173
174   /** Interprets the given command.
175    * @param toEval command to be evaluated. */

176   public final void interpret(String JavaDoc toEval) {
177     synchronized(_interpreterLock) { _interpret(toEval); }
178   }
179
180   /** Interprets the given command. This should only be called from interpret, never directly.
181    * @param toEval command to be evaluated
182    */

183   protected abstract void _interpret(String JavaDoc toEval);
184
185   /** Notifies the view that the current interaction is incomplete. */
186   protected abstract void _notifyInteractionIncomplete();
187
188   /** Notifies listeners that an interaction has started. (Subclasses must maintain listeners.) */
189   protected abstract void _notifyInteractionStarted();
190
191   /** Gets the string representation of the value of a variable in the current interpreter.
192    * @param var the name of the variable
193    */

194   public abstract String JavaDoc getVariableToString(String JavaDoc var);
195
196   /** Gets the class name of a variable in the current interpreter.
197    * @param var the name of the variable
198    */

199   public abstract String JavaDoc getVariableClassName(String JavaDoc var);
200
201   /** Resets the Java interpreter with working directry wd. */
202   public final void resetInterpreter(File wd) {
203     _workingDirectory = wd;
204     _resetInterpreter(wd);
205   }
206
207   /** Resets the Java interpreter. This should only be called from resetInterpreter, never directly. */
208   protected abstract void _resetInterpreter(File wd);
209   
210   /** Returns the working directory for the current interpreter. */
211   public File getWorkingDirectory() { return _workingDirectory; }
212
213   /** These add the given path to the classpaths used in the interpreter.
214    * @param path Path to add
215    */

216   public abstract void addProjectClassPath(URL JavaDoc path);
217   public abstract void addBuildDirectoryClassPath(URL JavaDoc path);
218   public abstract void addProjectFilesClassPath(URL JavaDoc path);
219   public abstract void addExternalFilesClassPath(URL JavaDoc path);
220   public abstract void addExtraClassPath(URL JavaDoc path);
221  
222   /** Handles a syntax error being returned from an interaction
223    * @param offset the first character of the error in the InteractionsDocument
224    * @param length the length of the error.
225    */

226   protected abstract void _notifySyntaxErrorOccurred(int offset, int length);
227
228   /** Opens the files chosen in the given file selector, and returns an ArrayList with one history string
229    * for each selected file.
230    * @param selector A file selector supporting multiple file selection
231    * @return a list of histories (one for each selected file)
232    */

233   protected ArrayList JavaDoc<String JavaDoc> _getHistoryText(FileOpenSelector selector)
234     throws IOException, OperationCanceledException {
235     File[] files = selector.getFiles();
236     if (files == null) throw new IOException("No Files returned from FileSelector");
237     
238     ArrayList JavaDoc<String JavaDoc> histories = new ArrayList JavaDoc<String JavaDoc>();
239     ArrayList JavaDoc<String JavaDoc> strings = new ArrayList JavaDoc<String JavaDoc>();
240     
241     for (File f: files) {
242       if (f == null) throw new IOException("File name returned from FileSelector is null");
243       try {
244         FileInputStream fis = new FileInputStream(f);
245         InputStreamReader isr = new InputStreamReader(fis);
246         BufferedReader br = new BufferedReader(isr);
247         while (true) {
248           String JavaDoc line = br.readLine();
249           if (line == null) break;
250           strings.add(line);
251         }
252         br.close(); // win32 needs readers closed explicitly!
253
}
254       catch (IOException ioe) { throw new IOException("File name returned from FileSelector is null"); }
255     
256       // Create a single string with all formatted lines from this history
257
final StringBuilder JavaDoc text = new StringBuilder JavaDoc();
258       boolean firstLine = true;
259       int formatVersion = 1;
260       for (String JavaDoc s: strings) {
261         int sl = s.length();
262         if (sl > 0) {
263           
264           // check for format version string. NOTE: the original file format did not have a version string
265
if (firstLine && (s.trim().equals(History.HISTORY_FORMAT_VERSION_2.trim()))) formatVersion = 2;
266           
267           switch (formatVersion) {
268             case (1):
269               // When reading this format, we need to make sure each line ends in a semicolon.
270
// This behavior can be buggy; that's why the format was changed.
271
text.append(s);
272               if (s.charAt(sl - 1) != ';') text.append(';');
273               text.append(_newLine);
274               break;
275             case (2):
276               if (!firstLine) text.append(s).append(_newLine); // omit version string from output
277
break;
278           }
279           firstLine = false;
280         }
281       }
282       
283       // Add the entire formatted text to the list of histories
284
histories.add(text.toString());
285     }
286     return histories;
287   }
288
289   /** Removes the interaction-separator comments from a history, so that they will not appear when executing
290    * the history.
291    * @param text The full, formatted text of an interactions history (obtained from _getHistoryText)
292    * @return A list of strings representing each interaction in the history. If no separators are present,
293    * the entire history is treated as one interaction.
294    */

295   protected ArrayList JavaDoc<String JavaDoc> _removeSeparators(String JavaDoc text) {
296     String JavaDoc sep = History.INTERACTION_SEPARATOR;
297     int len = sep.length();
298     ArrayList JavaDoc<String JavaDoc> interactions = new ArrayList JavaDoc<String JavaDoc>();
299
300     // Loop while there are still separators, adding the text between separators
301
// as separate elements to the interactions list
302
int index = text.indexOf(sep);
303     int lastIndex = 0;
304     while (index != -1) {
305       interactions.add(text.substring(lastIndex, index).trim());
306       lastIndex = index + len;
307       index = text.indexOf(sep, lastIndex);
308     }
309
310     // get last interaction
311
String JavaDoc last = text.substring(lastIndex, text.length()).trim();
312     if (!"".equals(last)) interactions.add(last);
313     return interactions;
314   }
315
316   /** Interprets the files selected in the FileOpenSelector. Assumes all strings have no trailing whitespace.
317    * Interprets the array all at once so if there are any errors, none of the statements after the first
318    * erroneous one are processed.
319    */

320   public void loadHistory(FileOpenSelector selector) throws IOException {
321     ArrayList JavaDoc<String JavaDoc> histories;
322     try { histories = _getHistoryText(selector); }
323     catch (OperationCanceledException oce) { return; }
324     _document.clearCurrentInteraction();
325
326     // Insert into the document and interpret
327
final StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
328     for (String JavaDoc hist: histories) {
329       ArrayList JavaDoc<String JavaDoc> interactions = _removeSeparators(hist);
330       for (String JavaDoc curr: interactions) {
331         int len = curr.length();
332         buf.append(curr);
333         if (len > 0 && curr.charAt(len - 1) != ';') buf.append(';');
334         buf.append(_newLine);
335       }
336     }
337     append(buf.toString().trim(), InteractionsDocument.DEFAULT_STYLE);
338     interpretCurrentInteraction();
339   }
340
341   /* Loads the contents of the specified file(s) into the histories buffer. */
342   public InteractionsScriptModel loadHistoryAsScript(FileOpenSelector selector)
343     throws IOException, OperationCanceledException {
344     ArrayList JavaDoc<String JavaDoc> histories = _getHistoryText(selector);
345     ArrayList JavaDoc<String JavaDoc> interactions = new ArrayList JavaDoc<String JavaDoc>();
346     for (String JavaDoc hist: histories) interactions.addAll(_removeSeparators(hist));
347     return new InteractionsScriptModel(this, interactions);
348   }
349
350   /** Returns the port number to use for debugging the interactions JVM. Generates an available port if one has
351    * not been set manually.
352    * @throws IOException if unable to get a valid port number.
353    */

354   public int getDebugPort() throws IOException {
355     if (!_debugPortSet) _createNewDebugPort();
356     return _debugPort;
357   }
358
359   /** Generates an available port for use with the debugger.
360    * @throws IOException if unable to get a valid port number.
361    */

362   protected void _createNewDebugPort() throws IOException {
363 // Utilities.showDebug("InteractionsModel: _createNewDebugPort() called");
364
try {
365       ServerSocket JavaDoc socket = new ServerSocket JavaDoc(0);
366       _debugPort = socket.getLocalPort();
367       socket.close();
368     }
369     catch (java.net.SocketException JavaDoc se) {
370       // something wrong with sockets, can't use for debugger
371
_debugPort = -1;
372     }
373     _debugPortSet = true;
374     if (CodeStatus.DEVELOPMENT) {
375       System.setProperty("drjava.debug.port", String.valueOf(_debugPort));
376     }
377   }
378
379   /** Sets the port number to use for debugging the interactions JVM.
380    * @param port Port to use to debug the interactions JVM
381    */

382   public void setDebugPort(int port) {
383     _debugPort = port;
384     _debugPortSet = true;
385   }
386
387   /** Called when the repl prints to System.out.
388    * @param s String to print
389    */

390   public void replSystemOutPrint(String JavaDoc s) {
391     _document.insertBeforeLastPrompt(s, InteractionsDocument.SYSTEM_OUT_STYLE);
392   }
393
394   /** Called when the repl prints to System.err.
395    * @param s String to print
396    */

397   public void replSystemErrPrint(String JavaDoc s) {
398     _document.insertBeforeLastPrompt(s, InteractionsDocument.SYSTEM_ERR_STYLE);
399   }
400
401   /** Returns a line of text entered by the user at the equivalent of System.in. */
402   public String JavaDoc getConsoleInput() { return _inputListener.getConsoleInput(); }
403
404   /** Sets the listener for any type of single-source input event.
405    * The listener can only be changed with the changeInputListener method.
406    * @param listener a listener that reacts to input requests
407    * @throws IllegalStateException if the input listener is locked
408    */

409   public void setInputListener(InputListener listener) {
410     if (_inputListener == NoInputListener.ONLY) _inputListener = listener;
411     else throw new IllegalStateException JavaDoc("Cannot change the input listener until it is released.");
412   }
413
414   /** Changes the input listener. Takes in the old listener to ensure that the owner
415    * of the original listener is aware that it is being changed. It is therefore
416    * important NOT to include a public accessor to the input listener on the model.
417    * @param oldListener the listener that was installed
418    * @param newListener the listener to be installed
419    */

420   public void changeInputListener(InputListener oldListener, InputListener newListener) {
421     // synchronize to prevent concurrent modifications to the listener
422
synchronized(NoInputListener.ONLY) {
423       if (_inputListener == oldListener) _inputListener = newListener;
424       else
425         throw new IllegalArgumentException JavaDoc("The given old listener is not installed!");
426     }
427   }
428
429   /** Any common behavior when an interaction ends. Subclasses might want to additionally notify listeners
430    * here. (Do this after calling super())
431    */

432   protected void _interactionIsOver() {
433     _document.addToHistory(_toAddToHistory);
434     _document.setInProgress(false);
435     _document.insertPrompt();
436     _notifyInteractionEnded();
437   }
438
439   /** Notifies listeners that an interaction has ended. (Subclasses must maintain listeners.) */
440   protected abstract void _notifyInteractionEnded();
441
442   /** Appends a string to the given document using a named style. Also waits for a small amount of time
443    * (_writeDelay) to prevent any one writer from flooding the model with print calls to the point that
444    * the user interface could become unresponsive.
445    * @param s String to append to the end of the document
446    * @param styleName Name of the style to use for s
447    */

448   public void append(String JavaDoc s, String JavaDoc styleName) {
449     synchronized(_writerLock) {
450       try {
451         _document.append(s, styleName);
452         
453         // Wait to prevent being flooded with println's
454
_writerLock.wait(_writeDelay);
455       }
456       catch (EditDocumentException e) { throw new UnexpectedException(e); }
457       catch (InterruptedException JavaDoc e) {
458         // It's ok, we'll go ahead and resume
459
}
460     }
461   }
462
463   /** Signifies that the most recent interpretation completed successfully, returning no value. */
464   public void replReturnedVoid() { _interactionIsOver(); }
465
466   /** Signifies that the most recent interpretation completed successfully, returning a value.
467    *
468    * @param result The .toString-ed version of the value that was returned by the interpretation. We must return the
469    * String form because returning the Object directly would require the data type to be serializable.
470    */

471   public void replReturnedResult(String JavaDoc result, String JavaDoc style) {
472     append(result + _newLine, style);
473     _interactionIsOver();
474   }
475
476   /** Signifies that the most recent interpretation was ended due to an exception being thrown.
477    * @param exceptionClass The name of the class of the thrown exception
478    * @param message The exception's message
479    * @param stackTrace The stack trace of the exception
480    */

481   public void replThrewException(String JavaDoc exceptionClass, String JavaDoc message, String JavaDoc stackTrace, String JavaDoc shortMessage) {
482     if (shortMessage!=null) {
483       if (shortMessage.endsWith("<EOF>\"")) {
484         interactionContinues();
485         return;
486       }
487     }
488     _document.appendExceptionResult(exceptionClass, message, stackTrace, InteractionsDocument.ERROR_STYLE);
489     _interactionIsOver();
490   }
491
492   /** Signifies that the most recent interpretation was preempted by a syntax error. The integer parameters
493    * support future error highlighting.
494    * @param errorMessage The syntax error message
495    * @param startRow The starting row of the error
496    * @param startCol The starting column of the error
497    * @param endRow The end row of the error
498    * param endCol The end column of the error
499    */

500   public void replReturnedSyntaxError(String JavaDoc errorMessage, String JavaDoc interaction, int startRow, int startCol,
501                                       int endRow, int endCol ) {
502     if (errorMessage!=null) {
503       if (errorMessage.endsWith("<EOF>\"")) {
504         interactionContinues();
505         return;
506       }
507     }
508     
509     edu.rice.cs.plt.tuple.Pair<Integer JavaDoc,Integer JavaDoc> oAndL =
510       StringOps.getOffsetAndLength(interaction, startRow, startCol, endRow, endCol);
511
512     _notifySyntaxErrorOccurred(_document.getPromptPos() + oAndL.first().intValue(),oAndL.second().intValue());
513
514     _document.appendSyntaxErrorResult(errorMessage, interaction, startRow, startCol, endRow, endCol,
515                                       InteractionsDocument.ERROR_STYLE);
516
517     _interactionIsOver();
518   }
519
520   /** Signifies that the most recent interpretation contained a call to System.exit.
521    * @param status The exit status that will be returned.
522    */

523   public void replCalledSystemExit(int status) {
524 // Utilities.showDebug("InteractionsModel: replCalledSystemExit(" + status + ") called");
525
_notifyInterpreterExited(status);
526   }
527
528   /** Notifies listeners that the interpreter has exited unexpectedly. (Subclasses must maintain listeners.)
529    * @param status Status code of the dead process
530    */

531   protected abstract void _notifyInterpreterExited(int status);
532
533   /** Called when the interpreter starts to reset. */
534   public void interpreterResetting() {
535 // Utilities.showDebug("InteractionsModel: interpreterResetting called. _waitingForFirstInterpreter = " +
536
// _waitingForFirstInterpreter);
537
if (! _waitingForFirstInterpreter) {
538       _document.acquireWriteLock();
539       try {
540         _document.insertBeforeLastPrompt("Resetting Interactions..." + _newLine, InteractionsDocument.ERROR_STYLE);
541         _document.setInProgress(true);
542       }
543       finally { _document.releaseWriteLock(); }
544 // Utilities.showDebug("interpreter resetting in progress");
545

546       // Change to a new debug port to avoid conflicts
547
try { _createNewDebugPort(); }
548       catch (IOException ioe) {
549         // Oh well, leave it at the previous port
550
}
551       _notifyInterpreterResetting();
552 // Utilities.showDebug("InteractionsModel: interpreterResetting notification complete");
553
}
554   }
555
556   /** Notifies listeners that the interpreter is resetting. (Subclasses must maintain listeners.) */
557   protected abstract void _notifyInterpreterResetting();
558
559   /** This method is called by the Main JVM if the Interpreter JVM cannot be exited
560    * @param t The Throwable thrown by System.exit
561    */

562   public void interpreterResetFailed(Throwable JavaDoc t) {
563     _interpreterResetFailed(t);
564     _document.setInProgress(false);
565     _notifyInterpreterResetFailed(t);
566   }
567
568   /** Any extra action to perform (beyond notifying listeners) when the interpreter fails to reset.
569    * @param t The Throwable thrown by System.exit
570    */

571   protected abstract void _interpreterResetFailed(Throwable JavaDoc t);
572
573   /** Notifies listeners that the interpreter reset failed. (Subclasses must maintain listeners.)
574    * @param t Throwable explaining why the reset failed.
575    */

576   protected abstract void _notifyInterpreterResetFailed(Throwable JavaDoc t);
577   
578   public String JavaDoc getBanner() { return _banner; }
579   
580   public String JavaDoc getStartUpBanner() { return getBanner(_workingDirectory); }
581   
582   public static String JavaDoc getBanner(File wd) { return BANNER_PREFIX + " Working directory is " + wd + '\n'; }
583
584   private String JavaDoc generateBanner(File wd) {
585     _banner = getBanner(wd);
586     return _banner;
587   }
588   
589   //TODO: use _workingDirectory field rather than passing wd?
590

591   /** Called when a new Java interpreter has registered and is ready for use. */
592   public void interpreterReady(File wd) {
593 // System.out.println("interpreterReady(" + wd + ") called in InteractionsModel"); // DEBUG
594
// System.out.println("_waitingForFirstInterpreter = " + _waitingForFirstInterpreter); // DEBUG
595
if (! _waitingForFirstInterpreter) {
596       _document.reset(generateBanner(wd));
597       _document.setInProgress(false);
598       _notifyInterpreterReady(wd);
599     }
600     _waitingForFirstInterpreter = false;
601   }
602   
603   /** Notifies listeners that the interpreter is ready. (Subclasses must maintain listeners.) */
604   public abstract void _notifyInterpreterReady(File wd);
605   
606    /** Called when the slave JVM has been used for interpretation or unit testing. */
607   public void slaveJVMUsed() { _notifySlaveJVMUsed(); }
608   
609   /** Notifies listeners that the slave JVM has been used. (Subclasses must maintain listeners.) */
610   protected abstract void _notifySlaveJVMUsed();
611
612   /** Assumes a trimmed String. Returns a string of the main call that the interpretor can use. */
613   protected static String JavaDoc _testClassCall(String JavaDoc s) {
614     if (s.endsWith(";")) s = _deleteSemiColon(s);
615     List JavaDoc<String JavaDoc> args = ArgumentTokenizer.tokenize(s, true);
616     boolean seenArg = false;
617     final String JavaDoc className = args.get(1);
618     final StringBuilder JavaDoc mainCall = new StringBuilder JavaDoc();
619     mainCall.append(className.substring(1, className.length() - 1));
620     mainCall.append(".main(new String[]{");
621     for (int i = 2; i < args.size(); i++) {
622       if (seenArg) mainCall.append(",");
623       else seenArg = true;
624       mainCall.append(args.get(i));
625     }
626     mainCall.append("});");
627     return mainCall.toString();
628   }
629
630   /** Deletes the last character of a string. Assumes semicolon at the end, but does not check. Helper
631    * for _testClassCall(String).
632    * @param s the String containing the semicolon
633    * @return a substring of s with one less character
634    */

635   protected static String JavaDoc _deleteSemiColon(String JavaDoc s) { return s.substring(0, s.length() - 1); }
636
637   /** Singleton InputListener which should never be asked for input. */
638   private static class NoInputListener implements InputListener {
639     public static final NoInputListener ONLY = new NoInputListener();
640     private NoInputListener() { }
641
642     public String JavaDoc getConsoleInput() { throw new IllegalStateException JavaDoc("No input listener installed!"); }
643   }
644   
645   /** Gets the console tab document for this interactions model */
646   public abstract ConsoleDocument getConsoleDocument();
647 }
648
Popular Tags