Source Code Cross Referenced for InterpreterJVM.java in  » IDE » DrJava » edu » rice » cs » drjava » model » repl » newjvm » 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.newjvm 
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.newjvm;
038:
039:        import java.util.LinkedList;
040:        import java.util.ListIterator;
041:        import java.util.ArrayList;
042:        import java.util.Hashtable;
043:        import java.util.Enumeration;
044:        import java.util.List;
045:        import java.util.Set;
046:        import java.util.LinkedHashSet;
047:        import java.io.*;
048:
049:        import java.rmi.*;
050:
051:        // NOTE: Do NOT import/use the config framework in this class!
052:        //  (This class runs in a different JVM, and will not share the config object)
053:
054:        import edu.rice.cs.util.Log;
055:        import edu.rice.cs.util.OutputStreamRedirector;
056:        import edu.rice.cs.util.InputStreamRedirector;
057:        import edu.rice.cs.util.StringOps;
058:        import edu.rice.cs.util.UnexpectedException;
059:        import edu.rice.cs.util.classloader.ClassFileError;
060:        import edu.rice.cs.util.newjvm.*;
061:        import edu.rice.cs.plt.iter.IterUtil;
062:
063:        import edu.rice.cs.drjava.platform.PlatformFactory;
064:        import edu.rice.cs.drjava.model.junit.JUnitModelCallback;
065:        import edu.rice.cs.drjava.model.junit.JUnitTestManager;
066:        import edu.rice.cs.drjava.model.junit.JUnitError;
067:        import edu.rice.cs.drjava.model.repl.*;
068:
069:        // For Windows focus fix
070:        import javax.swing.JDialog;
071:
072:        import koala.dynamicjava.parser.wrapper.*;
073:        import koala.dynamicjava.parser.*;
074:
075:        /** This is the main class for the interpreter JVM.  All public methods except those involving remote calls (callbacks) 
076:         *  synchronized (unless synchronization has no effect).  This class is loaded in the Interpreter JVM, not the Main JVM. 
077:         *  (Do not use DrJava's config framework here.)
078:         *  <p>
079:         *  Note that this class is specific to DynamicJava. It must be refactored to accommodate other interpreters.
080:         *  @version $Id: InterpreterJVM.java 4255 2007-08-28 19:17:37Z mgricken $
081:         */
082:        public class InterpreterJVM extends AbstractSlaveJVM implements 
083:                InterpreterJVMRemoteI, JUnitModelCallback {
084:
085:            /** Singleton instance of this class. */
086:            public static final InterpreterJVM ONLY = newInterpreterJVM();
087:
088:            private static final Log _log = new Log("MasterSlave.txt", false);
089:            private static final boolean printMessages = false;
090:
091:            /** String to append to error messages when no stack trace is available. */
092:            public static final String EMPTY_TRACE_TEXT = "";
093:
094:            /** Metadata encapsulating the default interpreter. */
095:            private final InterpreterData _defaultInterpreter;
096:
097:            /** Maps names to interpreters with metadata. */
098:            private final Hashtable<String, InterpreterData> _interpreters;
099:
100:            /** The currently accumulated classpath for all Java interpreters.  List contains unqiue entries. */
101:            private final Set<File> _classPath;
102:
103:            /** Responsible for running JUnit tests in this JVM. */
104:            private final JUnitTestManager _junitTestManager;
105:
106:            /** manages the classpath for all of DrJava */
107:            private final ClassPathManager _classPathManager;
108:
109:            /** Remote reference to the MainJVM class in DrJava's primary JVM.  Assigned ONLY once. */
110:            private volatile MainJVMRemoteI _mainJVM;
111:
112:            /** The current interpreter. */
113:            private volatile InterpreterData _activeInterpreter;
114:
115:            //  /** Busy flag.  Used to prevent multiple interpretations from running simultaneously. */
116:            //  private volatile boolean interpretationInProgress = false;
117:
118:            /** Interactions processor, currently a pre-processor **/
119:            //  private InteractionsProcessorI _interactionsProcessor;
120:            /** Whether to display an error message if a reset fails. */
121:            private volatile boolean _messageOnResetFailure;
122:
123:            /** Private constructor; use the singleton ONLY instance. */
124:            private InterpreterJVM() throws RemoteException {
125:
126:                _classPath = new LinkedHashSet<File>();
127:                _classPathManager = new ClassPathManager();
128:                _defaultInterpreter = new InterpreterData(
129:                        new DynamicJavaAdapter(_classPathManager));
130:                _interpreters = new Hashtable<String, InterpreterData>();
131:                _junitTestManager = new JUnitTestManager(this );
132:                _messageOnResetFailure = true;
133:
134:                //    _interactionsProcessor = new InteractionsProcessor();
135:
136:                _quitSlaveThreadName = "Reset Interactions Thread";
137:                _pollMasterThreadName = "Poll DrJava Thread";
138:                _activeInterpreter = _defaultInterpreter;
139:
140:                try {
141:                    _activeInterpreter.getInterpreter().interpret("0");
142:                } catch (ExceptionReturnedException e) {
143:                    throw new edu.rice.cs.util.UnexpectedException(e);
144:                }
145:            }
146:
147:            private static InterpreterJVM newInterpreterJVM() {
148:                try {
149:                    return new InterpreterJVM();
150:                } catch (Exception e) {
151:                    throw new UnexpectedException(e);
152:                }
153:            }
154:
155:            private static void _dialog(String s) {
156:                //javax.swing.JOptionPane.showMessageDialog(null, s);
157:                _log.log(s);
158:            }
159:
160:            /** Actions to perform when this JVM is started (through its superclass, AbstractSlaveJVM).  Contract from superclass
161:             *  mandates that this code does not synchronized on this across a remote call.  This method has no synchronization
162:             *  because it can only be called once (part of the superclass contract) and _mainJVM is only assigned (once!) here. */
163:            protected void handleStart(MasterRemote mainJVM) {
164:                //_dialog("handleStart");
165:                _mainJVM = (MainJVMRemoteI) mainJVM;
166:
167:                // redirect stdin
168:                System.setIn(new InputStreamRedirector() {
169:                    protected String _getInput() { // NOT synchronized on InterpreterJVM.this.  _mainJVM is immutable.
170:                        try {
171:                            String s = _mainJVM.getConsoleInput();
172:                            //          System.err.println("InterpreterJVM.getConsoleInput() = '" + s + "'");
173:                            return s;
174:                        } catch (RemoteException re) {
175:                            // blow up if no MainJVM found
176:                            _log.log("System.in: " + re.toString());
177:                            throw new IllegalStateException(
178:                                    "Main JVM can't be reached for input.\n"
179:                                            + re);
180:                        }
181:                    }
182:                });
183:
184:                // redirect stdout
185:                System.setOut(new PrintStream(new OutputStreamRedirector() {
186:                    public void print(String s) { // NOT synchronized on InterpreterJVM.this.  _mainJVM is immutable.
187:                        try {
188:                            //_log.logTime("out.print: " + s);
189:                            _mainJVM.systemOutPrint(s);
190:                        } catch (RemoteException re) {
191:                            // nothing to do
192:                            _log.log("System.out: " + re.toString());
193:                        }
194:                    }
195:                }));
196:
197:                // redirect stderr
198:                System.setErr(new PrintStream(new OutputStreamRedirector() {
199:                    public void print(String s) { // NOT synchronized on InterpreterJVM.this.  _mainJVM is immutable.
200:                        try {
201:                            //_log.logTime("err.print: " + s);
202:                            _mainJVM.systemErrPrint(s);
203:                        } catch (RemoteException re) {
204:                            // nothing to do
205:                            _log.log("System.err: " + re.toString());
206:                        }
207:                    }
208:                }));
209:
210:                /* On Windows, any frame or dialog opened from Interactions pane will appear *behind* DrJava's frame, unless a 
211:                 * previous frame or dialog is shown here.  Not sure what the difference is, but this hack seems to work.  (I'd
212:                 * be happy to find a better solution, though.)  Only necessary on Windows, since frames and dialogs on other 
213:                 * platforms appear correctly in front of DrJava. */
214:                if (PlatformFactory.ONLY.isWindowsPlatform()) {
215:                    JDialog d = new JDialog();
216:                    d.setSize(0, 0);
217:                    d.setVisible(true);
218:                    d.setVisible(false);
219:                }
220:                //_dialog("interpreter JVM started");
221:            }
222:
223:            /** Interprets the given string of source code in the active interpreter. The result is returned to MainJVM via 
224:             *  the interpretResult method.
225:             *  @param s Source code to interpret.
226:             */
227:            public void interpret(String s) {
228:                interpret(s, _activeInterpreter);
229:            }
230:
231:            /** Interprets the given string of source code with the given interpreter. The result is returned to MainJVM via 
232:             *  the interpretResult method.
233:             *  @param s Source code to interpret.
234:             *  @param interpreterName Name of the interpreter to use
235:             *  @throws IllegalArgumentException if the named interpreter does not exist
236:             */
237:            public void interpret(String s, String interpreterName) {
238:                interpret(s, getInterpreter(interpreterName));
239:            }
240:
241:            /** Interprets the given string of source code with the given interpreter.  The result is returned to MainJVM via
242:             *  the interpretResult method.  Not synchronized on this!
243:             *  @param input Source code to interpret.
244:             *  @param interpreter The interpreter (plus metadata) to use
245:             */
246:            public void interpret(final String input,
247:                    final InterpreterData interpreter) {
248:                _log.log(this  + ".interpret(" + input + ") called");
249:                try {
250:                    synchronized (interpreter) {
251:                        if (interpreter.inProgress()) {
252:                            _mainJVM.interpretResult(new InterpreterBusy());
253:                            return;
254:                        }
255:                        //      interpretationInProgress = true; 
256:                        interpreter.setInProgress(true); // records that a given interpreter is in progress (used by debugger?)
257:                    }
258:                    // The following code is NOT synchronized on this. Mutual exclusion is guaranteed by preceding synchronized block.
259:                    //        Utilities.showDebug("InterpreterJVM.interpret(" + input + ", ...) called");
260:                    Thread thread = new Thread("interpret thread: " + input) {
261:                        public void run() {
262:                            String s = input;
263:                            try { // Delimiting a catch for RemoteExceptions that might be thrown in catch clauses of enclosed try
264:                                try {
265:                                    _log.log("Interpreter thread for " + input
266:                                            + " has started");
267:                                    //              _dialog("to interp: " + s);
268:
269:                                    //            Utilities.showDebug("Preparing to invoke interpret method on " + s);
270:                                    Object result = interpreter
271:                                            .getInterpreter().interpret(s);
272:                                    String resultString = String
273:                                            .valueOf(result);
274:                                    //            Utilities.showDebug("Result string is: " + resultString);
275:
276:                                    if (result == Interpreter.NO_RESULT) {
277:                                        //return new VoidResult();
278:                                        //_dialog("void interp ret: " + resultString);
279:                                        _mainJVM
280:                                                .interpretResult(new VoidResult());
281:                                    } else {
282:                                        // we use String.valueOf because it deals with result = null!
283:                                        //_dialog("about to tell main result was " + resultString);
284:                                        //return new ValueResult(resultString);
285:                                        String style = InteractionsDocument.OBJECT_RETURN_STYLE;
286:                                        if (result instanceof  String) {
287:                                            style = InteractionsDocument.STRING_RETURN_STYLE;
288:                                            //Single quotes have already been added to chars by now, so they are read as strings
289:                                            String possibleChar = (String) result;
290:
291:                                            if (possibleChar.startsWith("\'")
292:                                                    && possibleChar
293:                                                            .endsWith("\'")
294:                                                    && possibleChar.length() == 3)
295:                                                style = InteractionsDocument.CHARACTER_RETURN_STYLE;
296:                                        }
297:                                        if (result instanceof  Number)
298:                                            style = InteractionsDocument.NUMBER_RETURN_STYLE;
299:                                        _mainJVM
300:                                                .interpretResult(new ValueResult(
301:                                                        resultString, style));
302:                                    }
303:                                } catch (ExceptionReturnedException e) {
304:                                    Throwable t = e.getContainedException();
305:                                    //            Utilities.showStackTrace(t);
306:                                    _dialog("interp exception: " + t);
307:                                    // TODO: replace the following if ladder by dynamic dispatch.  Create a visitor for DynamicJava errors?
308:                                    if (t instanceof  ParseException)
309:                                        _mainJVM
310:                                                .interpretResult(new SyntaxErrorResult(
311:                                                        (ParseException) t,
312:                                                        input));
313:                                    else if (t instanceof  TokenMgrError)
314:                                        _mainJVM
315:                                                .interpretResult(new SyntaxErrorResult(
316:                                                        (TokenMgrError) t,
317:                                                        input));
318:                                    else if (t instanceof  ParseError)
319:                                        _mainJVM
320:                                                .interpretResult(new SyntaxErrorResult(
321:                                                        (ParseError) t, input));
322:                                    else {
323:                                        //Other exceptions are non lexical/parse related exceptions. These include arithmetic exceptions, 
324:                                        //wrong version exceptions, etc.
325:
326:                                        _mainJVM
327:                                                .interpretResult(new ExceptionResult(
328:                                                        t.getClass().getName(),
329:                                                        t.getMessage(),
330:                                                        InterpreterJVM
331:                                                                .getStackTrace(t),
332:                                                        null));
333:                                    }
334:                                } catch (Throwable t) {
335:                                    // A user's toString method might throw anything, so we need to be careful
336:                                    _dialog("irregular interp exception: " + t);
337:                                    //            Utilities.showStackTrace(t);
338:                                    String shortMsg = null;
339:                                    if ((t instanceof  ParseError)
340:                                            && ((ParseError) t)
341:                                                    .getParseException() != null)
342:                                        shortMsg = ((ParseError) t)
343:                                                .getMessage(); // in this case, getMessage is equivalent to getShortMessage
344:                                    _mainJVM
345:                                            .interpretResult(new ExceptionResult(
346:                                                    t.getClass().getName(), t
347:                                                            .getMessage(),
348:                                                    InterpreterJVM
349:                                                            .getStackTrace(t),
350:                                                    shortMsg));
351:                                }
352:                            } catch (RemoteException re) { /* MainJVM no longer accessible.  Cannot recover. */
353:                                _log.log("MainJVM.interpret threw "
354:                                        + re.toString());
355:                            }
356:                        }
357:                    }; // end of Thread definition
358:
359:                    thread.setDaemon(true);
360:                    thread.start();
361:                } // end of interpretation block including synchronized prelude 
362:                catch (RemoteException re) { /* MainJVM not accessible.  Cannot recover. */
363:                    _log.log("MainJVM.interpret threw" + re.toString());
364:                } finally { // fields are volatile so no synchronization is necessary
365:                //      interpretationInProgress = false;
366:                    interpreter.setInProgress(false);
367:                }
368:            }
369:
370:            private static String _processReturnValue(Object o) {
371:                if (o instanceof  String)
372:                    return "\"" + o + "\"";
373:                if (o instanceof  Character)
374:                    return "'" + o + "'";
375:                return o.toString();
376:            }
377:
378:            /** Gets the string representation of the value of a variable in the current interpreter.
379:             *  @param var the name of the variable
380:             *  @return null if the variable is not defined, "null" if the value is null, or else its string representation
381:             */
382:            public synchronized String getVariableToString(String var)
383:                    throws RemoteException {
384:                // Add to the default interpreter, if it is a JavaInterpreter
385:                Interpreter i = _activeInterpreter.getInterpreter();
386:                if (i instanceof  JavaInterpreter) {
387:                    try {
388:                        Object value = ((JavaInterpreter) i).getVariable(var);
389:                        if (value == null)
390:                            return "null";
391:                        if (value instanceof  koala.dynamicjava.interpreter.UninitializedObject)
392:                            return null;
393:                        return _processReturnValue(value);
394:                    } catch (IllegalStateException e) {
395:                        return null;
396:                    } // variable was not defined
397:                }
398:                return null;
399:            }
400:
401:            /** Gets the class name of a variable in the current interpreter.
402:             *  @param var the name of the variable
403:             */
404:            public synchronized String getVariableClassName(String var)
405:                    throws RemoteException {
406:                // Add to the default interpreter, if it is a JavaInterpreter
407:                Interpreter i = _activeInterpreter.getInterpreter();
408:                if (i instanceof  JavaInterpreter) {
409:                    try {
410:                        Class c = ((JavaInterpreter) i).getVariableClass(var);
411:                        if (c == null)
412:                            return "null";
413:                        else
414:                            return c.getName();
415:                    } catch (IllegalStateException e) {
416:                        // variable was not defined
417:                        return null;
418:                    }
419:                } else
420:                    return null;
421:            }
422:
423:            /** Adds a named DynamicJavaAdapter to list of interpreters. Presets it to contain the current accumulated classpath.
424:             *  @param name the unique name for the interpreter
425:             *  @throws IllegalArgumentException if the name is not unique
426:             */
427:            public synchronized void addJavaInterpreter(String name) {
428:                JavaInterpreter interpreter = new DynamicJavaAdapter(
429:                        _classPathManager);
430:                // Add each entry on the accumulated classpath
431:                _updateInterpreterClassPath(interpreter);
432:                addInterpreter(name, interpreter);
433:            }
434:
435:            /** Adds a named JavaDebugInterpreter to the list of interpreters.
436:             *  @param name the unique name for the interpreter
437:             *  @param className the fully qualified class name of the class the debug interpreter is in
438:             *  @throws IllegalArgumentException if the name is not unique
439:             */
440:            public synchronized void addDebugInterpreter(String name,
441:                    String className) {
442:                JavaDebugInterpreter interpreter = new JavaDebugInterpreter(
443:                        name, className);
444:                interpreter.setPrivateAccessible(true);
445:                // Add each entry on the accumulated classpath
446:                _updateInterpreterClassPath(interpreter);
447:                addInterpreter(name, interpreter);
448:            }
449:
450:            /** Adds a named interpreter to the list of interpreters.
451:             *  @param name the unique name for the interpreter
452:             *  @param interpreter the interpreter to add
453:             *  @throws IllegalArgumentException if the name is not unique
454:             */
455:            public synchronized void addInterpreter(String name,
456:                    Interpreter interpreter) {
457:                if (_interpreters.containsKey(name)) {
458:                    throw new IllegalArgumentException("'" + name
459:                            + "' is not a unique interpreter name");
460:                }
461:                _interpreters.put(name, new InterpreterData(interpreter));
462:            }
463:
464:            /** Removes the interpreter with the given name, if it exists.  Unsynchronized because _interpreters is immutable
465:             *  and its methods are thread-safe.
466:             *  @param name Name of the interpreter to remove
467:             */
468:            public void removeInterpreter(String name) {
469:                _interpreters.remove(name);
470:            }
471:
472:            /** Returns the interpreter (with metadata) with the given name
473:             *  @param name the unique name of the desired interpreter
474:             *  @throws IllegalArgumentException if no such named interpreter exists
475:             */
476:            InterpreterData getInterpreter(String name) {
477:                InterpreterData interpreter = _interpreters.get(name);
478:                if (interpreter != null)
479:                    return interpreter;
480:                else
481:                    throw new IllegalArgumentException("Interpreter '" + name
482:                            + "' does not exist.");
483:            }
484:
485:            /** Returns the Java interpreter with the given name
486:             *  @param name the unique name of the desired interpreter
487:             *  @throws IllegalArgumentException if no such named interpreter exists, or if the named interpreter is not a Java
488:             *          interpreter
489:             */
490:            public synchronized JavaInterpreter getJavaInterpreter(String name) {
491:                if (printMessages)
492:                    System.out.println("Getting interpreter data");
493:                InterpreterData interpreterData = getInterpreter(name);
494:                if (printMessages)
495:                    System.out.println("Getting interpreter instance");
496:                Interpreter interpreter = interpreterData.getInterpreter();
497:                if (printMessages)
498:                    System.out.println("returning");
499:
500:                if (interpreter instanceof  JavaInterpreter)
501:                    return (JavaInterpreter) interpreter;
502:                else {
503:                    throw new IllegalArgumentException("Interpreter '" + name
504:                            + "' is not a JavaInterpreter.");
505:                }
506:            }
507:
508:            /** Sets the current interpreter to be the one specified by the given name
509:             *  @param name the unique name of the interpreter to set active
510:             *  @return Whether the new interpreter is currently in progress with an interaction
511:             */
512:            public synchronized boolean setActiveInterpreter(String name) {
513:                _activeInterpreter = getInterpreter(name);
514:                return _activeInterpreter.inProgress();
515:            }
516:
517:            /** Sets the default interpreter to be active.
518:             *  @return Whether the new interpreter is currently in progress with an interaction
519:             */
520:            public synchronized boolean setToDefaultInterpreter() {
521:                _activeInterpreter = _defaultInterpreter;
522:                return _activeInterpreter.inProgress();
523:            }
524:
525:            /** Gets the hashtable containing the named interpreters.  Package private for testing purposes.
526:             *  @return said hashtable
527:             */
528:            Hashtable<String, InterpreterData> getInterpreters() {
529:                return _interpreters;
530:            }
531:
532:            /** Returns the current active interpreter.  Package private; for tests only. */
533:            Interpreter getActiveInterpreter() {
534:                return _activeInterpreter.getInterpreter();
535:            }
536:
537:            /** Gets the stack trace from the given exception, stripping off the bottom parts of the trace that are internal 
538:             *  to the interpreter.  This would be much easier to do in JDK 1.4, since you can get the stack trace frames 
539:             *  directly, instead of having to parse this!  TODO: revise this code to use the JDK 1.4+ API.
540:             */
541:            public static String getStackTrace(Throwable t) {
542:                //_dialog("before creating reader");
543:                BufferedReader reader = new BufferedReader(new StringReader(
544:                        StringOps.getStackTrace(t)));
545:
546:                //_dialog("after creating reader");
547:                LinkedList<String> traceItems = new LinkedList<String>();
548:                try {
549:                    // we will generate list of trace items
550:                    // skip the first one since it's just the message
551:                    //_dialog("before first readLine");
552:                    reader.readLine();
553:                    //_dialog("after first readLine");
554:
555:                    String s;
556:                    while ((s = reader.readLine()) != null) {
557:                        //_dialog("read: " + s);
558:                        traceItems.add(s);
559:                    }
560:                } catch (IOException ioe) {
561:                    return "Unable to get stack trace";
562:                }
563:
564:                // OK, now we crop off everything after the first "koala.dynamicjava." or "edu.rice.cs.drjava.", if there is one.
565:
566:                //  First, find the index of an occurrence.
567:                int index = -1;
568:                for (int i = 0; i < traceItems.size(); i++) {
569:                    String item = traceItems.get(i);
570:                    item = item.trim();
571:                    if (item.startsWith("at edu.rice.cs.drjava.")
572:                            || item.startsWith("at koala.dynamicjava.")) {
573:                        index = i;
574:                        break;
575:                    }
576:                }
577:
578:                // Now crop off the rest
579:                if (index > -1) {
580:                    while (traceItems.size() > index)
581:                        traceItems.removeLast();
582:                }
583:
584:                // Last check: See if there are no items left. If there are none, put one in to say it happened at top-level.
585:                if (traceItems.isEmpty())
586:                    traceItems.add(EMPTY_TRACE_TEXT);
587:
588:                // OK, now rebuild string
589:                final StringBuilder buf = new StringBuilder();
590:                final ListIterator itor = traceItems.listIterator();
591:                final String newLine = StringOps.EOL; // intended for output to system? (as opposed to Swing text)
592:                boolean first = true;
593:                while (itor.hasNext()) {
594:                    if (first)
595:                        first = false;
596:                    else
597:                        buf.append(newLine);
598:
599:                    buf.append("  " + ((String) itor.next()).trim());
600:                }
601:
602:                return buf.toString();
603:            }
604:
605:            // ---------- Java-specific methods ----------
606:
607:            /** Sets the package scope for the current active interpreter, if it is a JavaInterpreter. */
608:            public void setPackageScope(String s) {
609:                Interpreter active = _activeInterpreter.getInterpreter();
610:                if (active instanceof  JavaInterpreter) {
611:                    ((JavaInterpreter) active).setPackageScope(s);
612:                }
613:            }
614:
615:            /** @param show Whether to show a message if a reset operation fails. */
616:            public void setShowMessageOnResetFailure(boolean show) {
617:                _messageOnResetFailure = show;
618:            }
619:
620:            /** This method is called if the interpreterJVM cannot be exited (likely because of a modified security manager. */
621:            protected void quitFailed(Throwable th) { // NOT synchronized
622:                if (_messageOnResetFailure) {
623:                    String msg = "The interactions pane could not be reset:\n"
624:                            + th;
625:                    javax.swing.JOptionPane.showMessageDialog(null, msg);
626:                }
627:
628:                try {
629:                    _mainJVM.quitFailed(th);
630:                } catch (RemoteException re) {
631:                    // nothing to do
632:                    _log.log("quitFailed: " + re.toString());
633:                }
634:            }
635:
636:            /** Sets the interpreter to allow access to private members. */
637:            public synchronized void setPrivateAccessible(boolean allow) {
638:                Interpreter active = _activeInterpreter.getInterpreter();
639:                if (active instanceof  JavaInterpreter) {
640:                    ((JavaInterpreter) active).setPrivateAccessible(allow);
641:                }
642:            }
643:
644:            // ---------- JUnit methods ----------
645:            /** Sets up a JUnit test suite in the Interpreter JVM and finds which classes are really TestCases classes (by 
646:             *  loading them).  Unsynchronized because it contains a remote call and does not involve mutable local state.
647:             *  @param classNames the class names to run in a test
648:             *  @param files the associated file
649:             *  @return the class names that are actually test cases
650:             */
651:            public List<String> findTestClasses(List<String> classNames,
652:                    List<File> files) throws RemoteException {
653:                return _junitTestManager.findTestClasses(classNames, files);
654:            }
655:
656:            /** Runs JUnit test suite already cached in the Interpreter JVM.  Unsynchronized because it contains a remote call
657:             *  and does not involve mutable local state.
658:             *  @return false if no test suite is cached; true otherwise
659:             */
660:            public boolean runTestSuite() throws RemoteException {
661:                return _junitTestManager.runTestSuite();
662:            }
663:
664:            /** Notifies Main JVM that JUnit has been invoked on a non TestCase class.  Unsynchronized because it contains a 
665:             *  remote call and does not involve mutable local state.
666:             *  @param isTestAll whether or not it was a use of the test all button
667:             */
668:            public void nonTestCase(boolean isTestAll) {
669:                try {
670:                    _mainJVM.nonTestCase(isTestAll);
671:                } catch (RemoteException re) {
672:                    // nothing to do
673:                    _log.log("nonTestCase: " + re.toString());
674:                }
675:            }
676:
677:            /** Notifies the main JVM that JUnitTestManager has encountered an illegal class file.  Unsynchronized because it 
678:             *  contains a remote call and does not involve mutable local state.
679:             *  @param e the ClassFileError object describing the error on loading the file
680:             */
681:            public void classFileError(ClassFileError e) {
682:                try {
683:                    _mainJVM.classFileError(e);
684:                } catch (RemoteException re) {
685:                    // nothing to do
686:                    _log.log("classFileError: " + re.toString());
687:                }
688:            }
689:
690:            /** Notifies that a suite of tests has started running.  Unsynchronized because it contains a remote call and does
691:             *  not involve mutable local state.
692:             *  @param numTests The number of tests in the suite to be run.
693:             */
694:            public void testSuiteStarted(int numTests) {
695:                try {
696:                    _mainJVM.testSuiteStarted(numTests);
697:                } catch (RemoteException re) {
698:                    // nothing to do
699:                    _log.log("testSuiteStarted: " + re.toString());
700:                }
701:            }
702:
703:            /** Notifies that a particular test has started.  Unsynchronized because it contains a remote call and does not
704:             *  involve mutable local state.
705:             *  @param testName The name of the test being started.
706:             */
707:            public void testStarted(String testName) {
708:                try {
709:                    _mainJVM.testStarted(testName);
710:                } catch (RemoteException re) {
711:                    // nothing to do
712:                    _log.log("testStarted" + re.toString());
713:                }
714:            }
715:
716:            /** Notifies that a particular test has ended.  Unsynchronized because it contains a remote call.
717:             *  @param testName The name of the test that has ended.
718:             *  @param wasSuccessful Whether the test passed or not.
719:             *  @param causedError If not successful, whether the test caused an error or simply failed.
720:             */
721:            public void testEnded(String testName, boolean wasSuccessful,
722:                    boolean causedError) {
723:                try {
724:                    _mainJVM.testEnded(testName, wasSuccessful, causedError);
725:                } catch (RemoteException re) {
726:                    // nothing to do
727:                    _log.log("testEnded: " + re.toString());
728:                }
729:            }
730:
731:            /** Notifies that a full suite of tests has finished running.  Unsynchronized because it contains a remote call
732:             *  and does not involve mutable local state.
733:             *  @param errors The array of errors from all failed tests in the suite.
734:             */
735:            public void testSuiteEnded(JUnitError[] errors) {
736:                try {
737:                    _mainJVM.testSuiteEnded(errors);
738:                } catch (RemoteException re) {
739:                    // nothing to do
740:                    _log.log("testSuiteFinished: " + re.toString());
741:                }
742:            }
743:
744:            /** Called when the JUnitTestManager wants to open a file that is not currently open.  Unsynchronized because it 
745:             *  contains a remote call and does not involve mutable local state.
746:             *  @param className the name of the class for which we want to find the file
747:             *  @return the file associated with the given class
748:             */
749:            public File getFileForClassName(String className) {
750:                try {
751:                    return _mainJVM.getFileForClassName(className);
752:                } catch (RemoteException re) {
753:                    // nothing to do
754:                    _log.log("getFileForClassName: " + re.toString());
755:                    return null;
756:                }
757:            }
758:
759:            public void junitJVMReady() {
760:            }
761:
762:            //////////////////////////////////////////////////////////////
763:            // ALL functions regarding classpath
764:            //////////////////////////////////////////////////////////////
765:
766:            /** Adds a classpath to the given interpreter.  assumes that lock on this is held.
767:             *  @param interpreter the interpreter
768:             */
769:            protected/* synchronized */void _updateInterpreterClassPath(
770:                    JavaInterpreter interpreter) {
771:
772:                for (File f : _classPathManager.getProjectCP())
773:                    interpreter.addProjectClassPath(f);
774:
775:                for (File f : _classPathManager.getBuildDirectoryCP())
776:                    interpreter.addBuildDirectoryClassPath(f);
777:
778:                for (File f : _classPathManager.getProjectFilesCP())
779:                    interpreter.addProjectFilesClassPath(f);
780:
781:                for (File f : _classPathManager.getExternalFilesCP())
782:                    interpreter.addExternalFilesClassPath(f);
783:
784:                for (File f : _classPathManager.getExtraCP())
785:                    interpreter.addExtraClassPath(f);
786:            }
787:
788:            /** Adds the given path to the classpath shared by ALL Java interpreters.  Only unique paths are added.
789:             *  @param f  Entry to add to the accumulated classpath
790:             */
791:            public synchronized void addExtraClassPath(File f) {
792:                if (_classPath.contains(f))
793:                    return; // Don't add it again
794:
795:                // Add to the default interpreter, if it is a JavaInterpreter
796:                if (_defaultInterpreter.getInterpreter() instanceof  JavaInterpreter) {
797:                    ((JavaInterpreter) _defaultInterpreter.getInterpreter())
798:                            .addExtraClassPath(f);
799:                }
800:
801:                // Add to any named JavaInterpreters to be consistent
802:                Enumeration<InterpreterData> interpreters = _interpreters
803:                        .elements();
804:                while (interpreters.hasMoreElements()) {
805:                    Interpreter interpreter = interpreters.nextElement()
806:                            .getInterpreter();
807:                    if (interpreter instanceof  JavaInterpreter) {
808:                        ((JavaInterpreter) interpreter).addExtraClassPath(f);
809:                    }
810:                }
811:
812:                // Keep this entry on the accumulated classpath
813:                _classPath.add(f);
814:            }
815:
816:            /** Adds the given file to the classpath shared by ALL Java interpreters.  Only unique paths are added.
817:             *  @param f  Entry to add to the accumulated classpath
818:             */
819:            public synchronized void addProjectClassPath(File f) {
820:                if (_classPath.contains(f))
821:                    return; // Don't add it again
822:
823:                // Add to the default interpreter, if it is a JavaInterpreter
824:                if (_defaultInterpreter.getInterpreter() instanceof  JavaInterpreter) {
825:                    ((JavaInterpreter) _defaultInterpreter.getInterpreter())
826:                            .addProjectClassPath(f);
827:                }
828:
829:                // Add to any named JavaInterpreters to be consistent
830:                Enumeration<InterpreterData> interpreters = _interpreters
831:                        .elements();
832:                while (interpreters.hasMoreElements()) {
833:                    Interpreter interpreter = interpreters.nextElement()
834:                            .getInterpreter();
835:                    if (interpreter instanceof  JavaInterpreter) {
836:                        ((JavaInterpreter) interpreter).addProjectClassPath(f);
837:                    }
838:                }
839:
840:                // Keep this entry on the accumulated classpath
841:                _classPath.add(f);
842:            }
843:
844:            /** Adds the given path to the classpath shared by ALL Java interpreters. Only unique paths are added.
845:             *  @param f  Entry to add to the accumulated classpath
846:             */
847:            public synchronized void addBuildDirectoryClassPath(File f) {
848:                if (_classPath.contains(f))
849:                    return; // Don't add it again
850:
851:                // Add to the default interpreter, if it is a JavaInterpreter
852:                if (_defaultInterpreter.getInterpreter() instanceof  JavaInterpreter) {
853:                    ((JavaInterpreter) _defaultInterpreter.getInterpreter())
854:                            .addBuildDirectoryClassPath(f);
855:                }
856:
857:                // Add to any named JavaInterpreters to be consistent
858:                Enumeration<InterpreterData> interpreters = _interpreters
859:                        .elements();
860:                while (interpreters.hasMoreElements()) {
861:                    Interpreter interpreter = interpreters.nextElement()
862:                            .getInterpreter();
863:                    if (interpreter instanceof  JavaInterpreter) {
864:                        ((JavaInterpreter) interpreter)
865:                                .addBuildDirectoryClassPath(f);
866:                    }
867:                }
868:
869:                // Keep this entry on the accumulated classpath
870:                _classPath.add(f);
871:            }
872:
873:            /** Adds the given path to the classpath shared by ALL Java interpreters. Only unique paths are added.
874:             *  @param f  Entry to add to the accumulated classpath
875:             */
876:            public synchronized void addProjectFilesClassPath(File f) {
877:                if (_classPath.contains(f))
878:                    return; // Don't add it again
879:
880:                // Add to the default interpreter, if it is a JavaInterpreter
881:                if (_defaultInterpreter.getInterpreter() instanceof  JavaInterpreter) {
882:                    ((JavaInterpreter) _defaultInterpreter.getInterpreter())
883:                            .addProjectFilesClassPath(f);
884:                }
885:
886:                // Add to any named JavaInterpreters to be consistent
887:                Enumeration<InterpreterData> interpreters = _interpreters
888:                        .elements();
889:                while (interpreters.hasMoreElements()) {
890:                    Interpreter interpreter = interpreters.nextElement()
891:                            .getInterpreter();
892:                    if (interpreter instanceof  JavaInterpreter) {
893:                        ((JavaInterpreter) interpreter)
894:                                .addProjectFilesClassPath(f);
895:                    }
896:                }
897:
898:                // Keep this entry on the accumulated classpath
899:                _classPath.add(f);
900:            }
901:
902:            /** Adds the given path to the classpath shared by ALL Java interpreters. Only unique paths are added.
903:             * @param f  Entry to add to the accumulated classpath
904:             */
905:            public synchronized void addExternalFilesClassPath(File f) {
906:                if (_classPath.contains(f))
907:                    return; // Don't add it again
908:
909:                // Add to the default interpreter, if it is a JavaInterpreter
910:                if (_defaultInterpreter.getInterpreter() instanceof  JavaInterpreter) {
911:                    ((JavaInterpreter) _defaultInterpreter.getInterpreter())
912:                            .addExternalFilesClassPath(f);
913:                }
914:
915:                // Add to any named JavaInterpreters to be consistent
916:                Enumeration<InterpreterData> interpreters = _interpreters
917:                        .elements();
918:                while (interpreters.hasMoreElements()) {
919:                    Interpreter interpreter = interpreters.nextElement()
920:                            .getInterpreter();
921:                    if (interpreter instanceof  JavaInterpreter) {
922:                        ((JavaInterpreter) interpreter)
923:                                .addExternalFilesClassPath(f);
924:                    }
925:                }
926:
927:                // Keep this entry on the accumulated classpath
928:                _classPath.add(f);
929:            }
930:
931:            public synchronized Iterable<File> getClassPath() {
932:                Iterable<File> result = IterUtil.empty();
933:                result = IterUtil.compose(result, _classPathManager
934:                        .getProjectCP());
935:                result = IterUtil.compose(result, _classPathManager
936:                        .getBuildDirectoryCP());
937:                result = IterUtil.compose(result, _classPathManager
938:                        .getProjectFilesCP());
939:                result = IterUtil.compose(result, _classPathManager
940:                        .getExternalFilesCP());
941:                result = IterUtil.compose(result, _classPathManager
942:                        .getExtraCP());
943:                return result;
944:            }
945:
946:            public List<File> getAugmentedClassPath() {
947:                return IterUtil.asList(getClassPath());
948:            }
949:
950:        }
951:
952:        /** Bookkeeping class to maintain information about each interpreter, such as whether it is currently in progress. */
953:        class InterpreterData {
954:            protected final Interpreter _interpreter;
955:            protected volatile boolean _inProgress;
956:
957:            InterpreterData(Interpreter interpreter) {
958:                _interpreter = interpreter;
959:                _inProgress = false;
960:            }
961:
962:            // The following methods do not need to be synchronized because they access or set volatile fields.
963:
964:            /** Gets the interpreter. */
965:            public Interpreter getInterpreter() {
966:                return _interpreter;
967:            }
968:
969:            /** Returns whether this interpreter is currently in progress with an interaction. */
970:            public boolean inProgress() {
971:                return _inProgress;
972:            }
973:
974:            /** Sets whether this interpreter is currently in progress. */
975:            public void setInProgress(boolean inProgress) {
976:                _inProgress = inProgress;
977:            }
978:        }
w_w__w.ja___v_a__2s__.___c_om_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.