1 19 20 package org.netbeans.modules.search; 21 22 import java.awt.EventQueue ; 23 import java.lang.ref.Reference ; 24 import java.lang.reflect.InvocationTargetException ; 25 import java.lang.reflect.Method ; 26 import org.openide.DialogDisplayer; 27 import org.openide.ErrorManager; 28 import org.openide.NotifyDescriptor; 29 import org.openide.awt.StatusDisplayer; 30 import org.openide.util.NbBundle; 31 import org.openide.util.RequestProcessor; 32 import org.openide.util.Task; 33 import org.openide.util.TaskListener; 34 import org.openidex.search.SearchGroup; 35 import static org.netbeans.modules.search.ReplaceTask.ResultStatus.SUCCESS; 36 import static org.netbeans.modules.search.ReplaceTask.ResultStatus.PRE_CHECK_FAILED; 37 import static org.netbeans.modules.search.ReplaceTask.ResultStatus.PROBLEMS_ENCOUNTERED; 38 39 47 final class Manager { 48 49 53 private static final int CLEANUP_TIMEOUT_MILLIS = 3000; 54 55 56 static final int NO_TASK = 0; 57 58 static final int SEARCHING = 0x01; 59 60 static final int CLEANING_RESULT = 0x02; 61 62 static final int PRINTING_DETAILS = 0x04; 63 64 static final int REPLACING = 0x08; 65 66 static final int EVENT_SEARCH_STARTED = 1; 67 68 static final int EVENT_SEARCH_FINISHED = 2; 69 70 static final int EVENT_SEARCH_INTERRUPTED = 3; 71 72 static final int EVENT_SEARCH_CANCELLED = 4; 73 74 private static final Manager instance = new Manager(); 75 76 77 private boolean moduleBeingUninstalled = false; 78 79 80 private final Object lock = new Object (); 81 82 private int state = NO_TASK; 83 84 private int pendingTasks = 0; 85 86 private TaskListener taskListener; 87 88 private SearchTask currentSearchTask; 89 90 private SearchTask pendingSearchTask; 91 92 private SearchTask lastSearchTask; 93 94 private ReplaceTask currentReplaceTask; 95 96 private ReplaceTask pendingReplaceTask; 97 98 private PrintDetailsTask currentPrintDetailsTask; 99 100 private PrintDetailsTask pendingPrintDetailsTask; 101 102 private Task searchTask; 103 104 private Task replaceTask; 105 106 private Task cleanResultTask; 107 108 private Task printDetailsTask; 109 110 private ResultModel resultModelToClean; 111 112 private boolean searchWindowOpen = false; 113 114 private Reference outputWriterRef; 115 116 117 119 static Manager getInstance() { 120 return instance; 121 } 122 123 125 private Manager() { } 126 127 138 139 141 void scheduleSearchTask(SearchTask task) { 142 assert EventQueue.isDispatchThread(); 143 144 synchronized (lock) { 145 ResultView.getInstance().setResultModel(null); 146 if (currentSearchTask != null) { 147 currentSearchTask.stop(false); 148 } 149 if (resultModelToClean != null) { 150 pendingTasks |= CLEANING_RESULT; 151 } 152 pendingTasks |= SEARCHING; 153 pendingSearchTask = task; 154 lastSearchTask = task; 155 if (state == NO_TASK) { 156 processNextPendingTask(); 157 } else { 158 notifySearchPending(state); } 160 } 161 } 162 163 165 void scheduleReplaceTask(ReplaceTask task) { 166 assert EventQueue.isDispatchThread(); 167 168 synchronized (lock) { 169 assert (state == NO_TASK) && (pendingTasks == 0); 170 171 pendingTasks |= REPLACING; 172 pendingReplaceTask = task; 173 processNextPendingTask(); 174 } 175 } 176 177 179 void scheduleSearchTaskRerun() { 180 assert EventQueue.isDispatchThread(); 181 182 synchronized (lock) { 183 SearchTask newSearchTask = lastSearchTask.createNewGeneration(); 184 lastSearchTask = null; 185 scheduleSearchTask(newSearchTask); 186 } 187 } 188 189 191 void schedulePrintingDetails(Object [] matchingObjects, 192 SearchGroup searchGroup) { 193 synchronized (lock) { 194 assert state == NO_TASK; 195 pendingTasks |= PRINTING_DETAILS; 196 197 pendingPrintDetailsTask = new PrintDetailsTask( 198 matchingObjects, 199 searchGroup); 200 processNextPendingTask(); 201 } 202 } 203 204 213 String mayStartSearching() { 214 boolean replacing; 215 216 synchronized (lock) { 217 replacing = (state == REPLACING); 218 } 219 220 String msgKey = replacing ? "MSG_Cannot_start_search__replacing" : null; 222 return (msgKey != null) ? NbBundle.getMessage(getClass(), msgKey) 223 : null; 224 } 225 226 228 private void notifySearchStarted() { 229 notifySearchTaskStateChange(EVENT_SEARCH_STARTED); 230 } 231 232 234 private void notifySearchFinished() { 235 notifySearchTaskStateChange(EVENT_SEARCH_FINISHED); 236 } 237 238 240 private void notifySearchInterrupted() { 241 notifySearchTaskStateChange(EVENT_SEARCH_INTERRUPTED); 242 } 243 244 246 private void notifySearchCancelled() { 247 notifySearchTaskStateChange(EVENT_SEARCH_CANCELLED); 248 } 249 250 256 private void notifySearchTaskStateChange(final int changeType) { 257 synchronized (lock) { 258 if (!searchWindowOpen) { 259 return; 260 } 261 } 262 callOnWindowFromAWT("searchTaskStateChanged", new Integer (changeType)); 264 } 265 266 268 private void notifySearchPending(final int blockingTask) { 269 if (!searchWindowOpen) { 270 return; 271 } 272 callOnWindowFromAWT("notifySearchPending", new Integer (blockingTask)); 274 } 275 276 278 private void notifyReplaceFinished() { 279 assert Thread.holdsLock(lock); 280 assert currentReplaceTask != null; 281 282 ReplaceTask.ResultStatus resultStatus 283 = currentReplaceTask.getResultStatus(); 284 if (resultStatus == SUCCESS) { 285 StatusDisplayer.getDefault().setStatusText( 286 NbBundle.getMessage(getClass(), "MSG_Success")); if (searchWindowOpen) { 288 callOnWindowFromAWT("closeAndSendFocusToEditor", false); } 290 } else { 291 String msgKey = (resultStatus == PRE_CHECK_FAILED) 292 ? "MSG_Issues_found_during_precheck" : "MSG_Issues_found_during_replace"; String title = NbBundle.getMessage(getClass(), msgKey); 295 displayIssuesFromAWT(title, 296 currentReplaceTask.getProblems(), 297 resultStatus != PRE_CHECK_FAILED); 298 if (resultStatus == PRE_CHECK_FAILED) { 299 offerRescanAfterIssuesFound(); 300 } 301 } 302 } 303 304 306 private void offerRescanAfterIssuesFound() { 307 assert Thread.holdsLock(lock); 308 assert currentReplaceTask != null; 309 310 String msg = NbBundle.getMessage(getClass(), 311 "MSG_IssuesFound_Rescan_"); NotifyDescriptor nd = new NotifyDescriptor.Message( 313 msg, 314 NotifyDescriptor.QUESTION_MESSAGE); 315 String rerunOption = NbBundle.getMessage(getClass(), 316 "LBL_Rerun"); nd.setOptions(new Object [] {rerunOption, 318 NotifyDescriptor.CANCEL_OPTION}); 319 Object dlgResult = DialogDisplayer.getDefault().notify(nd); 320 if (rerunOption.equals(dlgResult)) { 321 330 callOnWindowFromAWT("rescan", false); } 332 } 333 334 336 private void notifyPrintingDetailsFinished() { 337 if (!searchWindowOpen) { 338 return; 339 } 340 callOnWindowFromAWT("showAllDetailsFinished"); } 342 343 345 private void activateResultWindow() { 346 Method theMethod; 347 try { 348 theMethod = ResultView.class 349 .getMethod("requestActive", new Class [0]); } catch (NoSuchMethodException ex) { 351 throw new IllegalArgumentException (); 352 } 353 callOnWindowFromAWT(theMethod, null); 354 } 355 356 358 private void displayIssuesFromAWT(String title, 359 String [] issues, 360 boolean att) { 361 Method theMethod; 362 try { 363 theMethod = ResultView.class.getDeclaredMethod( 364 "displayIssuesToUser", String .class, 366 String [].class, 367 Boolean.TYPE); 368 } catch (NoSuchMethodException ex) { 369 throw new IllegalStateException (ex); 370 } 371 callOnWindowFromAWT(theMethod, 372 new Object [] {title, issues, Boolean.valueOf(att)}, 373 false); 374 } 375 376 381 private void callOnWindowFromAWT(final String methodName) { 382 callOnWindowFromAWT(methodName, true); 383 } 384 385 387 private void callOnWindowFromAWT(final String methodName, 388 final boolean wait) { 389 Method theMethod; 390 try { 391 theMethod = ResultView.class 392 .getDeclaredMethod(methodName, new Class [0]); 393 } catch (NoSuchMethodException ex) { 394 throw new IllegalArgumentException (); 395 } 396 callOnWindowFromAWT(theMethod, null, wait); 397 } 398 399 405 private void callOnWindowFromAWT(final String methodName, 406 final Object param) { 407 callOnWindowFromAWT(methodName, param, true); 408 } 409 410 412 private void callOnWindowFromAWT(final String methodName, 413 final Object param, 414 final boolean wait) { 415 Method theMethod = null; 416 Method [] methods = ResultView.class.getDeclaredMethods(); 417 for (int i = 0; i < methods.length; i++) { 418 Method method = methods[i]; 419 if (method.getName().equals(methodName)) { 420 Class [] parameterTypes = method.getParameterTypes(); 421 if (parameterTypes.length == 1) { 422 Class paramType = parameterTypes[0]; 423 if ((param == null 424 && !paramType.isPrimitive()) 425 || (paramType == Integer.TYPE) 426 && (param instanceof Integer ) 427 || parameterTypes[0].isInstance(param)) { 428 theMethod = method; 429 } 430 } 431 } 432 } 433 if (theMethod == null) { 434 throw new IllegalArgumentException (); 435 } 436 callOnWindowFromAWT(theMethod, new Object [] {param}, wait); 437 } 438 439 441 private void callOnWindowFromAWT(final Method method, 442 final Object [] params) { 443 callOnWindowFromAWT(method, params, true); 444 } 445 446 448 private void callOnWindowFromAWT(final Method method, 449 final Object [] params, 450 final boolean wait) { 451 Runnable runnable = new Runnable () { 452 public void run() { 453 final ResultView resultViewInstance = ResultView.getInstance(); 454 try { 455 method.invoke(resultViewInstance, params); 456 } catch (Exception ex) { 457 ErrorManager.getDefault().notify(ex); 458 } 459 } 460 }; 461 if (EventQueue.isDispatchThread()) { 462 runnable.run(); 463 } else { 464 if (wait) { 465 try { 466 EventQueue.invokeAndWait(runnable); 467 } catch (InvocationTargetException ex1) { 468 ErrorManager.getDefault().notify(ex1); 469 } catch (Exception ex2) { 470 ErrorManager.getDefault().notify(ErrorManager.ERROR, ex2); 471 } 472 } else { 473 EventQueue.invokeLater(runnable); 474 } 475 } 476 } 477 478 480 void searchWindowOpened() { 481 synchronized (lock) { 482 searchWindowOpen = true; 483 } 484 } 485 486 488 void searchWindowClosed() { 489 assert EventQueue.isDispatchThread(); 490 491 synchronized (lock) { 492 searchWindowOpen = false; 493 494 if (moduleBeingUninstalled) { 495 return; 496 } 497 498 if (currentSearchTask != null) { 499 currentSearchTask.stop(false); 500 } 501 if (resultModelToClean != null) { 502 pendingTasks |= CLEANING_RESULT; 503 } 504 pendingTasks &= ~SEARCHING; 505 pendingSearchTask = null; 506 lastSearchTask = null; 507 if (state == NO_TASK) { 508 processNextPendingTask(); 509 } 510 } 511 } 512 513 515 private void processNextPendingTask() { 516 synchronized (lock) { 517 assert state == NO_TASK; 518 if (resultModelToClean == null) { 519 pendingTasks &= ~CLEANING_RESULT; 520 } 521 if ((pendingTasks & PRINTING_DETAILS) != 0) { 522 if ((pendingTasks & SEARCHING) != 0) { 523 notifySearchPending(PRINTING_DETAILS); } 525 startPrintingDetails(); 526 } else if ((pendingTasks & CLEANING_RESULT) != 0) { 527 if ((pendingTasks & SEARCHING) != 0) { 528 notifySearchPending(CLEANING_RESULT); } 530 startCleaning(); 531 } else if ((pendingTasks & SEARCHING) != 0) { 532 startSearching(); 533 } else if ((pendingTasks & REPLACING) != 0) { 534 startReplacing(); 535 } else { 536 assert pendingTasks == 0; 537 } 538 } 539 } 540 541 543 private void startSearching() { 544 synchronized (lock) { 545 assert pendingSearchTask != null; 546 547 notifySearchStarted(); 548 549 ResultModel resultModel = pendingSearchTask.getResultModel(); 550 callOnWindowFromAWT("setResultModel", resultModel); 552 resultModelToClean = resultModel; 553 554 if (outputWriterRef != null) { 555 SearchDisplayer.clearOldOutput(outputWriterRef); 556 outputWriterRef = null; 557 558 562 activateResultWindow(); 563 } 564 565 RequestProcessor.Task task; 566 task = RequestProcessor.getDefault().create(pendingSearchTask); 567 task.addTaskListener(getTaskListener()); 568 task.schedule(0); 569 570 currentSearchTask = pendingSearchTask; 571 pendingSearchTask = null; 572 573 searchTask = task; 574 pendingTasks &= ~SEARCHING; 575 state = SEARCHING; 576 } 577 } 578 579 581 private void startReplacing() { 582 synchronized (lock) { 583 assert pendingReplaceTask != null; 584 585 RequestProcessor.Task task; 586 task = RequestProcessor.getDefault().create(pendingReplaceTask); 587 task.addTaskListener(getTaskListener()); 588 task.schedule(0); 589 590 currentReplaceTask = pendingReplaceTask; 591 pendingReplaceTask = null; 592 593 replaceTask = task; 594 pendingTasks &= ~REPLACING; 595 state = REPLACING; 596 } 597 } 598 599 601 private void startPrintingDetails() { 602 synchronized (lock) { 603 if (outputWriterRef != null) { 604 SearchDisplayer.clearOldOutput(outputWriterRef); 605 outputWriterRef = null; 606 } 607 608 RequestProcessor.Task task; 609 task = RequestProcessor.getDefault() 610 .create(pendingPrintDetailsTask); 611 task.addTaskListener(getTaskListener()); 612 task.schedule(0); 613 614 printDetailsTask = task; 615 pendingTasks &= ~PRINTING_DETAILS; 616 currentPrintDetailsTask = pendingPrintDetailsTask; 617 pendingPrintDetailsTask = null; 618 619 state = PRINTING_DETAILS; 620 } 621 } 622 623 625 private void startCleaning() { 626 synchronized (lock) { 627 Runnable cleaner = new CleanTask(resultModelToClean); 628 resultModelToClean = null; 629 630 RequestProcessor.Task task; 631 task = RequestProcessor.getDefault().create(cleaner); 632 task.addTaskListener(getTaskListener()); 633 task.schedule(0); 634 635 cleanResultTask = task; 636 pendingTasks &= ~CLEANING_RESULT; 637 state = CLEANING_RESULT; 638 } 639 } 640 641 643 void stopSearching() { 644 synchronized (lock) { 645 if ((pendingTasks & SEARCHING) != 0) { 646 pendingTasks &= ~SEARCHING; 647 pendingSearchTask = null; 648 notifySearchCancelled(); 649 } else if (currentSearchTask != null) { 650 currentSearchTask.stop(); 651 } 652 } 653 } 654 655 657 private void taskFinished(Task task) { 658 synchronized (lock) { 659 if (moduleBeingUninstalled) { 660 allTasksFinished(); 661 return; 662 } 663 664 if (task == searchTask) { 665 assert state == SEARCHING; 666 if (currentSearchTask.notifyWhenFinished()) { 667 if (currentSearchTask.wasInterrupted()) { 668 notifySearchInterrupted(); 669 } else { 670 notifySearchFinished(); 671 } 672 } 673 currentSearchTask = null; 674 searchTask = null; 675 state = NO_TASK; 676 } else if (task == replaceTask) { 677 assert state == REPLACING; 678 notifyReplaceFinished(); 679 currentReplaceTask = null; 680 replaceTask = null; 681 state = NO_TASK; 682 } else if (task == cleanResultTask) { 683 assert state == CLEANING_RESULT; 684 cleanResultTask = null; 685 state = NO_TASK; 686 } else if (task == printDetailsTask) { 687 assert state == PRINTING_DETAILS; 688 notifyPrintingDetailsFinished(); 689 690 outputWriterRef = currentPrintDetailsTask.getOutputWriterRef(); 691 currentPrintDetailsTask = null; 692 printDetailsTask = null; 693 state = NO_TASK; 694 } else { 695 assert false; 696 } 697 processNextPendingTask(); 698 } 699 } 700 701 707 private void allTasksFinished() { 708 synchronized (lock) { 709 lock.notifyAll(); 710 } 711 } 712 713 723 void doCleanup() { 724 synchronized (lock) { 725 moduleBeingUninstalled = true; 726 if (state != NO_TASK) { 727 if (currentSearchTask != null) { 728 currentSearchTask.stop(false); 729 } 730 if (currentPrintDetailsTask != null) { 731 currentPrintDetailsTask.stop(); 732 } 733 try { 734 lock.wait(CLEANUP_TIMEOUT_MILLIS); 735 } catch (InterruptedException ex) { 736 ErrorManager.getDefault().notify( 737 ErrorManager.EXCEPTION, 738 ex); 739 } 740 } 741 callOnWindowFromAWT("closeResults"); } 743 } 744 745 747 private TaskListener getTaskListener() { 748 if (taskListener == null) { 749 taskListener = new MyTaskListener(); 750 } 751 return taskListener; 752 } 753 754 755 757 private class MyTaskListener implements TaskListener { 758 759 761 MyTaskListener() { 762 super(); 763 } 764 765 767 public void taskFinished(Task task) { 768 synchronized (lock) { 769 Manager.this.taskFinished(task); 770 } 771 } 772 773 } 774 775 } 776 | Popular Tags |