edu.rice.cs.drjava.model.repl.newjvm
Class InterpreterJVM

java.lang.Object
  extended by edu.rice.cs.util.newjvm.AbstractSlaveJVM
      extended by edu.rice.cs.drjava.model.repl.newjvm.InterpreterJVM
All Implemented Interfaces:
JUnitModelCallback, InterpreterJVMRemoteI, SlaveRemote, Remote

public class InterpreterJVM
extends AbstractSlaveJVM
implements InterpreterJVMRemoteI, JUnitModelCallback

This is the main class for the interpreter JVM. All public methods except those involving remote calls (callbacks) use synchronizazion on _stateLock (unless synchronization has no effect). The class is not ready for remote calls until handleStart has been executed. This class is loaded in the Interpreter JVM, not the Main JVM. (Do not use DrJava's config framework here.)

Note that this class is specific to DynamicJava. It must be refactored to accommodate other interpreters.

Version:
$Id: InterpreterJVM.java 5445 2011-08-17 20:32:57Z rcartwright $

Nested Class Summary
private static class InterpreterJVM.DebugMethodContext
          A custom context for interpreting within the body of a defined method.
 
Field Summary
private  Pair<String,Interpreter> _activeInterpreter
           
private  Set<Interpreter> _busyInterpreters
           
private  ClassPathManager _classPathManager
           
private  Interpreter _defaultInterpreter
           
private  ClassLoader _interpreterLoader
           
private  InteractionsPaneOptions _interpreterOptions
           
private  Map<String,Interpreter> _interpreters
           
private  JUnitTestManager _junitTestManager
          Responsible for running JUnit tests in this JVM.
private  MainJVMRemoteI _mainJVM
          Remote reference to the MainJVM class in DrJava's primary JVM.
private  Object _stateLock
           
static InterpreterJVM ONLY
          Singleton instance of this class.
 
Fields inherited from class edu.rice.cs.util.newjvm.AbstractSlaveJVM
CHECK_MAIN_VM_ALIVE_SECONDS
 
Constructor Summary
private InterpreterJVM()
          Private constructor; use the singleton ONLY instance.
 
Method Summary
 void addBuildDirectoryClassPath(File f)
          Adds the given path to the class path shared by ALL Java interpreters.
private  boolean addBusyInterpreter(Interpreter i)
           
 void addExternalFilesClassPath(File f)
          Adds the given path to the class path shared by ALL Java interpreters.
 void addExtraClassPath(File f)
          Adds the given path to the class path shared by ALL Java interpreters.
 void addInterpreter(String name)
          Adds a named Interpreter to the list.
 void addInterpreter(String name, Object thisVal, Class<?> thisClass, Object[] localVars, String[] localVarNames, Class<?>[] localVarClasses)
          Adds a named Interpreter in the given environment to the list.
 void addProjectClassPath(File f)
          Adds the given path to the class path shared by ALL Java interpreters.
 void addProjectFilesClassPath(File f)
          Adds the given path to the class path shared by ALL Java interpreters.
 void classFileError(ClassFileError e)
          Notifies the main JVM that JUnitTestManager has encountered an illegal class file.
 List<String> findTestClasses(List<String> classNames, List<File> files)
          Sets up a JUnit test suite in the Interpreter JVM and finds which classes are really TestCases classes (by loading them).
static String getClassName(Class<?> c)
           
 Iterable<File> getClassPath()
          Returns the current class path.
 File getFileForClassName(String className)
          Called when the JUnitTestManager wants to open a file that is not currently open.
private  Interpreter getInterpreter(String name)
           
 Pair<Object,String>[] getVariable(String var)
          Gets the value and type string of the variable with the given name in the current interpreter.
 Pair<String,String> getVariableToString(String var)
          Gets the string representation of the value of a variable in the current interpreter.
 Object[] getVariableValue(String var)
          Gets the value of the variable with the given name in the current interpreter.
protected  void handleStart(MasterRemote mainJVM)
          Actions to perform when this JVM is started (through its superclass, AbstractSlaveJVM).
 InterpretResult interpret(String s)
          Interprets the given string of source code in the active interpreter.
private  InterpretResult interpret(String input, Interpreter interpreter)
           
 InterpretResult interpret(String s, String name)
          Interprets the given string of source code with the given interpreter.
private  boolean isBusyInterpreter(Interpreter i)
           
private  boolean isInterpreterName(String name)
           
 void junitJVMReady()
          Called when the JVM used for unit tests has registered.
 void nonTestCase(boolean isTestAll, boolean didCompileFail)
          Notifies Main JVM that JUnit has been invoked on a non TestCase class.
private  Interpreter putInterpreter(String name, Interpreter i)
           
private  boolean removeBusyInterpreter(Interpreter i)
           
 void removeInterpreter(String name)
          Removes the interpreter with the given name, if it exists.
 boolean runTestSuite()
          Runs JUnit test suite already cached in the Interpreter JVM.
 Pair<Boolean,Boolean> setActiveInterpreter(String name)
          Sets the current interpreter to be the one specified by the given name
 void setEnforceAllAccess(boolean enforce)
          Check that all access of class members is permitted by accessibility controls.
 void setEnforcePrivateAccess(boolean enforce)
          Check that access of private class members is permitted (irrelevant if setEnforceAllAccess() is set to true).
 void setRequireSemicolon(boolean require)
          Require a semicolon at the end of statements.
 void setRequireVariableType(boolean require)
          Require variable declarations to include an explicit type.
 Pair<Boolean,Boolean> setToDefaultInterpreter()
          Sets the default interpreter to be active.
 void testEnded(String testName, boolean wasSuccessful, boolean causedError)
          Notifies that a particular test has ended.
 void testStarted(String testName)
          Notifies that a particular test has started.
 void testSuiteEnded(JUnitError[] errors)
          Notifies that a full suite of tests has finished running.
 void testSuiteStarted(int numTests)
          Notifies that a suite of tests has started running.
 
Methods inherited from class edu.rice.cs.util.newjvm.AbstractSlaveJVM
beforeQuit, quit, start
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface edu.rice.cs.util.newjvm.SlaveRemote
quit, start
 

Field Detail

ONLY

public static final InterpreterJVM ONLY
Singleton instance of this class.


_interpreterOptions

private final InteractionsPaneOptions _interpreterOptions

_activeInterpreter

private volatile Pair<String,Interpreter> _activeInterpreter

_defaultInterpreter

private final Interpreter _defaultInterpreter

_interpreters

private final Map<String,Interpreter> _interpreters

_busyInterpreters

private final Set<Interpreter> _busyInterpreters

_classPathManager

private final ClassPathManager _classPathManager

_interpreterLoader

private final ClassLoader _interpreterLoader

_stateLock

private final Object _stateLock

_junitTestManager

private final JUnitTestManager _junitTestManager
Responsible for running JUnit tests in this JVM.


_mainJVM

private volatile MainJVMRemoteI _mainJVM
Remote reference to the MainJVM class in DrJava's primary JVM. Assigned ONLY once.

Constructor Detail

InterpreterJVM

private InterpreterJVM()
Private constructor; use the singleton ONLY instance.

Method Detail

handleStart

protected void handleStart(MasterRemote mainJVM)
Actions to perform when this JVM is started (through its superclass, AbstractSlaveJVM). Not synchronized because "this" is not initialized for general access until this method has run.

Specified by:
handleStart in class AbstractSlaveJVM

getInterpreter

private Interpreter getInterpreter(String name)

isInterpreterName

private boolean isInterpreterName(String name)

putInterpreter

private Interpreter putInterpreter(String name,
                                   Interpreter i)

removeInterpreter

public void removeInterpreter(String name)
Description copied from interface: InterpreterJVMRemoteI
Removes the interpreter with the given name, if it exists.

Specified by:
removeInterpreter in interface InterpreterJVMRemoteI
Parameters:
name - Name of the interpreter to remove

addBusyInterpreter

private boolean addBusyInterpreter(Interpreter i)

removeBusyInterpreter

private boolean removeBusyInterpreter(Interpreter i)

isBusyInterpreter

private boolean isBusyInterpreter(Interpreter i)

interpret

public InterpretResult interpret(String s)
Interprets the given string of source code in the active interpreter. The result is returned to MainJVM via the interpretResult method. No synchronization necessary; the code only contains a single read of local state.

Specified by:
interpret in interface InterpreterJVMRemoteI
Parameters:
s - Source code to interpret.

interpret

public InterpretResult interpret(String s,
                                 String name)
Interprets the given string of source code with the given interpreter. The result is returned to MainJVM via the interpretResult method.

Parameters:
s - Source code to interpret.
interpreterName - Name of the interpreter to use
Throws:
IllegalArgumentException - if the named interpreter does not exist

interpret

private InterpretResult interpret(String input,
                                  Interpreter interpreter)

getVariableValue

public Object[] getVariableValue(String var)
Gets the value of the variable with the given name in the current interpreter. Invoked reflectively by the debugger. To simplify the inter-process exchange, an array here is used as the return type rather than an Option<Object> -- an empty array corresponds to "none," and a singleton array corresponds to a "some."

Parameters:
var - name of the variable to look up
Returns:
empty array for "none", singleton array for "some" value
See Also:
JPDADebugger.GET_VARIABLE_VALUE_SIG, JPDADebugger._copyVariablesFromInterpreter()

getVariable

public Pair<Object,String>[] getVariable(String var)
Gets the value and type string of the variable with the given name in the current interpreter. Invoked reflectively by the debugger. To simplify the inter-process exchange, an array here is used as the return type rather than an Option<Object> -- an empty array corresponds to "none," and a singleton array corresponds to a "some."


getVariableToString

public Pair<String,String> getVariableToString(String var)
Gets the string representation of the value of a variable in the current interpreter.

Specified by:
getVariableToString in interface InterpreterJVMRemoteI
Parameters:
var - the name of the variable
Returns:
null if the variable is not defined; the first part of the pair is "null" if the value is null, otherwise its string representation; the second part is the string representation of the variable's type

getClassName

public static String getClassName(Class<?> c)
Returns:
the name of the class, with the right number of array suffixes "[]" and while being ambiguous about boxed and primitive types.

addInterpreter

public void addInterpreter(String name)
Adds a named Interpreter to the list.

Specified by:
addInterpreter in interface InterpreterJVMRemoteI
Parameters:
name - the unique name for the interpreter
Throws:
IllegalArgumentException - if the name is not unique

addInterpreter

public void addInterpreter(String name,
                           Object thisVal,
                           Class<?> thisClass,
                           Object[] localVars,
                           String[] localVarNames,
                           Class<?>[] localVarClasses)
Adds a named Interpreter in the given environment to the list. Invoked reflectively by the debugger.

Parameters:
name - The unique name for the interpreter
thisVal - The value of this (may be null, implying this is a static context)
thisClass - The class in whose context the interpreter is to be created
localVars - Values of local variables
localVarNames - Names of the local variables
localVarClasses - Classes of the local variables. To simplify the work callers must do, a value with a primitive type may have a null entry here.
Throws:
IllegalArgumentException - if the name is not unique, or if the local var arrays are not all of the same length
See Also:
JPDADebugger.ADD_INTERPRETER_SIG, JPDADebugger._dumpVariablesIntoInterpreterAndSwitch()

setActiveInterpreter

public Pair<Boolean,Boolean> setActiveInterpreter(String name)
Sets the current interpreter to be the one specified by the given name

Specified by:
setActiveInterpreter in interface InterpreterJVMRemoteI
Parameters:
name - the unique name of the interpreter to set active
Returns:
Status flags: whether the current interpreter changed, and whether it is busy

setToDefaultInterpreter

public Pair<Boolean,Boolean> setToDefaultInterpreter()
Sets the default interpreter to be active.

Specified by:
setToDefaultInterpreter in interface InterpreterJVMRemoteI
Returns:
Status flags: whether the current interpreter changed, and whether it is busy

setEnforceAllAccess

public void setEnforceAllAccess(boolean enforce)
Check that all access of class members is permitted by accessibility controls.

Specified by:
setEnforceAllAccess in interface InterpreterJVMRemoteI

setEnforcePrivateAccess

public void setEnforcePrivateAccess(boolean enforce)
Check that access of private class members is permitted (irrelevant if setEnforceAllAccess() is set to true).

Specified by:
setEnforcePrivateAccess in interface InterpreterJVMRemoteI

setRequireSemicolon

public void setRequireSemicolon(boolean require)
Require a semicolon at the end of statements.

Specified by:
setRequireSemicolon in interface InterpreterJVMRemoteI

setRequireVariableType

public void setRequireVariableType(boolean require)
Require variable declarations to include an explicit type.

Specified by:
setRequireVariableType in interface InterpreterJVMRemoteI

findTestClasses

public List<String> findTestClasses(List<String> classNames,
                                    List<File> files)
                             throws RemoteException
Sets up a JUnit test suite in the Interpreter JVM and finds which classes are really TestCases classes (by loading them). Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
findTestClasses in interface InterpreterJVMRemoteI
Parameters:
classNames - the class names to run in a test
files - the associated file
Returns:
the class names that are actually test cases
Throws:
RemoteException

runTestSuite

public boolean runTestSuite()
                     throws RemoteException
Runs JUnit test suite already cached in the Interpreter JVM. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
runTestSuite in interface InterpreterJVMRemoteI
Returns:
false if no test suite is cached; true otherwise
Throws:
RemoteException

nonTestCase

public void nonTestCase(boolean isTestAll,
                        boolean didCompileFail)
Notifies Main JVM that JUnit has been invoked on a non TestCase class. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
nonTestCase in interface JUnitModelCallback
Parameters:
isTestAll - whether or not it was a use of the test all button
didCompileFail - whether or not a compile before this JUnit attempt failed

classFileError

public void classFileError(ClassFileError e)
Notifies the main JVM that JUnitTestManager has encountered an illegal class file. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
classFileError in interface JUnitModelCallback
Parameters:
e - the ClassFileError object describing the error on loading the file

testSuiteStarted

public void testSuiteStarted(int numTests)
Notifies that a suite of tests has started running. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
testSuiteStarted in interface JUnitModelCallback
Parameters:
numTests - The number of tests in the suite to be run.

testStarted

public void testStarted(String testName)
Notifies that a particular test has started. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
testStarted in interface JUnitModelCallback
Parameters:
testName - The name of the test being started.

testEnded

public void testEnded(String testName,
                      boolean wasSuccessful,
                      boolean causedError)
Notifies that a particular test has ended. Unsynchronized because it contains a remote call.

Specified by:
testEnded in interface JUnitModelCallback
Parameters:
testName - The name of the test that has ended.
wasSuccessful - Whether the test passed or not.
causedError - If not successful, whether the test caused an error or simply failed.

testSuiteEnded

public void testSuiteEnded(JUnitError[] errors)
Notifies that a full suite of tests has finished running. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
testSuiteEnded in interface JUnitModelCallback
Parameters:
errors - The array of errors from all failed tests in the suite.

getFileForClassName

public File getFileForClassName(String className)
Called when the JUnitTestManager wants to open a file that is not currently open. Unsynchronized because it contains a remote call and does not involve mutable local state.

Specified by:
getFileForClassName in interface JUnitModelCallback
Parameters:
className - the name of the class for which we want to find the file
Returns:
the file associated with the given class

junitJVMReady

public void junitJVMReady()
Description copied from interface: JUnitModelCallback
Called when the JVM used for unit tests has registered.

Specified by:
junitJVMReady in interface JUnitModelCallback

addExtraClassPath

public void addExtraClassPath(File f)
Description copied from interface: InterpreterJVMRemoteI
Adds the given path to the class path shared by ALL Java interpreters. Only unique paths are added.

Specified by:
addExtraClassPath in interface InterpreterJVMRemoteI
Parameters:
f - Entry to add to the accumulated class path

addProjectClassPath

public void addProjectClassPath(File f)
Description copied from interface: InterpreterJVMRemoteI
Adds the given path to the class path shared by ALL Java interpreters. Only unique paths are added.

Specified by:
addProjectClassPath in interface InterpreterJVMRemoteI
Parameters:
f - Entry to add to the accumulated class path

addBuildDirectoryClassPath

public void addBuildDirectoryClassPath(File f)
Description copied from interface: InterpreterJVMRemoteI
Adds the given path to the class path shared by ALL Java interpreters. Only unique paths are added.

Specified by:
addBuildDirectoryClassPath in interface InterpreterJVMRemoteI
Parameters:
f - Entry to add to the accumulated class path

addProjectFilesClassPath

public void addProjectFilesClassPath(File f)
Description copied from interface: InterpreterJVMRemoteI
Adds the given path to the class path shared by ALL Java interpreters. Only unique paths are added.

Specified by:
addProjectFilesClassPath in interface InterpreterJVMRemoteI
Parameters:
f - Entry to add to the accumulated class path

addExternalFilesClassPath

public void addExternalFilesClassPath(File f)
Description copied from interface: InterpreterJVMRemoteI
Adds the given path to the class path shared by ALL Java interpreters. Only unique paths are added.

Specified by:
addExternalFilesClassPath in interface InterpreterJVMRemoteI
Parameters:
f - Entry to add to the accumulated class path

getClassPath

public Iterable<File> getClassPath()
Description copied from interface: InterpreterJVMRemoteI
Returns the current class path.

Specified by:
getClassPath in interface JUnitModelCallback
Specified by:
getClassPath in interface InterpreterJVMRemoteI