Source Code Cross Referenced for InteractionsModel.java in  » IDE » DrJava » edu » rice » cs » drjava » model » repl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » DrJava » edu.rice.cs.drjava.model.repl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*BEGIN_COPYRIGHT_BLOCK
002:         *
003:         * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004:         * All rights reserved.
005:         * 
006:         * Redistribution and use in source and binary forms, with or without
007:         * modification, are permitted provided that the following conditions are met:
008:         *    * Redistributions of source code must retain the above copyright
009:         *      notice, this list of conditions and the following disclaimer.
010:         *    * Redistributions in binary form must reproduce the above copyright
011:         *      notice, this list of conditions and the following disclaimer in the
012:         *      documentation and/or other materials provided with the distribution.
013:         *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014:         *      names of its contributors may be used to endorse or promote products
015:         *      derived from this software without specific prior written permission.
016:         * 
017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018:         * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020:         * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024:         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028:         *
029:         * This software is Open Source Initiative approved Open Source Software.
030:         * Open Source Initative Approved is a trademark of the Open Source Initiative.
031:         * 
032:         * This file is part of DrJava.  Download the current version of this project
033:         * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034:         * 
035:         * END_COPYRIGHT_BLOCK*/
036:
037:        package edu.rice.cs.drjava.model.repl;
038:
039:        import java.io.*;
040:        import java.net.ServerSocket;
041:        import java.util.List;
042:        import java.util.ArrayList;
043:
044:        import edu.rice.cs.drjava.CodeStatus;
045:        import edu.rice.cs.drjava.ui.InteractionsController;
046:        import edu.rice.cs.util.FileOpenSelector;
047:        import edu.rice.cs.util.OperationCanceledException;
048:        import edu.rice.cs.util.StringOps;
049:        import edu.rice.cs.util.UnexpectedException;
050:        import edu.rice.cs.util.*;
051:        import edu.rice.cs.util.swing.Utilities;
052:        import edu.rice.cs.util.text.ConsoleDocumentInterface;
053:        import edu.rice.cs.util.text.ConsoleDocument;
054:        import edu.rice.cs.util.text.EditDocumentException;
055:        import edu.rice.cs.plt.tuple.Pair;
056:
057:        /** A model which can serve as the glue between an InteractionsDocument and a JavaInterpreter.  This 
058:         * abstract class provides common functionality for all such models.
059:         * @version $Id: InteractionsModel.java 4264 2007-11-15 01:33:48Z mgricken $
060:         */
061:        public abstract class InteractionsModel implements 
062:                InteractionsModelCallback {
063:
064:            /** Banner prefix. */
065:            public static final String BANNER_PREFIX = "Welcome to DrJava.";
066:
067:            public static final String _newLine = "\n"; // was StringOps.EOL; but Swing uses '\n' for newLine
068:
069:            /** Keeps track of any listeners to the model. */
070:            protected final InteractionsEventNotifier _notifier = new InteractionsEventNotifier();
071:
072:            /** InteractionsDocument containing the commands and history. */
073:            protected final InteractionsDocument _document;
074:
075:            /** Whether we are waiting for the interpreter to register for the first time. */
076:            protected volatile boolean _waitingForFirstInterpreter;
077:
078:            /** The working directory for the current interpreter. */
079:            protected volatile File _workingDirectory;
080:
081:            /** A lock object to prevent multiple threads from interpreting at once. */
082:            private final Object _interpreterLock;
083:
084:            /** A lock object to prevent print calls to System.out or System.err from flooding the JVM, ensuring the UI remains
085:             * responsive.  Only public for testing purposes. */
086:            public final Object _writerLock;
087:
088:            /** Number of milliseconds to wait after each println, to prevent the JVM from being flooded with print calls. */
089:            private final int _writeDelay;
090:
091:            /** Port used by the debugger to connect to the Interactions JVM. Uniquely created in getDebugPort(). */
092:            private volatile int _debugPort;
093:
094:            /** Whether the debug port has already been set.  If not, calling getDebugPort will generate an available port. */
095:            private volatile boolean _debugPortSet;
096:
097:            /** The String added to history when the interaction is complete or an error is thrown */
098:            private volatile String _toAddToHistory = "";
099:
100:            /** The input listener to listen for requests to System.in. */
101:            protected volatile InputListener _inputListener;
102:
103:            /** The embedded interactions document (a SwingDocument in native DrJava) */
104:            protected final ConsoleDocumentInterface _adapter;
105:
106:            /** Banner displayed at top of the interactions document */
107:            private volatile String _banner;
108:
109:            /** Last error, or null if successful. */
110:            protected volatile Pair<String, String> _lastError = null;
111:            protected volatile Pair<String, String> _secondToLastError = null;
112:
113:            /** Constructs an InteractionsModel.
114:             *  @param adapter DocumentAdapter to use in the InteractionsDocument
115:             *  @param wd Working directory for the interpreter
116:             *  @param historySize Number of lines to store in the history
117:             *  @param writeDelay Number of milliseconds to wait after each println
118:             */
119:            public InteractionsModel(ConsoleDocumentInterface adapter, File wd,
120:                    int historySize, int writeDelay) {
121:                _writeDelay = writeDelay;
122:                _document = new InteractionsDocument(adapter, historySize,
123:                        getBanner(wd));
124:                _adapter = adapter;
125:                _waitingForFirstInterpreter = true;
126:                _workingDirectory = wd;
127:                _interpreterLock = new Object();
128:                _writerLock = new Object();
129:                _debugPort = -1;
130:                _debugPortSet = false;
131:                _inputListener = NoInputListener.ONLY;
132:            }
133:
134:            /** Add an InteractionsListener to the model.
135:             *  @param listener a listener that reacts to Interactions events */
136:            public void addListener(InteractionsListener listener) {
137:                _notifier.addListener(listener);
138:            }
139:
140:            /** Remove an InteractionsListener from the model.  If the listener is not currently listening to this model, this 
141:             *  method has no effect.
142:             *  @param listener a listener that reacts to Interactions events
143:             */
144:            public void removeListener(InteractionsListener listener) {
145:                _notifier.removeListener(listener);
146:            }
147:
148:            /** Removes all InteractionsListeners from this model. */
149:            public void removeAllInteractionListeners() {
150:                _notifier.removeAllListeners();
151:            }
152:
153:            /** Returns the InteractionsDocument stored by this model. */
154:            public InteractionsDocument getDocument() {
155:                return _document;
156:            }
157:
158:            public void interactionContinues() {
159:                _document.setInProgress(false);
160:                _notifyInteractionEnded();
161:                _notifyInteractionIncomplete();
162:            }
163:
164:            /** Sets this model's notion of whether it is waiting for the first interpreter to connect.  The interactionsReady
165:             *  event is not fired for the first interpreter.
166:             */
167:            public void setWaitingForFirstInterpreter(boolean waiting) {
168:                _waitingForFirstInterpreter = waiting;
169:            }
170:
171:            /** Interprets the current given text at the prompt in the interactions doc. */
172:            public void interpretCurrentInteraction() {
173:                synchronized (_interpreterLock) {
174:                    // Don't start a new interaction while one is in progress
175:                    if (_document.inProgress())
176:                        return;
177:
178:                    String text = _document.getCurrentInteraction();
179:                    String toEval = text.trim();
180:                    if (toEval.startsWith("java "))
181:                        toEval = _testClassCall(toEval);
182:
183:                    _prepareToInterpret(text);
184:                    interpret(toEval);
185:                }
186:            }
187:
188:            /** Performs pre-interpretation preparation of the interactions document and notifies the view. */
189:            private void _prepareToInterpret(String text) {
190:                addNewLine();
191:                _notifyInteractionStarted();
192:                _document.setInProgress(true);
193:                _toAddToHistory = text; // _document.addToHistory(text);
194:                //Do not add to history immediately in case the user is not finished typing when they press return
195:            }
196:
197:            public void addNewLine() {
198:                append(_newLine, InteractionsDocument.DEFAULT_STYLE);
199:            }
200:
201:            /** Interprets the given command.
202:             *  @param toEval command to be evaluated. */
203:            public final void interpret(String toEval) {
204:                synchronized (_interpreterLock) {
205:                    _interpret(toEval);
206:                }
207:            }
208:
209:            /** Interprets the given command.  This should only be called from interpret, never directly.
210:             *  @param toEval command to be evaluated
211:             */
212:            protected abstract void _interpret(String toEval);
213:
214:            /** Notifies the view that the current interaction is incomplete. */
215:            protected abstract void _notifyInteractionIncomplete();
216:
217:            /** Notifies listeners that an interaction has started. (Subclasses must maintain listeners.) */
218:            protected abstract void _notifyInteractionStarted();
219:
220:            /** Gets the string representation of the value of a variable in the current interpreter.
221:             *  @param var the name of the variable
222:             */
223:            public abstract String getVariableToString(String var);
224:
225:            /** Gets the class name of a variable in the current interpreter.
226:             *  @param var the name of the variable
227:             */
228:            public abstract String getVariableClassName(String var);
229:
230:            /** Resets the Java interpreter with working directry wd. */
231:            public final void resetInterpreter(File wd) {
232:                _workingDirectory = wd;
233:                _resetInterpreter(wd);
234:            }
235:
236:            /** Resets the Java interpreter.  This should only be called from resetInterpreter, never directly. */
237:            protected abstract void _resetInterpreter(File wd);
238:
239:            /** Returns the working directory for the current interpreter. */
240:            public File getWorkingDirectory() {
241:                return _workingDirectory;
242:            }
243:
244:            /** These add the given path to the classpaths used in the interpreter.
245:             *  @param path Path to add
246:             */
247:            public abstract void addProjectClassPath(File f);
248:
249:            public abstract void addBuildDirectoryClassPath(File f);
250:
251:            public abstract void addProjectFilesClassPath(File f);
252:
253:            public abstract void addExternalFilesClassPath(File f);
254:
255:            public abstract void addExtraClassPath(File f);
256:
257:            /** Handles a syntax error being returned from an interaction
258:             *  @param offset the first character of the error in the InteractionsDocument
259:             *  @param length the length of the error.
260:             */
261:            protected abstract void _notifySyntaxErrorOccurred(int offset,
262:                    int length);
263:
264:            /** Opens the files chosen in the given file selector, and returns an ArrayList with one history string 
265:             *  for each selected file.
266:             *  @param selector A file selector supporting multiple file selection
267:             *  @return a list of histories (one for each selected file)
268:             */
269:            protected ArrayList<String> _getHistoryText(
270:                    FileOpenSelector selector) throws IOException,
271:                    OperationCanceledException {
272:                File[] files = selector.getFiles();
273:                if (files == null)
274:                    throw new IOException("No Files returned from FileSelector");
275:
276:                ArrayList<String> histories = new ArrayList<String>();
277:                ArrayList<String> strings = new ArrayList<String>();
278:
279:                for (File f : files) {
280:                    if (f == null)
281:                        throw new IOException(
282:                                "File name returned from FileSelector is null");
283:                    try {
284:                        FileInputStream fis = new FileInputStream(f);
285:                        InputStreamReader isr = new InputStreamReader(fis);
286:                        BufferedReader br = new BufferedReader(isr);
287:                        while (true) {
288:                            String line = br.readLine();
289:                            if (line == null)
290:                                break;
291:                            strings.add(line);
292:                        }
293:                        br.close(); // win32 needs readers closed explicitly!
294:                    } catch (IOException ioe) {
295:                        throw new IOException(
296:                                "File name returned from FileSelector is null");
297:                    }
298:
299:                    // Create a single string with all formatted lines from this history
300:                    final StringBuilder text = new StringBuilder();
301:                    boolean firstLine = true;
302:                    int formatVersion = 1;
303:                    for (String s : strings) {
304:                        int sl = s.length();
305:                        if (sl > 0) {
306:
307:                            // check for format version string. NOTE: the original file format did not have a version string
308:                            if (firstLine
309:                                    && (s.trim()
310:                                            .equals(History.HISTORY_FORMAT_VERSION_2
311:                                                    .trim())))
312:                                formatVersion = 2;
313:
314:                            switch (formatVersion) {
315:                            case (1):
316:                                // When reading this format, we need to make sure each line ends in a semicolon.
317:                                // This behavior can be buggy; that's why the format was changed.
318:                                text.append(s);
319:                                if (s.charAt(sl - 1) != ';')
320:                                    text.append(';');
321:                                text.append(StringOps.EOL);
322:                                break;
323:                            case (2):
324:                                if (!firstLine)
325:                                    text.append(s).append(StringOps.EOL); // omit version string from output
326:                                break;
327:                            }
328:                            firstLine = false;
329:                        }
330:                    }
331:
332:                    // Add the entire formatted text to the list of histories
333:                    histories.add(text.toString());
334:                }
335:                return histories;
336:            }
337:
338:            /** Removes the interaction-separator comments from a history, so that they will not appear when executing
339:             *  the history.
340:             *  @param text The full, formatted text of an interactions history (obtained from _getHistoryText)
341:             *  @return A list of strings representing each interaction in the history. If no separators are present, 
342:             *  the entire history is treated as one interaction.
343:             */
344:            protected ArrayList<String> _removeSeparators(String text) {
345:                String sep = History.INTERACTION_SEPARATOR;
346:                int len = sep.length();
347:                ArrayList<String> interactions = new ArrayList<String>();
348:
349:                // Loop while there are still separators, adding the text between separators
350:                //  as separate elements to the interactions list
351:                int index = text.indexOf(sep);
352:                int lastIndex = 0;
353:                while (index != -1) {
354:                    interactions.add(text.substring(lastIndex, index).trim());
355:                    lastIndex = index + len;
356:                    index = text.indexOf(sep, lastIndex);
357:                }
358:
359:                // get last interaction
360:                String last = text.substring(lastIndex, text.length()).trim();
361:                if (!"".equals(last))
362:                    interactions.add(last);
363:                return interactions;
364:            }
365:
366:            /** Interprets the files selected in the FileOpenSelector. Assumes all strings have no trailing whitespace.
367:             * Interprets the array all at once so if there are any errors, none of the statements after the first 
368:             * erroneous one are processed.
369:             */
370:            public void loadHistory(FileOpenSelector selector)
371:                    throws IOException {
372:                ArrayList<String> histories;
373:                try {
374:                    histories = _getHistoryText(selector);
375:                } catch (OperationCanceledException oce) {
376:                    return;
377:                }
378:                _document.clearCurrentInteraction();
379:
380:                // Insert into the document and interpret
381:                final StringBuilder buf = new StringBuilder();
382:                for (String hist : histories) {
383:                    ArrayList<String> interactions = _removeSeparators(hist);
384:                    for (String curr : interactions) {
385:                        int len = curr.length();
386:                        buf.append(curr);
387:                        if (len > 0 && curr.charAt(len - 1) != ';')
388:                            buf.append(';');
389:                        buf.append(StringOps.EOL);
390:                    }
391:                }
392:                append(buf.toString().trim(),
393:                        InteractionsDocument.DEFAULT_STYLE);
394:                interpretCurrentInteraction();
395:            }
396:
397:            /* Loads the contents of the specified file(s) into the histories buffer. */
398:            public InteractionsScriptModel loadHistoryAsScript(
399:                    FileOpenSelector selector) throws IOException,
400:                    OperationCanceledException {
401:                ArrayList<String> histories = _getHistoryText(selector);
402:                ArrayList<String> interactions = new ArrayList<String>();
403:                for (String hist : histories)
404:                    interactions.addAll(_removeSeparators(hist));
405:                return new InteractionsScriptModel(this , interactions);
406:            }
407:
408:            /** Returns the port number to use for debugging the interactions JVM. Generates an available port if one has 
409:             *  not been set manually.
410:             *  @throws IOException if unable to get a valid port number.
411:             */
412:            public int getDebugPort() throws IOException {
413:                if (!_debugPortSet)
414:                    _createNewDebugPort();
415:                return _debugPort;
416:            }
417:
418:            /** Generates an available port for use with the debugger.
419:             *  @throws IOException if unable to get a valid port number.
420:             */
421:            protected void _createNewDebugPort() throws IOException {
422:                //    Utilities.showDebug("InteractionsModel: _createNewDebugPort() called");
423:                try {
424:                    ServerSocket socket = new ServerSocket(0);
425:                    _debugPort = socket.getLocalPort();
426:                    socket.close();
427:                } catch (java.net.SocketException se) {
428:                    // something wrong with sockets, can't use for debugger
429:                    _debugPort = -1;
430:                }
431:                _debugPortSet = true;
432:                System.setProperty("drjava.debug.port", String
433:                        .valueOf(_debugPort));
434:            }
435:
436:            /** Sets the port number to use for debugging the interactions JVM.
437:             *  @param port Port to use to debug the interactions JVM
438:             */
439:            public void setDebugPort(int port) {
440:                _debugPort = port;
441:                _debugPortSet = true;
442:            }
443:
444:            /** Called when the repl prints to System.out.  Includes a delay to prevent flooding the interactions document.
445:             *  @param s String to print
446:             */
447:            public void replSystemOutPrint(String s) {
448:                _document.insertBeforeLastPrompt(s,
449:                        InteractionsDocument.SYSTEM_OUT_STYLE);
450:                _writerDelay();
451:            }
452:
453:            /** Called when the repl prints to System.err.  Includes a delay to prevent flooding the interactions document.
454:             *  @param s String to print
455:             */
456:            public void replSystemErrPrint(String s) {
457:                _document.insertBeforeLastPrompt(s,
458:                        InteractionsDocument.SYSTEM_ERR_STYLE);
459:                _writerDelay();
460:            }
461:
462:            /** Returns a line of text entered by the user at the equivalent of System.in. */
463:            public String getConsoleInput() {
464:                return _inputListener.getConsoleInput();
465:            }
466:
467:            /** Sets the listener for any type of single-source input event. The listener can only be changed with the 
468:             * changeInputListener method.
469:             * @param listener a listener that reacts to input requests
470:             * @throws IllegalStateException if the input listener is locked
471:             */
472:            public void setInputListener(InputListener listener) {
473:                if (_inputListener == NoInputListener.ONLY) {
474:                    _inputListener = listener;
475:                } else
476:                    throw new IllegalStateException(
477:                            "Cannot change the input listener until it is released.");
478:            }
479:
480:            /** Changes the input listener. Takes in the old listener to ensure that the owner
481:             *  of the original listener is aware that it is being changed. It is therefore
482:             *  important NOT to include a public accessor to the input listener on the model.
483:             *  @param oldListener the listener that was installed
484:             *  @param newListener the listener to be installed
485:             */
486:            public void changeInputListener(InputListener oldListener,
487:                    InputListener newListener) {
488:                // synchronize to prevent concurrent modifications to the listener
489:                synchronized (NoInputListener.ONLY) {
490:                    if (_inputListener == oldListener)
491:                        _inputListener = newListener;
492:                    else
493:                        throw new IllegalArgumentException(
494:                                "The given old listener is not installed!");
495:                }
496:            }
497:
498:            /** Any common behavior when an interaction ends. Subclasses might want to additionally notify listeners 
499:             * here. (Do this after calling super()),  public for testing purposes.
500:             */
501:            public void _interactionIsOver() {
502:                _document.acquireWriteLock(); // TODO: encapsulate as method of InteractionsDocument
503:                try {
504:                    _document.addToHistory(_toAddToHistory);
505:                    _document.setInProgress(false);
506:                    _document.insertPrompt();
507:                } finally {
508:                    _document.releaseWriteLock();
509:                }
510:
511:                _notifyInteractionEnded();
512:            }
513:
514:            /** Notifies listeners that an interaction has ended. (Subclasses must maintain listeners.) */
515:            protected abstract void _notifyInteractionEnded();
516:
517:            /** Appends a string to the given document using a named style. Also waits for a small amount of time 
518:             *  (_writeDelay) to prevent any one writer from flooding the model with print calls to the point that 
519:             *  the user interface could become unresponsive.
520:             *  @param s String to append to the end of the document
521:             *  @param styleName Name of the style to use for s
522:             */
523:            public void append(String s, String styleName) {
524:                _document.append(s, styleName);
525:                _writerDelay();
526:            }
527:
528:            /** Waits for a small amount of time on a shared writer lock. */
529:            public void _writerDelay() {
530:                synchronized (_writerLock) {
531:                    try {
532:                        // Wait to prevent being flooded with println's
533:                        _writerLock.wait(_writeDelay);
534:                    } catch (EditDocumentException e) {
535:                        throw new UnexpectedException(e);
536:                    } catch (InterruptedException e) { /* Not a problem. continue */
537:                    }
538:                }
539:            }
540:
541:            /** Signifies that the most recent interpretation completed successfully, returning no value. */
542:            public void replReturnedVoid() {
543:                _secondToLastError = _lastError;
544:                _lastError = null;
545:                _interactionIsOver();
546:            }
547:
548:            /** Signifies that the most recent interpretation completed successfully, returning a value.
549:             *  @param result The .toString-ed version of the value that was returned by the interpretation. We must return the 
550:             *         String form because returning the Object directly would require the data type to be serializable.
551:             */
552:            public void replReturnedResult(String result, String style) {
553:                //    System.err.println("InteractionsModel.replReturned(...) passed '" + result + "'");
554:                _secondToLastError = _lastError;
555:                _lastError = null;
556:                append(result + "\n", style);
557:                _interactionIsOver();
558:            }
559:
560:            /** Signifies that the most recent interpretation was ended due to an exception being thrown.
561:             *  @param exceptionClass The name of the class of the thrown exception
562:             *  @param message The exception's message
563:             *  @param stackTrace The stack trace of the exception
564:             */
565:            public void replThrewException(String exceptionClass,
566:                    String message, String stackTrace, String shortMessage) {
567:                if (shortMessage != null) {
568:                    if (shortMessage.endsWith("<EOF>\"")) {
569:                        interactionContinues();
570:                        return;
571:                    }
572:                }
573:                _document.appendExceptionResult(exceptionClass, message,
574:                        stackTrace, InteractionsDocument.ERROR_STYLE);
575:                _secondToLastError = _lastError;
576:                _lastError = new Pair<String, String>(exceptionClass, message);
577:                _interactionIsOver();
578:            }
579:
580:            /** Signifies that the most recent interpretation was preempted by a syntax error.  The integer parameters
581:             *  support future error highlighting.
582:             *  @param errorMessage The syntax error message
583:             *  @param startRow The starting row of the error
584:             *  @param startCol The starting column of the error
585:             *  @param endRow The end row of the error
586:             *  param endCol The end column of the error
587:             */
588:            public void replReturnedSyntaxError(String errorMessage,
589:                    String interaction, int startRow, int startCol, int endRow,
590:                    int endCol) {
591:                _secondToLastError = _lastError;
592:                _lastError = new Pair<String, String>(
593:                        "koala.dynamicjava.parser.ParserException",
594:                        errorMessage);
595:                if (errorMessage != null) {
596:                    if (errorMessage.endsWith("<EOF>\"")) {
597:                        interactionContinues();
598:                        return;
599:                    }
600:                }
601:
602:                Pair<Integer, Integer> oAndL = StringOps.getOffsetAndLength(
603:                        interaction, startRow, startCol, endRow, endCol);
604:
605:                _notifySyntaxErrorOccurred(_document.getPromptPos()
606:                        + oAndL.first().intValue(), oAndL.second().intValue());
607:
608:                _document.appendSyntaxErrorResult(errorMessage, interaction,
609:                        startRow, startCol, endRow, endCol,
610:                        InteractionsDocument.ERROR_STYLE);
611:
612:                _interactionIsOver();
613:            }
614:
615:            /** Signifies that the most recent interpretation contained a call to System.exit.
616:             *  @param status The exit status that will be returned.
617:             */
618:            public void replCalledSystemExit(int status) {
619:                //    Utilities.showDebug("InteractionsModel: replCalledSystemExit(" + status + ") called");
620:                _notifyInterpreterExited(status);
621:            }
622:
623:            /** Notifies listeners that the interpreter has exited unexpectedly. (Subclasses must maintain listeners.)
624:             *  @param status Status code of the dead process
625:             */
626:            protected abstract void _notifyInterpreterExited(int status);
627:
628:            /** Called when the interpreter starts to reset. */
629:            public void interpreterResetting() {
630:                //    Utilities.showDebug("InteractionsModel: interpreterResetting called.  _waitingForFirstInterpreter = " + 
631:                //      _waitingForFirstInterpreter);
632:                if (!_waitingForFirstInterpreter) {
633:                    _document.acquireWriteLock();
634:                    try {
635:                        _document.insertBeforeLastPrompt(
636:                                "Resetting Interactions ...\n",
637:                                InteractionsDocument.ERROR_STYLE);
638:                        _document.setInProgress(true);
639:                    } finally {
640:                        _document.releaseWriteLock();
641:                    }
642:                    //      Utilities.showDebug("interpreter resetting in progress");
643:
644:                    // Change to a new debug port to avoid conflicts
645:                    try {
646:                        _createNewDebugPort();
647:                    } catch (IOException ioe) {
648:                        // Oh well, leave it at the previous port
649:                    }
650:                    _notifyInterpreterResetting();
651:                    //      Utilities.showDebug("InteractionsModel: interpreterResetting notification complete");
652:                }
653:            }
654:
655:            /** Notifies listeners that the interpreter is resetting. (Subclasses must maintain listeners.) */
656:            protected abstract void _notifyInterpreterResetting();
657:
658:            /** This method is called by the Main JVM if the Interpreter JVM cannot be exited
659:             *  @param t The Throwable thrown by System.exit
660:             */
661:            public void interpreterResetFailed(Throwable t) {
662:                _interpreterResetFailed(t);
663:                _document.setInProgress(false);
664:                _notifyInterpreterResetFailed(t);
665:            }
666:
667:            /** Any extra action to perform (beyond notifying listeners) when the interpreter fails to reset.
668:             *  @param t The Throwable thrown by System.exit
669:             */
670:            protected abstract void _interpreterResetFailed(Throwable t);
671:
672:            /** Notifies listeners that the interpreter reset failed. (Subclasses must maintain listeners.)
673:             *  @param t Throwable explaining why the reset failed.
674:             */
675:            protected abstract void _notifyInterpreterResetFailed(Throwable t);
676:
677:            public String getBanner() {
678:                return _banner;
679:            }
680:
681:            public String getStartUpBanner() {
682:                return getBanner(_workingDirectory);
683:            }
684:
685:            public static String getBanner(File wd) {
686:                return BANNER_PREFIX + "  Working directory is " + wd + '\n';
687:            }
688:
689:            private String generateBanner(File wd) {
690:                _banner = getBanner(wd);
691:                return _banner;
692:            }
693:
694:            /** Called when a new Java interpreter has registered and is ready for use. */
695:            public void interpreterReady(File wd) {
696:                //    System.err.println("interpreterReady(" + wd + ") called in InteractionsModel");  // DEBUG
697:                //    System.out.println("_waitingForFirstInterpreter = " + _waitingForFirstInterpreter);  // DEBUG
698:                if (!_waitingForFirstInterpreter) {
699:                    _document.reset(generateBanner(wd));
700:                    _document.setInProgress(false);
701:                    _notifyInterpreterReady(wd);
702:                }
703:                _waitingForFirstInterpreter = false;
704:            }
705:
706:            /** Notifies listeners that the interpreter is ready. (Subclasses must maintain listeners.) */
707:            public abstract void _notifyInterpreterReady(File wd);
708:
709:            /** Called when the slave JVM has been used for interpretation or unit testing. */
710:            public void slaveJVMUsed() {
711:                _notifySlaveJVMUsed();
712:            }
713:
714:            /** Notifies listeners that the slave JVM has been used. (Subclasses must maintain listeners.) */
715:            protected abstract void _notifySlaveJVMUsed();
716:
717:            /** Assumes a trimmed String. Returns a string of the main call that the interpretor can use. */
718:            protected static String _testClassCall(String s) {
719:                if (s.endsWith(";"))
720:                    s = _deleteSemiColon(s);
721:                List<String> args = ArgumentTokenizer.tokenize(s, true);
722:                boolean seenArg = false;
723:                final String className = args.get(1);
724:                final StringBuilder mainCall = new StringBuilder();
725:                mainCall.append(className.substring(1, className.length() - 1));
726:                mainCall.append(".main(new String[]{");
727:                for (int i = 2; i < args.size(); i++) {
728:                    if (seenArg)
729:                        mainCall.append(",");
730:                    else
731:                        seenArg = true;
732:                    mainCall.append(args.get(i));
733:                }
734:                mainCall.append("});");
735:                return mainCall.toString();
736:            }
737:
738:            /** Deletes the last character of a string.  Assumes semicolon at the end, but does not check.  Helper 
739:             *  for _testClassCall(String).
740:             *  @param s the String containing the semicolon
741:             *  @return a substring of s with one less character
742:             */
743:            protected static String _deleteSemiColon(String s) {
744:                return s.substring(0, s.length() - 1);
745:            }
746:
747:            /** Singleton InputListener which should never be asked for input. */
748:            private static class NoInputListener implements  InputListener {
749:                public static final NoInputListener ONLY = new NoInputListener();
750:
751:                private NoInputListener() {
752:                }
753:
754:                public String getConsoleInput() {
755:                    throw new IllegalStateException(
756:                            "No input listener installed!");
757:                }
758:            }
759:
760:            /** Gets the console tab document for this interactions model */
761:            public abstract ConsoleDocument getConsoleDocument();
762:
763:            /** Return the last error as a pair (exception class name, message), or null if successful. */
764:            public Pair<String, String> getLastError() {
765:                return _lastError;
766:            }
767:
768:            /** Return the second to last error as a pair (exception class name, message), or null if successful. */
769:            public Pair<String, String> getSecondToLastError() {
770:                return _secondToLastError;
771:            }
772:
773:            /** Reset the information about the last and second to last error. */
774:            public void resetLastErrors() {
775:                _lastError = _secondToLastError = null;
776:            }
777:
778:            /** Returns the last history item and then removes it, or returns null if the history is empty. */
779:            public String removeLastFromHistory() {
780:                return _document.removeLastFromHistory();
781:            }
782:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.