1 33 34 package edu.rice.cs.drjava.model.repl.newjvm; 35 36 import java.rmi.*; 37 import java.io.*; 38 import java.net.URL ; 39 import java.net.MalformedURLException ; 40 41 import java.util.List ; 42 import java.util.ArrayList ; 43 44 import edu.rice.cs.drjava.DrJava; 47 import edu.rice.cs.drjava.config.OptionConstants; 48 import edu.rice.cs.drjava.model.GlobalModel; 49 import edu.rice.cs.drjava.model.repl.*; 50 import edu.rice.cs.drjava.model.junit.JUnitError; 51 import edu.rice.cs.drjava.model.junit.JUnitModelCallback; 52 import edu.rice.cs.drjava.model.debug.DebugModelCallback; 53 54 import edu.rice.cs.util.ArgumentTokenizer; 55 import edu.rice.cs.util.ClassPathVector; 56 import edu.rice.cs.util.FileOps; 57 import edu.rice.cs.util.Log; 58 import edu.rice.cs.util.StringOps; 59 import edu.rice.cs.util.UnexpectedException; 60 import edu.rice.cs.plt.io.IOUtil; 61 62 import edu.rice.cs.util.newjvm.*; 63 import edu.rice.cs.util.classloader.ClassFileError; 64 import edu.rice.cs.util.swing.Utilities; 65 import edu.rice.cs.util.swing.ScrollableDialog; 66 import koala.dynamicjava.parser.wrapper.*; 67 68 71 public class MainJVM extends AbstractMasterJVM implements MainJVMRemoteI { 72 73 private static final String SLAVE_CLASS_NAME = "edu.rice.cs.drjava.model.repl.newjvm.InterpreterJVM"; 74 75 public static final String DEFAULT_INTERPRETER_NAME = "DEFAULT"; 76 77 79 80 private volatile File _workDir; 81 82 83 private volatile InteractionsModelCallback _interactionsModel; 84 85 86 private volatile JUnitModelCallback _junitModel; 87 88 89 private volatile DebugModelCallback _debugModel; 90 91 92 private final Object _interpreterLock = new Object (); 93 94 95 private volatile boolean _slaveJVMUsed = false; 96 97 98 private volatile boolean _restart = true; 99 100 103 private volatile boolean _cleanlyRestarting = false; 104 105 106 private final ResultHandler _handler = new ResultHandler(); 107 108 109 private volatile boolean _allowAssertions = false; 110 111 112 private volatile Iterable <File> _startupClassPath; 113 114 115 private volatile List <String > _optionArgs; 116 117 118 private volatile String _currentInterpreterName = DEFAULT_INTERPRETER_NAME; 119 120 124 public MainJVM(File wd) { 125 super(SLAVE_CLASS_NAME); 126 _workDir = wd; 128 _waitForQuitThreadName = "Wait for Interactions to Exit Thread"; 129 131 _interactionsModel = new DummyInteractionsModel(); 132 _junitModel = new DummyJUnitModel(); 133 _debugModel = new DummyDebugModel(); 134 _startupClassPath = IOUtil.attemptCanonicalFiles(IOUtil.parsePath(System.getProperty("java.class.path"))); 135 _optionArgs = new ArrayList <String >(); 136 } 137 138 public boolean isInterpreterRunning() { return _interpreterJVM() != null; } 139 140 public boolean slaveJVMUsed() { return _slaveJVMUsed; } 141 142 143 public void setInteractionsModel(InteractionsModelCallback model) { _interactionsModel = model; } 144 145 146 public void setJUnitModel(JUnitModelCallback model) { _junitModel = model; } 147 148 151 public void setDebugModel(DebugModelCallback model) { _debugModel = model; } 152 153 154 public void setAllowAssertions(boolean allow) { _allowAssertions = allow; } 155 156 159 public void setOptionArgs(String argString) { _optionArgs = ArgumentTokenizer.tokenize(argString); } 160 161 163 public void interpret(final String s) { 164 if (! _restart) return; 166 167 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 168 169 try { 172 _log.log(this + ".interpret(" + s + ")"); 173 _slaveJVMUsed = true; 174 _interactionsModel.slaveJVMUsed(); 175 slave.interpret(s); 176 } 177 catch (java.rmi.UnmarshalException ume) { 178 _log.log(this + ".interpret threw UnmarshalException, so interpreter is dead:\n" + ume); 181 } 182 catch (RemoteException re) { _threwException(re); } 183 } 184 185 188 public String getVariableToString(String var) { 189 if (! _restart) return null; 191 192 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 193 194 try { return slave.getVariableToString(var); } 195 catch (RemoteException re) { 196 _threwException(re); 197 return null; 198 } 199 } 200 201 204 public String getVariableClassName(String var) { 205 if (! _restart) return null; 207 208 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 209 210 try { return slave.getVariableClassName(var); } 211 catch (RemoteException re) { 212 _threwException(re); 213 return null; 214 } 215 } 216 217 220 public void interpretResult(InterpretResult result) throws RemoteException { 221 try { 222 _log.log(this + ".interpretResult(" + result + ")"); 223 224 result.apply(getResultHandler()); 225 } 226 catch (Throwable t) { 227 _log.log(this + "interpretResult threw " + t.toString()); 228 } 229 } 230 231 253 public void addProjectClassPath(URL path) { 254 if (! _restart) return; 255 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 256 257 try { slave.addProjectClassPath(path.toString()); } 258 catch(RemoteException re) { _threwException(re); } 259 } 260 261 public void addBuildDirectoryClassPath(URL path) { 262 if (! _restart) return; 263 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 264 265 try { slave.addBuildDirectoryClassPath(path.toString()); } 266 catch(RemoteException re) { _threwException(re); } 267 } 268 269 public void addProjectFilesClassPath(URL path) { 270 if (! _restart) return; 271 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 272 273 try { slave.addProjectFilesClassPath(path.toString()); } 274 catch(RemoteException re) { _threwException(re); } 275 } 276 277 public void addExternalFilesClassPath(URL path) { 278 if (! _restart) return; 279 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 280 281 try { slave.addExternalFilesClassPath(path.toString()); } 282 catch(RemoteException re) { _threwException(re); } 283 } 284 285 public void addExtraClassPath(URL path) { 286 if (! _restart) return; 287 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 288 289 try { slave.addExtraClassPath(path.toString()); } 290 catch(RemoteException re) { _threwException(re); } 291 } 292 293 296 public ClassPathVector getClassPath() { 297 if (_restart) { 299 300 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 301 302 try { 303 ClassPathVector classPath = slave.getAugmentedClassPath(); for (File f : _startupClassPath) { 305 try { classPath.add(FileOps.toURL(f)); } 306 catch (MalformedURLException e) { } 307 } 308 return classPath; 309 } 310 catch (RemoteException re) { _threwException(re); return new ClassPathVector(); } 311 } 312 else { return new ClassPathVector(); } 313 } 314 315 316 319 public void setPackageScope(String packageName) { 320 if (! _restart) return; 322 323 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 324 325 try { slave.setPackageScope(packageName); } 326 catch (RemoteException re) { _threwException(re); } 327 } 328 329 330 public void setShowMessageOnResetFailure(boolean show) { 331 if (! _restart) return; 333 334 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 335 336 try { slave.setShowMessageOnResetFailure(show); } 337 catch (RemoteException re) { _threwException(re); } 338 } 339 340 343 public void systemErrPrint(String s) throws RemoteException { 344 _interactionsModel.replSystemErrPrint(s); 345 } 346 347 350 public void systemOutPrint(String s) throws RemoteException { 351 _interactionsModel.replSystemOutPrint(s); 352 } 353 354 360 public List <String > findTestClasses(List <String > classNames, List <File> files) throws RemoteException { 361 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 362 return slave.findTestClasses(classNames, files); 363 } 364 365 368 public boolean runTestSuite() throws RemoteException { 369 return _interpreterJVM().runTestSuite(); 370 } 371 372 375 public void nonTestCase(boolean isTestAll) throws RemoteException { 376 _junitModel.nonTestCase(isTestAll); 377 } 378 379 383 public void classFileError(ClassFileError e) throws RemoteException { 384 _junitModel.classFileError(e); 386 } 387 391 public void testSuiteStarted(int numTests) throws RemoteException { 392 _slaveJVMUsed = true; 393 _interactionsModel.slaveJVMUsed(); 395 _junitModel.testSuiteStarted(numTests); 396 } 397 398 401 public void testStarted(String testName) throws RemoteException { 402 _slaveJVMUsed = true; 404 _junitModel.testStarted(testName); 406 } 407 408 413 public void testEnded(String testName, boolean wasSuccessful, boolean causedError) throws RemoteException { 414 _junitModel.testEnded(testName, wasSuccessful, causedError); 415 } 416 417 420 public void testSuiteEnded(JUnitError[] errors) throws RemoteException { 421 _junitModel.testSuiteEnded(errors); 423 } 424 425 429 public File getFileForClassName(String className) throws RemoteException { 430 return _junitModel.getFileForClassName(className); 431 } 432 433 443 444 445 private InterpreterJVMRemoteI _interpreterJVM() { return (InterpreterJVMRemoteI) getSlave(); } 446 447 457 458 462 public void addJavaInterpreter(String name) { 463 if (! _restart) return; 465 466 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 467 468 try { slave.addJavaInterpreter(name); } 469 catch (RemoteException re) { _threwException(re); } 470 } 471 472 477 public void addDebugInterpreter(String name, String className) { 478 if (! _restart) return; 480 481 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 482 483 try { slave.addDebugInterpreter(name, className); } 484 catch (RemoteException re) { _threwException(re); } 485 } 486 487 490 public void removeInterpreter(String name) { 491 if (!_restart) return; 493 494 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 495 496 try { 497 slave.removeInterpreter(name); 498 if (name.equals(_currentInterpreterName)) _currentInterpreterName = null; 499 } 500 catch (RemoteException re) { _threwException(re); } 501 } 502 503 508 public boolean setActiveInterpreter(String name) { 509 if (!_restart) return false; 511 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 512 513 try { 514 boolean result = slave.setActiveInterpreter(name); 515 _currentInterpreterName = name; 516 return result; 517 } 518 catch (RemoteException re) { 519 _threwException(re); 520 return false; 521 } 522 } 523 524 528 public boolean setToDefaultInterpreter() { 529 if (! _restart) return false; 531 532 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 533 534 try { 535 boolean result = slave.setToDefaultInterpreter(); 536 _currentInterpreterName = DEFAULT_INTERPRETER_NAME; 537 return result; 538 } 539 catch (ConnectIOException ce) { 540 _log.log(this + "could not connect to the interpreterJVM after killing it. Threw " + ce); 541 return false; 542 } 543 catch (RemoteException re) { 544 _threwException(re); 545 return false; 546 } 547 } 548 549 550 public String getCurrentInterpreterName() { return _currentInterpreterName; } 551 552 558 559 public void killInterpreter(File wd) { 560 synchronized(_masterJVMLock) { 561 _workDir = wd; 563 _restart = (wd != null); 564 _cleanlyRestarting = true; 565 if (_restart) _interactionsModel.interpreterResetting(); 566 } 567 568 try { quitSlave(); } catch (RemoteException e) { 570 _log.log(this + "could not connect to the interpreterJVM while trying to kill it. Threw " + e); 571 } 572 } 573 574 577 public void setStartupClassPath(String classPath) { 578 _startupClassPath = IOUtil.attemptCanonicalFiles(IOUtil.parsePath(classPath)); 579 } 580 581 582 public void startInterpreterJVM() { 583 _log.log(this + ".startInterpreterJVM() called"); 584 if (isStartupInProgress() || isInterpreterRunning()) return; ArrayList <String > jvmArgs = new ArrayList <String >(); 589 if (allowAssertions()) jvmArgs.add("-ea"); 590 int debugPort = getDebugPort(); 591 _log.log("Main JVM starting with debug port: " + debugPort); 592 if (debugPort > -1) { 593 jvmArgs.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + debugPort); 594 jvmArgs.add("-Xdebug"); 595 jvmArgs.add("-Xnoagent"); 596 jvmArgs.add("-Djava.compiler=NONE"); 597 } 598 jvmArgs.addAll(_optionArgs); 604 String [] jvmArgsArray = new String [jvmArgs.size()]; 605 for (int i = 0; i < jvmArgs.size(); i++) { jvmArgsArray[i] = jvmArgs.get(i); } 606 607 try { 609 invokeSlave(jvmArgsArray, IOUtil.pathToString(_startupClassPath), _workDir); 612 _slaveJVMUsed = false; 613 } 614 catch (RemoteException re) { _threwException(re); } 615 catch (IOException ioe) { _threwException(ioe); } 616 } 617 618 623 protected void handleSlaveQuit(int status) { 624 if (_restart) { 628 if (! _cleanlyRestarting) _interactionsModel.interpreterResetting(); 630 startInterpreterJVM(); 632 } 633 634 if (!_cleanlyRestarting) _interactionsModel.replCalledSystemExit(status); 635 _cleanlyRestarting = false; 636 } 637 638 643 protected void slaveQuitDuringStartup(int status) { 644 super.slaveQuitDuringStartup(status); 645 if (Utilities.TEST_MODE) return; 647 650 String msg = "Interpreter JVM exited before registering, status: " + status; 652 IllegalStateException e = new IllegalStateException (msg); 653 new edu.rice.cs.drjava.ui.DrJavaErrorHandler().handle(e); 654 } 655 656 659 public void errorStartingSlave(Throwable cause) throws RemoteException { 660 new edu.rice.cs.drjava.ui.DrJavaErrorHandler().handle(cause); 661 } 662 663 666 public void quitFailed(Throwable th) throws RemoteException { 667 _interactionsModel.interpreterResetFailed(th); 668 _cleanlyRestarting = false; 669 } 670 671 672 public boolean isStartupInProgress() { return super.isStartupInProgress(); } 673 674 675 protected void handleSlaveConnected() { 676 _restart = true; 680 _cleanlyRestarting = false; 681 682 Boolean allowAccess = DrJava.getConfig().getSetting(OptionConstants.ALLOW_PRIVATE_ACCESS); 683 setPrivateAccessible(allowAccess.booleanValue()); 684 685 _interactionsModel.interpreterReady(_workDir); 687 _junitModel.junitJVMReady(); 688 689 _log.log("Main JVM Thread for slave connection is: " + Thread.currentThread()); 690 691 synchronized(_interpreterLock) { _interpreterLock.notify(); } 693 } 694 695 696 697 protected InterpretResultVisitor<Object > getResultHandler() { return _handler; } 698 699 700 protected int getDebugPort() { 701 int port = -1; 702 try { port = _interactionsModel.getDebugPort(); } 703 catch (IOException ioe) { 704 705 } 706 return port; 707 } 708 709 710 protected boolean allowAssertions() { 711 String version = System.getProperty("java.version"); 712 return (_allowAssertions && (version != null) && ("1.4.0".compareTo(version) <= 0)); 713 } 714 715 716 private void _threwException(Throwable t) { 717 String shortMsg = null; 718 if ((t instanceof ParseError) && ((ParseError) t).getParseException() != null) 719 shortMsg = ((ParseError) t).getMessage(); _interactionsModel.replThrewException(t.getClass().getName(), t.getMessage(), StringOps.getStackTrace(t), shortMsg); ; 721 } 722 723 724 public void setPrivateAccessible(boolean allow) { 725 if (!_restart) return; 727 728 InterpreterJVMRemoteI slave = ensureInterpreterConnected(); 729 try { slave.setPrivateAccessible(allow); } 730 catch (RemoteException re) { _threwException(re); } 731 } 732 733 734 public InterpreterJVMRemoteI ensureInterpreterConnected() { 735 try { 737 synchronized(_interpreterLock) { 738 741 InterpreterJVMRemoteI slave = _interpreterJVM(); 745 while (slave == null) { 746 _interpreterLock.wait(); 748 slave = _interpreterJVM(); 749 } 750 751 return slave; 753 } 754 } 755 catch (InterruptedException ie) { throw new UnexpectedException(ie); } 756 } 757 758 762 public String getConsoleInput() { return _interactionsModel.getConsoleInput(); } 763 764 768 private class ResultHandler implements InterpretResultVisitor<Object > { 769 773 public Object forVoidResult(VoidResult that) { 774 _interactionsModel.replReturnedVoid(); 775 return null; 776 } 777 778 781 public Object forValueResult(ValueResult that) { 782 String result = that.getValueStr(); 783 String style = that.getStyle(); 784 _interactionsModel.replReturnedResult(result, style); 785 return null; 786 } 787 788 791 public Object forExceptionResult(ExceptionResult that) { 792 _interactionsModel.replThrewException(that.getExceptionClass(), that.getExceptionMessage(), that.getStackTrace(), 793 that.getSpecialMessage()); 794 return null; 795 } 796 797 800 public Object forSyntaxErrorResult(SyntaxErrorResult that) { 801 _interactionsModel.replReturnedSyntaxError(that.getErrorMessage(), that.getInteraction(), that.getStartRow(), 802 that.getStartCol(), that.getEndRow(), that.getEndCol() ); 803 return null; 804 } 805 806 public Object forInterpreterBusy(InterpreterBusy that) { 807 throw new UnexpectedException("MainJVM.interpret() called when InterpreterJVM was busy!"); 808 } 809 } 810 811 812 public static class DummyInteractionsModel implements InteractionsModelCallback { 813 public int getDebugPort() throws IOException { return -1; } 814 public void replSystemOutPrint(String s) { } 815 public void replSystemErrPrint(String s) { } 816 public String getConsoleInput() { 817 throw new IllegalStateException ("Cannot request input from dummy interactions model!"); 818 } 819 public void setInputListener(InputListener il) { 820 throw new IllegalStateException ("Cannot set the input listener of dummy interactions model!"); 821 } 822 public void changeInputListener(InputListener from, InputListener to) { 823 throw new IllegalStateException ("Cannot change the input listener of dummy interactions model!"); 824 } 825 public void replReturnedVoid() { } 826 public void replReturnedResult(String result, String style) { } 827 public void replThrewException(String exceptionClass, String message, String stackTrace, String specialMessage) { } 828 public void replReturnedSyntaxError(String errorMessage, String interaction, int startRow, int startCol, int endRow, 829 int endCol) { } 830 public void replCalledSystemExit(int status) { } 831 public void interpreterResetting() { } 832 public void interpreterResetFailed(Throwable th) { } 833 public void interpreterReady(File wd) { } 834 public void slaveJVMUsed() { } 835 } 836 837 838 public static class DummyJUnitModel implements JUnitModelCallback { 839 public void nonTestCase(boolean isTestAll) { } 840 public void classFileError(ClassFileError e) { } 841 public void testSuiteStarted(int numTests) { } 842 public void testStarted(String testName) { } 843 public void testEnded(String testName, boolean wasSuccessful, boolean causedError) { } 844 public void testSuiteEnded(JUnitError[] errors) { } 845 public File getFileForClassName(String className) { return null; } 846 public ClassPathVector getClassPath() { return new ClassPathVector(); } 847 public void junitJVMReady() { } 848 } 849 850 851 public static class DummyDebugModel implements DebugModelCallback { 852 public void notifyDebugInterpreterAssignment(String name) { 853 } 854 } 855 } 856 | Popular Tags |