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

java.lang.Object
  |
  +--java.rmi.server.RemoteObject
        |
        +--java.rmi.server.RemoteServer
              |
              +--java.rmi.server.UnicastRemoteObject
                    |
                    +--edu.rice.cs.drjava.model.repl.newjvm.MainJVM
All Implemented Interfaces:
MainJVMRemoteI, Remote, Serializable
Direct Known Subclasses:
NewJVMTest.TestJVMExtension

public class MainJVM
extends UnicastRemoteObject
implements MainJVMRemoteI

Manages a remote JVM.

Version:
$Id: MainJVM.java,v 1.26 2002/09/13 22:55:34 csreis Exp $
See Also:
Serialized Form

Inner Class Summary
private  class MainJVM.RestartThread
           
 
Field Summary
private  String _identifier
          The name of the RMI object for the present JVM.
private  InterpreterJVMRemoteI _interpreterJVM
          This is the pointer to the interpreter JVM remote object, used to call back to it.
private  Process _interpreterProcess
          Process object for the running interpreter, or null if none.
private  GlobalModel _model
          The global model.
private  MainJVM.RestartThread _restartThread
           
private  Timer _restartTimer
           
private static int _rmiPort
          Port on which RMI registry is running.
private  boolean _startupInProgress
          Is there a JVM in the process of starting up? This variable is protected by synchronized(this).
private  MainJVM.RestartThread _timerThread
           
private static int RESET_TIME_OUT
          How long to wait for an interpreter to register itself before starting another attempt.
 
Fields inherited from class java.rmi.server.UnicastRemoteObject
csf, port, portFactoryParamTypes, portParamTypes, serialVersionUID, ssf
 
Fields inherited from class java.rmi.server.RemoteServer
log, logname
 
Fields inherited from class java.rmi.server.RemoteObject
ref
 
Constructor Summary
MainJVM(GlobalModel model)
          Creates a new MainJVM to handle communication with the Interpreter JVM, and instantiates the Interpreter JVM.
MainJVM(GlobalModel model, int rmiPort)
          Creates a new MainJVM to handle communication with the Interpreter JVM, and instantiates the Interpreter JVM.
MainJVM(int rmiPort)
          Creates a MainJVM without a model.
 
Method Summary
private  String _createIdentifier()
          Returns a unique identifier to name this Main JVM.
private static int _generateSafeRMIPort()
          Returns a unique port to be safely used for RMI.
private  void _startNameServiceIfNeeded()
          Creates a new RMI registry for this copy on the current rmi port, if it is not already running.
private  void _stopTimerThread()
           
private  void _threwException(Throwable t)
           
(package private) static void ()
           
 void addClassPath(String path)
           
protected  boolean allowAssertions()
          Return whether to allow assertions in the InterpreterJVM.
 void checkStillAlive()
          Returns whether we are in the process of cleanly resetting the interactions JVM.
 void ensureInterpreterConnected()
          If an interpreter has not registered itself, this method will block until one does.
protected  int getDebugPort()
          Returns the debug port to use, as specified by the model.
 String getIdentifier()
           
 void interpret(String s)
           
 void killInterpreter()
           
 void nonTestCase()
           
 void registerInterpreterJVM(InterpreterJVMRemoteI remote)
          Registers the interpreter JVM for later callbacks.
protected  void replCalledSystemExit(int status)
          Action to take if the Repl tries to exit.
 void reset()
           
 void restartInterpreterJVM()
          Kills current interpreter JVM if any, then starts a new one.
 void returnedResult(String result)
          Signifies that the most recent interpretation completed successfully, returning a value.
 void returnedVoid()
          Signifies that the most recent interpretation completed successfully, returning no value.
 void runTest(String className, String fileName)
           
 void setModel(GlobalModel model)
          For test cases, we reuse the same MainJVM for efficiency.
 void setPackageScope(String packageName)
           
 void systemErrPrint(String s)
           
 void systemOutPrint(String s)
           
 void testFinished(JUnitError[] errors)
           
 void threwException(String exceptionClass, String message, String stackTrace)
          Signifies that the most recent interpretation was ended due to an exception being thrown.
 
Methods inherited from class java.rmi.server.UnicastRemoteObject
clone, exportObject, exportObject, exportObject, exportObject, readObject, reexport, unexportObject
 
Methods inherited from class java.rmi.server.RemoteServer
getClientHost, getLog, setLog
 
Methods inherited from class java.rmi.server.RemoteObject
equals, getRef, hashCode, toString, toStub, writeObject
 
Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, registerNatives, wait, wait, wait
 

Field Detail

_identifier

private final String _identifier
The name of the RMI object for the present JVM.

RESET_TIME_OUT

private static final int RESET_TIME_OUT
How long to wait for an interpreter to register itself before starting another attempt.

_rmiPort

private static int _rmiPort
Port on which RMI registry is running. Static because we only need one RMI registry port per JVM. Starts at a unique port, but defaults to the default RMI port (1099) if one cannot be found.

_model

private GlobalModel _model
The global model. This field might be null if the MainJVM is running in a test, but will never be null in actual use.

_startupInProgress

private boolean _startupInProgress
Is there a JVM in the process of starting up? This variable is protected by synchronized(this).

_restartThread

private MainJVM.RestartThread _restartThread

_timerThread

private MainJVM.RestartThread _timerThread

_restartTimer

private Timer _restartTimer

_interpreterJVM

private InterpreterJVMRemoteI _interpreterJVM
This is the pointer to the interpreter JVM remote object, used to call back to it. It has the value null when the interpeter JVM is not running or is not connected yet. It gets set to a value by registerInterpreterJVM(edu.rice.cs.drjava.model.repl.newjvm.InterpreterJVMRemoteI), which is called by the interpreter JVM itself over RMI. This can only be changed while holding the object lock.

_interpreterProcess

private Process _interpreterProcess
Process object for the running interpreter, or null if none. This can only be changed while holding the object lock.
Constructor Detail

MainJVM

public MainJVM(GlobalModel model)
        throws RemoteException
Creates a new MainJVM to handle communication with the Interpreter JVM, and instantiates the Interpreter JVM. Uses RMI over a unique port to communicate.
Parameters:
model - GlobalModel wishing to communicate with the Interpreter.

MainJVM

public MainJVM(GlobalModel model,
               int rmiPort)
        throws RemoteException
Creates a new MainJVM to handle communication with the Interpreter JVM, and instantiates the Interpreter JVM. Uses RMI over the given port to communicate.
Parameters:
model - GlobalModel wishing to communicate with the Interpreter.
rmiPort - Port on which to start the RMI registry. If -1, then a unique port will be used.

MainJVM

public MainJVM(int rmiPort)
        throws RemoteException
Creates a MainJVM without a model.
Parameters:
port - on which to run the RMI registry, or -1 for a unique port.
Method Detail

static void ()

setModel

public void setModel(GlobalModel model)
For test cases, we reuse the same MainJVM for efficiency. This method is used to retarget the model pointer. Note: This feature should only be used for test cases! Otherwise we're all better off making a new MainJVM when we need it.

interpret

public void interpret(String s)

addClassPath

public void addClassPath(String path)

setPackageScope

public void setPackageScope(String packageName)

reset

public void reset()

getIdentifier

public String getIdentifier()

systemErrPrint

public void systemErrPrint(String s)
                    throws RemoteException
Specified by:
systemErrPrint in interface MainJVMRemoteI

systemOutPrint

public void systemOutPrint(String s)
                    throws RemoteException
Specified by:
systemOutPrint in interface MainJVMRemoteI

registerInterpreterJVM

public void registerInterpreterJVM(InterpreterJVMRemoteI remote)
                            throws RemoteException
Registers the interpreter JVM for later callbacks.
Specified by:
registerInterpreterJVM in interface MainJVMRemoteI
Parameters:
remote - The interpreter JVM controller.

returnedVoid

public void returnedVoid()
                  throws RemoteException
Signifies that the most recent interpretation completed successfully, returning no value.
Specified by:
returnedVoid in interface MainJVMRemoteI

returnedResult

public void returnedResult(String result)
                    throws RemoteException
Signifies that the most recent interpretation completed successfully, returning a value.
Specified by:
returnedResult in interface MainJVMRemoteI
Parameters:
result - The .toString-ed version of the value that was returned by the interpretation. We must return the String form because returning the Object directly would require the data type to be serializable.

threwException

public void threwException(String exceptionClass,
                           String message,
                           String stackTrace)
                    throws RemoteException
Signifies that the most recent interpretation was ended due to an exception being thrown.
Specified by:
threwException in interface MainJVMRemoteI
Parameters:
exceptionClass - The name of the class of the thrown exception
message - The exception's message
stackTrace - The stack trace of the exception

killInterpreter

public void killInterpreter()

restartInterpreterJVM

public void restartInterpreterJVM()
Kills current interpreter JVM if any, then starts a new one. It turns out that before I added the _startupInProgress guard, we were starting up two jvms in quick succession sometimes. This caused nasty problems (sometimes, it was a timing thing!) if the addClasspath issued after an abort went to the first JVM but then future interpretations went to the second JVM! So, we can make restartInterpreterJVM safe for duplicate calls by just not starting another if the previous one is in the process of starting up.

_stopTimerThread

private void _stopTimerThread()

getDebugPort

protected int getDebugPort()
Returns the debug port to use, as specified by the model. Returns -1 if no usable port could be found.

allowAssertions

protected boolean allowAssertions()
Return whether to allow assertions in the InterpreterJVM.

replCalledSystemExit

protected void replCalledSystemExit(int status)
Action to take if the Repl tries to exit.
Parameters:
status - Exit code from the interpreter JVM

checkStillAlive

public void checkStillAlive()
                     throws RemoteException
Returns whether we are in the process of cleanly resetting the interactions JVM.
Specified by:
checkStillAlive in interface MainJVMRemoteI
See Also:
private synchronized boolean _isResetting() { //DrJava.consoleOut().println("isResetting: resetInProgress: " + _resetInProgress); return _resetInProgress; }

_threwException

private void _threwException(Throwable t)

ensureInterpreterConnected

public void ensureInterpreterConnected()
If an interpreter has not registered itself, this method will block until one does.

_generateSafeRMIPort

private static int _generateSafeRMIPort()
Returns a unique port to be safely used for RMI.

_startNameServiceIfNeeded

private void _startNameServiceIfNeeded()
Creates a new RMI registry for this copy on the current rmi port, if it is not already running.

_createIdentifier

private String _createIdentifier()
Returns a unique identifier to name this Main JVM.

runTest

public void runTest(String className,
                    String fileName)

nonTestCase

public void nonTestCase()
                 throws RemoteException
Specified by:
nonTestCase in interface MainJVMRemoteI

testFinished

public void testFinished(JUnitError[] errors)
                  throws RemoteException
Specified by:
testFinished in interface MainJVMRemoteI