1 33 34 package edu.rice.cs.drjava.model.repl; 35 36 import java.io.*; 37 import java.net.ServerSocket ; 38 import java.util.List ; 39 import java.util.ArrayList ; 40 import java.net.URL ; 41 42 import edu.rice.cs.drjava.CodeStatus; 43 import edu.rice.cs.util.FileOpenSelector; 44 import edu.rice.cs.util.OperationCanceledException; 45 import edu.rice.cs.util.*; 46 import edu.rice.cs.util.swing.Utilities; 47 import edu.rice.cs.util.text.EditDocumentInterface; 48 import edu.rice.cs.util.text.ConsoleDocument; 49 import edu.rice.cs.util.text.EditDocumentException; 50 51 55 public abstract class InteractionsModel implements InteractionsModelCallback { 56 57 58 public static final String BANNER_PREFIX = "Welcome to DrJava."; 59 60 61 protected final InteractionsEventNotifier _notifier = new InteractionsEventNotifier(); 62 63 64 protected static final String _newLine = System.getProperty("line.separator"); 65 66 67 protected final InteractionsDocument _document; 68 69 70 protected volatile boolean _waitingForFirstInterpreter; 71 72 73 protected volatile File _workingDirectory; 74 75 76 private final Object _interpreterLock; 77 78 80 private final Object _writerLock; 81 82 83 private final int _writeDelay; 84 85 86 private volatile int _debugPort; 87 88 89 private volatile boolean _debugPortSet; 90 91 92 private volatile String _toAddToHistory = ""; 93 94 95 protected volatile InputListener _inputListener; 96 97 protected final EditDocumentInterface _adapter; 98 99 100 private volatile String _banner; 101 102 108 public InteractionsModel(EditDocumentInterface adapter, File wd, int historySize, int writeDelay) { 109 _writeDelay = writeDelay; 110 _document = new InteractionsDocument(adapter, historySize, getBanner(wd)); 111 _adapter = adapter; 112 _waitingForFirstInterpreter = true; 113 _workingDirectory = wd; 114 _interpreterLock = new Object (); 115 _writerLock = new Object (); 116 _debugPort = -1; 117 _debugPortSet = false; 118 _inputListener = NoInputListener.ONLY; 119 } 120 121 123 public void addListener(InteractionsListener listener) { _notifier.addListener(listener); } 124 125 129 public void removeListener(InteractionsListener listener) { _notifier.removeListener(listener); } 130 131 132 public void removeAllInteractionListeners() { _notifier.removeAllListeners(); } 133 134 135 public InteractionsDocument getDocument() { return _document; } 136 137 public void interactionContinues() { 138 _document.setInProgress(false); 139 _notifyInteractionEnded(); 140 _notifyInteractionIncomplete(); 141 } 142 143 146 public void setWaitingForFirstInterpreter(boolean waiting) { _waitingForFirstInterpreter = waiting; } 147 148 149 public void interpretCurrentInteraction() { 150 synchronized(_interpreterLock) { 151 if (_document.inProgress()) return; 153 154 String text = _document.getCurrentInteraction(); 155 String toEval = text.trim(); 156 if (toEval.startsWith("java ")) toEval = _testClassCall(toEval); 157 158 _prepareToInterpret(text); 159 interpret(toEval); 160 } 161 } 162 163 164 private void _prepareToInterpret(String text) { 165 addNewLine(); 166 _notifyInteractionStarted(); 167 _document.setInProgress(true); 168 _toAddToHistory = text; } 171 172 public void addNewLine() { append(_newLine, InteractionsDocument.DEFAULT_STYLE); } 173 174 176 public final void interpret(String toEval) { 177 synchronized(_interpreterLock) { _interpret(toEval); } 178 } 179 180 183 protected abstract void _interpret(String toEval); 184 185 186 protected abstract void _notifyInteractionIncomplete(); 187 188 189 protected abstract void _notifyInteractionStarted(); 190 191 194 public abstract String getVariableToString(String var); 195 196 199 public abstract String getVariableClassName(String var); 200 201 202 public final void resetInterpreter(File wd) { 203 _workingDirectory = wd; 204 _resetInterpreter(wd); 205 } 206 207 208 protected abstract void _resetInterpreter(File wd); 209 210 211 public File getWorkingDirectory() { return _workingDirectory; } 212 213 216 public abstract void addProjectClassPath(URL path); 217 public abstract void addBuildDirectoryClassPath(URL path); 218 public abstract void addProjectFilesClassPath(URL path); 219 public abstract void addExternalFilesClassPath(URL path); 220 public abstract void addExtraClassPath(URL path); 221 222 226 protected abstract void _notifySyntaxErrorOccurred(int offset, int length); 227 228 233 protected ArrayList <String > _getHistoryText(FileOpenSelector selector) 234 throws IOException, OperationCanceledException { 235 File[] files = selector.getFiles(); 236 if (files == null) throw new IOException("No Files returned from FileSelector"); 237 238 ArrayList <String > histories = new ArrayList <String >(); 239 ArrayList <String > strings = new ArrayList <String >(); 240 241 for (File f: files) { 242 if (f == null) throw new IOException("File name returned from FileSelector is null"); 243 try { 244 FileInputStream fis = new FileInputStream(f); 245 InputStreamReader isr = new InputStreamReader(fis); 246 BufferedReader br = new BufferedReader(isr); 247 while (true) { 248 String line = br.readLine(); 249 if (line == null) break; 250 strings.add(line); 251 } 252 br.close(); } 254 catch (IOException ioe) { throw new IOException("File name returned from FileSelector is null"); } 255 256 final StringBuilder text = new StringBuilder (); 258 boolean firstLine = true; 259 int formatVersion = 1; 260 for (String s: strings) { 261 int sl = s.length(); 262 if (sl > 0) { 263 264 if (firstLine && (s.trim().equals(History.HISTORY_FORMAT_VERSION_2.trim()))) formatVersion = 2; 266 267 switch (formatVersion) { 268 case (1): 269 text.append(s); 272 if (s.charAt(sl - 1) != ';') text.append(';'); 273 text.append(_newLine); 274 break; 275 case (2): 276 if (!firstLine) text.append(s).append(_newLine); break; 278 } 279 firstLine = false; 280 } 281 } 282 283 histories.add(text.toString()); 285 } 286 return histories; 287 } 288 289 295 protected ArrayList <String > _removeSeparators(String text) { 296 String sep = History.INTERACTION_SEPARATOR; 297 int len = sep.length(); 298 ArrayList <String > interactions = new ArrayList <String >(); 299 300 int index = text.indexOf(sep); 303 int lastIndex = 0; 304 while (index != -1) { 305 interactions.add(text.substring(lastIndex, index).trim()); 306 lastIndex = index + len; 307 index = text.indexOf(sep, lastIndex); 308 } 309 310 String last = text.substring(lastIndex, text.length()).trim(); 312 if (!"".equals(last)) interactions.add(last); 313 return interactions; 314 } 315 316 320 public void loadHistory(FileOpenSelector selector) throws IOException { 321 ArrayList <String > histories; 322 try { histories = _getHistoryText(selector); } 323 catch (OperationCanceledException oce) { return; } 324 _document.clearCurrentInteraction(); 325 326 final StringBuilder buf = new StringBuilder (); 328 for (String hist: histories) { 329 ArrayList <String > interactions = _removeSeparators(hist); 330 for (String curr: interactions) { 331 int len = curr.length(); 332 buf.append(curr); 333 if (len > 0 && curr.charAt(len - 1) != ';') buf.append(';'); 334 buf.append(_newLine); 335 } 336 } 337 append(buf.toString().trim(), InteractionsDocument.DEFAULT_STYLE); 338 interpretCurrentInteraction(); 339 } 340 341 342 public InteractionsScriptModel loadHistoryAsScript(FileOpenSelector selector) 343 throws IOException, OperationCanceledException { 344 ArrayList <String > histories = _getHistoryText(selector); 345 ArrayList <String > interactions = new ArrayList <String >(); 346 for (String hist: histories) interactions.addAll(_removeSeparators(hist)); 347 return new InteractionsScriptModel(this, interactions); 348 } 349 350 354 public int getDebugPort() throws IOException { 355 if (!_debugPortSet) _createNewDebugPort(); 356 return _debugPort; 357 } 358 359 362 protected void _createNewDebugPort() throws IOException { 363 try { 365 ServerSocket socket = new ServerSocket (0); 366 _debugPort = socket.getLocalPort(); 367 socket.close(); 368 } 369 catch (java.net.SocketException se) { 370 _debugPort = -1; 372 } 373 _debugPortSet = true; 374 if (CodeStatus.DEVELOPMENT) { 375 System.setProperty("drjava.debug.port", String.valueOf(_debugPort)); 376 } 377 } 378 379 382 public void setDebugPort(int port) { 383 _debugPort = port; 384 _debugPortSet = true; 385 } 386 387 390 public void replSystemOutPrint(String s) { 391 _document.insertBeforeLastPrompt(s, InteractionsDocument.SYSTEM_OUT_STYLE); 392 } 393 394 397 public void replSystemErrPrint(String s) { 398 _document.insertBeforeLastPrompt(s, InteractionsDocument.SYSTEM_ERR_STYLE); 399 } 400 401 402 public String getConsoleInput() { return _inputListener.getConsoleInput(); } 403 404 409 public void setInputListener(InputListener listener) { 410 if (_inputListener == NoInputListener.ONLY) _inputListener = listener; 411 else throw new IllegalStateException ("Cannot change the input listener until it is released."); 412 } 413 414 420 public void changeInputListener(InputListener oldListener, InputListener newListener) { 421 synchronized(NoInputListener.ONLY) { 423 if (_inputListener == oldListener) _inputListener = newListener; 424 else 425 throw new IllegalArgumentException ("The given old listener is not installed!"); 426 } 427 } 428 429 432 protected void _interactionIsOver() { 433 _document.addToHistory(_toAddToHistory); 434 _document.setInProgress(false); 435 _document.insertPrompt(); 436 _notifyInteractionEnded(); 437 } 438 439 440 protected abstract void _notifyInteractionEnded(); 441 442 448 public void append(String s, String styleName) { 449 synchronized(_writerLock) { 450 try { 451 _document.append(s, styleName); 452 453 _writerLock.wait(_writeDelay); 455 } 456 catch (EditDocumentException e) { throw new UnexpectedException(e); } 457 catch (InterruptedException e) { 458 } 460 } 461 } 462 463 464 public void replReturnedVoid() { _interactionIsOver(); } 465 466 471 public void replReturnedResult(String result, String style) { 472 append(result + _newLine, style); 473 _interactionIsOver(); 474 } 475 476 481 public void replThrewException(String exceptionClass, String message, String stackTrace, String shortMessage) { 482 if (shortMessage!=null) { 483 if (shortMessage.endsWith("<EOF>\"")) { 484 interactionContinues(); 485 return; 486 } 487 } 488 _document.appendExceptionResult(exceptionClass, message, stackTrace, InteractionsDocument.ERROR_STYLE); 489 _interactionIsOver(); 490 } 491 492 500 public void replReturnedSyntaxError(String errorMessage, String interaction, int startRow, int startCol, 501 int endRow, int endCol ) { 502 if (errorMessage!=null) { 503 if (errorMessage.endsWith("<EOF>\"")) { 504 interactionContinues(); 505 return; 506 } 507 } 508 509 edu.rice.cs.plt.tuple.Pair<Integer ,Integer > oAndL = 510 StringOps.getOffsetAndLength(interaction, startRow, startCol, endRow, endCol); 511 512 _notifySyntaxErrorOccurred(_document.getPromptPos() + oAndL.first().intValue(),oAndL.second().intValue()); 513 514 _document.appendSyntaxErrorResult(errorMessage, interaction, startRow, startCol, endRow, endCol, 515 InteractionsDocument.ERROR_STYLE); 516 517 _interactionIsOver(); 518 } 519 520 523 public void replCalledSystemExit(int status) { 524 _notifyInterpreterExited(status); 526 } 527 528 531 protected abstract void _notifyInterpreterExited(int status); 532 533 534 public void interpreterResetting() { 535 if (! _waitingForFirstInterpreter) { 538 _document.acquireWriteLock(); 539 try { 540 _document.insertBeforeLastPrompt("Resetting Interactions..." + _newLine, InteractionsDocument.ERROR_STYLE); 541 _document.setInProgress(true); 542 } 543 finally { _document.releaseWriteLock(); } 544 546 try { _createNewDebugPort(); } 548 catch (IOException ioe) { 549 } 551 _notifyInterpreterResetting(); 552 } 554 } 555 556 557 protected abstract void _notifyInterpreterResetting(); 558 559 562 public void interpreterResetFailed(Throwable t) { 563 _interpreterResetFailed(t); 564 _document.setInProgress(false); 565 _notifyInterpreterResetFailed(t); 566 } 567 568 571 protected abstract void _interpreterResetFailed(Throwable t); 572 573 576 protected abstract void _notifyInterpreterResetFailed(Throwable t); 577 578 public String getBanner() { return _banner; } 579 580 public String getStartUpBanner() { return getBanner(_workingDirectory); } 581 582 public static String getBanner(File wd) { return BANNER_PREFIX + " Working directory is " + wd + '\n'; } 583 584 private String generateBanner(File wd) { 585 _banner = getBanner(wd); 586 return _banner; 587 } 588 589 591 592 public void interpreterReady(File wd) { 593 if (! _waitingForFirstInterpreter) { 596 _document.reset(generateBanner(wd)); 597 _document.setInProgress(false); 598 _notifyInterpreterReady(wd); 599 } 600 _waitingForFirstInterpreter = false; 601 } 602 603 604 public abstract void _notifyInterpreterReady(File wd); 605 606 607 public void slaveJVMUsed() { _notifySlaveJVMUsed(); } 608 609 610 protected abstract void _notifySlaveJVMUsed(); 611 612 613 protected static String _testClassCall(String s) { 614 if (s.endsWith(";")) s = _deleteSemiColon(s); 615 List <String > args = ArgumentTokenizer.tokenize(s, true); 616 boolean seenArg = false; 617 final String className = args.get(1); 618 final StringBuilder mainCall = new StringBuilder (); 619 mainCall.append(className.substring(1, className.length() - 1)); 620 mainCall.append(".main(new String[]{"); 621 for (int i = 2; i < args.size(); i++) { 622 if (seenArg) mainCall.append(","); 623 else seenArg = true; 624 mainCall.append(args.get(i)); 625 } 626 mainCall.append("});"); 627 return mainCall.toString(); 628 } 629 630 635 protected static String _deleteSemiColon(String s) { return s.substring(0, s.length() - 1); } 636 637 638 private static class NoInputListener implements InputListener { 639 public static final NoInputListener ONLY = new NoInputListener(); 640 private NoInputListener() { } 641 642 public String getConsoleInput() { throw new IllegalStateException ("No input listener installed!"); } 643 } 644 645 646 public abstract ConsoleDocument getConsoleDocument(); 647 } 648 | Popular Tags |