1 11 package org.eclipse.ltk.internal.core.refactoring.history; 12 13 import com.ibm.icu.text.DateFormat; 14 15 import java.io.IOException ; 16 import java.io.InputStream ; 17 import java.io.OutputStream ; 18 import java.net.URI ; 19 import java.util.ArrayList ; 20 import java.util.Arrays ; 21 import java.util.Collection ; 22 import java.util.Date ; 23 import java.util.EmptyStackException ; 24 import java.util.HashMap ; 25 import java.util.HashSet ; 26 import java.util.Iterator ; 27 import java.util.LinkedHashMap ; 28 import java.util.LinkedList ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Set ; 32 33 import org.eclipse.core.runtime.Assert; 34 import org.eclipse.core.runtime.CoreException; 35 import org.eclipse.core.runtime.IPath; 36 import org.eclipse.core.runtime.IProgressMonitor; 37 import org.eclipse.core.runtime.ISafeRunnable; 38 import org.eclipse.core.runtime.IStatus; 39 import org.eclipse.core.runtime.ListenerList; 40 import org.eclipse.core.runtime.MultiStatus; 41 import org.eclipse.core.runtime.NullProgressMonitor; 42 import org.eclipse.core.runtime.OperationCanceledException; 43 import org.eclipse.core.runtime.Platform; 44 import org.eclipse.core.runtime.SafeRunner; 45 import org.eclipse.core.runtime.Status; 46 import org.eclipse.core.runtime.SubProgressMonitor; 47 import org.eclipse.core.runtime.preferences.IScopeContext; 48 49 import org.eclipse.core.commands.operations.IOperationHistoryListener; 50 import org.eclipse.core.commands.operations.IUndoableOperation; 51 import org.eclipse.core.commands.operations.OperationHistoryEvent; 52 import org.eclipse.core.commands.operations.OperationHistoryFactory; 53 import org.eclipse.core.commands.operations.TriggeredOperations; 54 import org.eclipse.core.filesystem.EFS; 55 import org.eclipse.core.filesystem.IFileStore; 56 57 import org.eclipse.core.resources.IFolder; 58 import org.eclipse.core.resources.IProject; 59 import org.eclipse.core.resources.IResource; 60 import org.eclipse.core.resources.IResourceChangeEvent; 61 import org.eclipse.core.resources.IResourceChangeListener; 62 import org.eclipse.core.resources.IResourceDelta; 63 import org.eclipse.core.resources.ProjectScope; 64 import org.eclipse.core.resources.ResourcesPlugin; 65 66 import org.eclipse.ltk.core.refactoring.Change; 67 import org.eclipse.ltk.core.refactoring.ChangeDescriptor; 68 import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes; 69 import org.eclipse.ltk.core.refactoring.Refactoring; 70 import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor; 71 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 72 import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy; 73 import org.eclipse.ltk.core.refactoring.RefactoringSessionDescriptor; 74 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 75 import org.eclipse.ltk.core.refactoring.history.IRefactoringExecutionListener; 76 import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryListener; 77 import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryService; 78 import org.eclipse.ltk.core.refactoring.history.RefactoringExecutionEvent; 79 import org.eclipse.ltk.core.refactoring.history.RefactoringHistory; 80 import org.eclipse.ltk.core.refactoring.history.RefactoringHistoryEvent; 81 82 import org.eclipse.ltk.internal.core.refactoring.IRefactoringSerializationConstants; 83 import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages; 84 import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin; 85 import org.eclipse.ltk.internal.core.refactoring.RefactoringPreferenceConstants; 86 import org.eclipse.ltk.internal.core.refactoring.RefactoringSessionReader; 87 import org.eclipse.ltk.internal.core.refactoring.UndoableOperation2ChangeAdapter; 88 89 import org.xml.sax.InputSource ; 90 91 96 public final class RefactoringHistoryService implements IRefactoringHistoryService { 97 98 99 private static final class NoRefactoringDescriptor extends RefactoringDescriptor { 100 101 104 private NoRefactoringDescriptor() { 105 super("org.eclipse.ltk.core.refactoring.none", null, "N/A", null, RefactoringDescriptor.NONE); } 107 108 111 public Refactoring createRefactoring(final RefactoringStatus status) throws CoreException { 112 return null; 113 } 114 } 115 116 117 private static final class NullRefactoringHistory extends RefactoringHistory { 118 119 120 private static final RefactoringDescriptorProxy[] NO_PROXIES= {}; 121 122 125 public RefactoringDescriptorProxy[] getDescriptors() { 126 return NO_PROXIES; 127 } 128 129 132 public boolean isEmpty() { 133 return true; 134 } 135 136 139 public RefactoringHistory removeAll(final RefactoringHistory history) { 140 return this; 141 } 142 } 143 144 145 private final class RefactoringDescriptorStack { 146 147 148 private static final int MAX_MANAGERS= 2; 149 150 151 private final LinkedList fImplementation= new LinkedList (); 152 153 157 private final Map fManagerCache= new LinkedHashMap (MAX_MANAGERS, 0.75f, true) { 158 159 private static final long serialVersionUID= 1L; 160 161 protected final boolean removeEldestEntry(final Map.Entry entry) { 162 return size() > MAX_MANAGERS; 163 } 164 }; 165 166 175 private void checkDescriptor(final RefactoringDescriptor descriptor) throws CoreException { 176 final Map arguments= RefactoringHistoryManager.getArgumentMap(descriptor); 177 if (arguments != null) 178 RefactoringHistoryManager.checkArgumentMap(arguments); 179 } 180 181 192 private RefactoringHistoryManager getManager(final IFileStore store, final String name) { 193 Assert.isNotNull(store); 194 RefactoringHistoryManager manager= (RefactoringHistoryManager) fManagerCache.get(store); 195 if (manager == null) { 196 manager= new RefactoringHistoryManager(store, name); 197 fManagerCache.put(store, manager); 198 } 199 return manager; 200 } 201 202 211 private RefactoringHistoryManager getManager(final String name) { 212 final IFileStore store= EFS.getLocalFileSystem().getStore(RefactoringCorePlugin.getDefault().getStateLocation()).getChild(NAME_HISTORY_FOLDER); 213 if (name != null && !"".equals(name)) { try { 215 final IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(name); 216 if (project.isAccessible()) { 217 if (hasSharedRefactoringHistory(project)) { 218 final URI uri= project.getLocationURI(); 219 if (uri != null) 220 return getManager(EFS.getStore(uri).getChild(RefactoringHistoryService.NAME_HISTORY_FOLDER), name); 221 } else 222 return getManager(store.getChild(name), name); 223 } 224 } catch (CoreException exception) { 225 } 227 } else 228 return getManager(store.getChild(NAME_WORKSPACE_PROJECT), null); 229 return null; 230 } 231 232 239 private RefactoringDescriptor peek() throws EmptyStackException { 240 if (!fImplementation.isEmpty()) 241 return (RefactoringDescriptor) fImplementation.getFirst(); 242 throw new EmptyStackException (); 243 } 244 245 251 private void pop() throws EmptyStackException { 252 final RefactoringDescriptor descriptor= peek(); 253 if (!fImplementation.isEmpty()) 254 fImplementation.removeFirst(); 255 else 256 throw new EmptyStackException (); 257 final Object [] listeners= fHistoryListeners.getListeners(); 258 for (int index= 0; index < listeners.length; index++) { 259 final IRefactoringHistoryListener listener= (IRefactoringHistoryListener) listeners[index]; 260 SafeRunner.run(new ISafeRunnable() { 261 262 public void handleException(final Throwable throwable) { 263 RefactoringCorePlugin.log(throwable); 264 } 265 266 public void run() throws Exception { 267 listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.POPPED, new RefactoringDescriptorProxyAdapter(descriptor))); 268 } 269 }); 270 } 271 } 272 273 281 private void push(final RefactoringDescriptor descriptor) throws CoreException { 282 Assert.isNotNull(descriptor); 283 try { 284 checkDescriptor(descriptor); 285 } catch (CoreException exception) { 286 final IStatus status= exception.getStatus(); 287 if (status.getCode() == IRefactoringCoreStatusCodes.REFACTORING_HISTORY_FORMAT_ERROR) { 288 final String time= DateFormat.getDateTimeInstance().format(new Date (descriptor.getTimeStamp())); 289 final String message= "The refactoring executed at " + time + " contributed a refactoring descriptor with invalid format:"; final IStatus comment= new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), descriptor.getComment()); 291 RefactoringCorePlugin.log(new MultiStatus(RefactoringCorePlugin.getPluginId(), 0, new IStatus[] { comment}, message, null)); 292 } 293 throw exception; 294 } 295 fImplementation.addFirst(descriptor); 296 final int size= fImplementation.size(); 297 if (size > MAX_UNDO_STACK) 298 fImplementation.removeLast(); 299 final Object [] listeners= fHistoryListeners.getListeners(); 300 for (int index= 0; index < listeners.length; index++) { 301 final IRefactoringHistoryListener listener= (IRefactoringHistoryListener) listeners[index]; 302 SafeRunner.run(new ISafeRunnable() { 303 304 public void handleException(final Throwable throwable) { 305 RefactoringCorePlugin.log(throwable); 306 } 307 308 public void run() throws Exception { 309 listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.PUSHED, new RefactoringDescriptorProxyAdapter(descriptor))); 310 } 311 }); 312 } 313 } 314 315 326 private RefactoringDescriptor requestDescriptor(final RefactoringDescriptorProxy proxy, final IProgressMonitor monitor) { 327 Assert.isNotNull(proxy); 328 Assert.isNotNull(monitor); 329 try { 330 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_resolving_information, 6); 331 final long stamp= proxy.getTimeStamp(); 332 RefactoringDescriptor descriptor= null; 333 final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 4); 334 try { 335 subMonitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_resolving_information, fImplementation.size()); 336 for (final Iterator iterator= fImplementation.iterator(); iterator.hasNext();) { 337 subMonitor.worked(1); 338 final RefactoringDescriptor existing= (RefactoringDescriptor) iterator.next(); 339 final long time= existing.getTimeStamp(); 340 if (time >= 0 && time == stamp) { 341 descriptor= existing; 342 break; 343 } 344 } 345 } finally { 346 subMonitor.done(); 347 } 348 if (monitor.isCanceled()) 349 throw new OperationCanceledException(); 350 monitor.worked(1); 351 if (descriptor == null) { 352 final RefactoringHistoryManager manager= getManager(proxy.getProject()); 353 if (manager != null) 354 descriptor= manager.requestDescriptor(proxy, new SubProgressMonitor(monitor, 1)); 355 else 356 monitor.worked(1); 357 } else 358 monitor.worked(1); 359 return descriptor; 360 } finally { 361 monitor.done(); 362 } 363 } 364 365 377 private void setComment(final RefactoringDescriptorProxy proxy, final String comment, final IProgressMonitor monitor) throws CoreException { 378 Assert.isNotNull(proxy); 379 Assert.isNotNull(comment); 380 Assert.isNotNull(monitor); 381 try { 382 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_updating_history, 5); 383 final long stamp= proxy.getTimeStamp(); 384 final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 4); 385 try { 386 subMonitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_updating_history, fImplementation.size()); 387 for (final Iterator iterator= fImplementation.iterator(); iterator.hasNext();) { 388 final RefactoringDescriptor descriptor= (RefactoringDescriptor) iterator.next(); 389 subMonitor.worked(1); 390 if (descriptor.getTimeStamp() == stamp) { 391 descriptor.setComment(comment); 392 break; 393 } 394 } 395 } finally { 396 subMonitor.done(); 397 } 398 if (monitor.isCanceled()) 399 throw new OperationCanceledException(); 400 final String name= proxy.getProject(); 401 final RefactoringHistoryManager manager= getManager(name); 402 if (manager != null) 403 manager.setComment(proxy, comment, new SubProgressMonitor(monitor, 1)); 404 else 405 monitor.worked(1); 406 } finally { 407 monitor.done(); 408 } 409 } 410 } 411 412 413 private final class RefactoringOperationHistoryListener implements IOperationHistoryListener { 414 415 416 private RefactoringDescriptor fDescriptor= null; 417 418 421 public void historyNotification(final OperationHistoryEvent event) { 422 IUndoableOperation operation= event.getOperation(); 423 if (operation instanceof TriggeredOperations) 424 operation= ((TriggeredOperations) operation).getTriggeringOperation(); 425 UndoableOperation2ChangeAdapter adapter= null; 426 if (operation instanceof UndoableOperation2ChangeAdapter) 427 adapter= (UndoableOperation2ChangeAdapter) operation; 428 if (adapter != null) { 429 final Change change= adapter.getChange(); 430 switch (event.getEventType()) { 431 case OperationHistoryEvent.ABOUT_TO_EXECUTE: { 432 fDescriptor= null; 433 final ChangeDescriptor changeDescriptor= change.getDescriptor(); 434 if (changeDescriptor instanceof RefactoringChangeDescriptor) { 435 fDescriptor= ((RefactoringChangeDescriptor) changeDescriptor).getRefactoringDescriptor(); 436 fireAboutToPerformEvent(new RefactoringDescriptorProxyAdapter(fDescriptor)); 437 } 438 break; 439 } 440 case OperationHistoryEvent.DONE: { 441 try { 442 if (fDescriptor != null) { 443 if (!fDescriptor.getID().equals(RefactoringDescriptor.ID_UNKNOWN)) { 444 if (fOverrideTimeStamp >= 0) 445 fDescriptor.setTimeStamp(fOverrideTimeStamp); 446 else 447 fDescriptor.setTimeStamp(System.currentTimeMillis()); 448 } 449 fUndoStack.push(fDescriptor); 450 fireRefactoringPerformedEvent(new RefactoringDescriptorProxyAdapter(fDescriptor)); 451 fDescriptor= null; 452 } else 453 fUndoStack.push(NO_REFACTORING); 454 } catch (CoreException exception) { 455 try { 456 fUndoStack.push(NO_REFACTORING); 457 } catch (CoreException impossible) { 458 Assert.isLegal(false); 460 } 461 RefactoringCorePlugin.log(exception); 462 } 463 break; 464 } 465 case OperationHistoryEvent.ABOUT_TO_UNDO: { 466 final RefactoringDescriptor descriptor= fUndoStack.peek(); 467 if (descriptor != NO_REFACTORING) 468 fireAboutToUndoEvent(new RefactoringDescriptorProxyAdapter(descriptor)); 469 break; 470 } 471 case OperationHistoryEvent.UNDONE: { 472 fRedoQueue.addFirst(fUndoStack.peek()); 473 fUndoStack.pop(); 474 final RefactoringDescriptor descriptor= (RefactoringDescriptor) fRedoQueue.getFirst(); 475 if (descriptor != NO_REFACTORING) 476 fireRefactoringUndoneEvent(new RefactoringDescriptorProxyAdapter(descriptor)); 477 break; 478 } 479 case OperationHistoryEvent.ABOUT_TO_REDO: { 480 final RefactoringDescriptor descriptor= (RefactoringDescriptor) fRedoQueue.getFirst(); 481 if (descriptor != NO_REFACTORING) 482 fireAboutToRedoEvent(new RefactoringDescriptorProxyAdapter(descriptor)); 483 break; 484 } 485 case OperationHistoryEvent.REDONE: { 486 try { 487 fUndoStack.push((RefactoringDescriptor) fRedoQueue.removeFirst()); 488 final RefactoringDescriptor descriptor= fUndoStack.peek(); 489 if (descriptor != NO_REFACTORING) 490 fireRefactoringRedoneEvent(new RefactoringDescriptorProxyAdapter(descriptor)); 491 } catch (CoreException exception) { 492 } 494 break; 495 } 496 } 497 } 498 } 499 } 500 501 502 private final class WorkspaceChangeListener implements IResourceChangeListener { 503 504 514 private void moveHistory(final IProject oldProject, final IProject newProject, final IProgressMonitor monitor) { 515 try { 516 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_updating_history, 60); 517 final IFileStore historyStore= EFS.getLocalFileSystem().getStore(RefactoringCorePlugin.getDefault().getStateLocation()).getChild(NAME_HISTORY_FOLDER); 518 final String oldName= oldProject.getName(); 519 final String newName= newProject.getName(); 520 final IFileStore oldStore= historyStore.getChild(oldName); 521 if (oldStore.fetchInfo(EFS.NONE, new SubProgressMonitor(monitor, 10, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)).exists()) { 522 final IFileStore newStore= historyStore.getChild(newName); 523 if (newStore.fetchInfo(EFS.NONE, new SubProgressMonitor(monitor, 10, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)).exists()) 524 newStore.delete(EFS.NONE, new SubProgressMonitor(monitor, 20, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); 525 oldStore.move(newStore, EFS.OVERWRITE, new SubProgressMonitor(monitor, 20, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); 526 } 527 for (final Iterator iterator= fUndoStack.fImplementation.iterator(); iterator.hasNext();) { 528 final RefactoringDescriptor descriptor= (RefactoringDescriptor) iterator.next(); 529 if (oldName.equals(descriptor.getProject())) 530 descriptor.setProject(newName); 531 } 532 for (final Iterator iterator= fRedoQueue.iterator(); iterator.hasNext();) { 533 final RefactoringDescriptor descriptor= (RefactoringDescriptor) iterator.next(); 534 if (oldName.equals(descriptor.getProject())) 535 descriptor.setProject(newName); 536 } 537 } catch (CoreException exception) { 538 RefactoringCorePlugin.log(exception); 539 } finally { 540 monitor.done(); 541 } 542 } 543 544 547 public void resourceChanged(final IResourceChangeEvent event) { 548 final int type= event.getType(); 549 if ((type & IResourceChangeEvent.POST_CHANGE) != 0) { 550 final IResourceDelta delta= event.getDelta(); 551 if (delta != null) { 552 final IResourceDelta[] deltas= delta.getAffectedChildren(); 553 if (deltas.length == 2) { 554 final IPath toPath= deltas[0].getMovedToPath(); 555 final IPath fromPath= deltas[1].getMovedFromPath(); 556 if (fromPath != null && toPath != null) { 557 final IResource oldResource= deltas[0].getResource(); 558 final IResource newResource= deltas[1].getResource(); 559 if (oldResource.getType() == IResource.PROJECT && newResource.getType() == IResource.PROJECT) 560 moveHistory((IProject) oldResource, (IProject) newResource, new NullProgressMonitor()); 561 } else { 562 if (deltas[0].getKind() == IResourceDelta.ADDED && deltas[1].getKind() == IResourceDelta.REMOVED) { 563 final IResource newResource= deltas[0].getResource(); 564 final IResource oldResource= deltas[1].getResource(); 565 if (oldResource.getType() == IResource.PROJECT && newResource.getType() == IResource.PROJECT) 566 moveHistory((IProject) oldResource, (IProject) newResource, new NullProgressMonitor()); 567 } 568 } 569 } 570 } 571 } 572 } 573 } 574 575 576 private static RefactoringHistoryService fInstance= null; 577 578 579 private static final int MAX_UNDO_STACK= 5; 580 581 582 public static final String NAME_HISTORY_FILE= "refactorings.history"; 584 585 public static final String NAME_HISTORY_FOLDER= ".refactorings"; 587 588 public static final String NAME_INDEX_FILE= "refactorings.index"; 590 591 public static final String NAME_WORKSPACE_PROJECT= ".workspace"; 593 594 private static final NullRefactoringHistory NO_HISTORY= new NullRefactoringHistory(); 595 596 597 private static final RefactoringDescriptor NO_REFACTORING= new NoRefactoringDescriptor(); 598 599 622 private static void filterRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies, final Set set, final boolean resolve, final int flags, final IProgressMonitor monitor) { 623 Assert.isTrue(flags > RefactoringDescriptor.NONE); 624 try { 625 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_retrieving_history, proxies.length); 626 for (int offset= 0; offset < proxies.length; offset++) { 627 final RefactoringDescriptor descriptor= proxies[offset].requestDescriptor(new SubProgressMonitor(monitor, 1)); 628 if (descriptor != null) { 629 final int filter= descriptor.getFlags(); 630 if ((filter | flags) == filter) { 631 if (resolve) 632 set.add(new RefactoringDescriptorProxyAdapter(descriptor)); 633 else 634 set.add(proxies[offset]); 635 } 636 } 637 } 638 } finally { 639 monitor.done(); 640 } 641 } 642 643 648 public static RefactoringHistoryService getInstance() { 649 if (fInstance == null) 650 fInstance= new RefactoringHistoryService(); 651 return fInstance; 652 } 653 654 662 public static boolean hasSharedRefactoringHistory(final IProject project) { 663 Assert.isNotNull(project); 664 final IScopeContext[] contexts= new IScopeContext[] { new ProjectScope(project)}; 665 final String preference= Platform.getPreferencesService().getString(RefactoringCorePlugin.getPluginId(), RefactoringPreferenceConstants.PREFERENCE_SHARED_REFACTORING_HISTORY, Boolean.FALSE.toString(), contexts); 666 if (preference != null) 667 return Boolean.valueOf(preference).booleanValue(); 668 return false; 669 } 670 671 705 public static void setSharedRefactoringHistory(final IProject project, final boolean enable, IProgressMonitor monitor) throws CoreException { 706 Assert.isNotNull(project); 707 Assert.isTrue(project.isAccessible()); 708 if (monitor == null) 709 monitor= new NullProgressMonitor(); 710 try { 711 monitor.beginTask("", 300); final String name= project.getName(); 713 final URI uri= project.getLocationURI(); 714 if (uri != null) { 715 try { 716 final IFileStore history= EFS.getLocalFileSystem().getStore(RefactoringCorePlugin.getDefault().getStateLocation()).getChild(NAME_HISTORY_FOLDER); 717 if (enable) { 718 final IFileStore source= history.getChild(name); 719 if (source.fetchInfo(EFS.NONE, new SubProgressMonitor(monitor, 20)).exists()) { 720 IFileStore destination= EFS.getStore(uri).getChild(NAME_HISTORY_FOLDER); 721 if (destination.fetchInfo(EFS.NONE, new SubProgressMonitor(monitor, 20)).exists()) 722 destination.delete(EFS.NONE, new SubProgressMonitor(monitor, 20)); 723 destination.mkdir(EFS.NONE, new SubProgressMonitor(monitor, 20)); 724 source.copy(destination, EFS.OVERWRITE, new SubProgressMonitor(monitor, 20)); 725 source.delete(EFS.NONE, new SubProgressMonitor(monitor, 20)); 726 } 727 } else { 728 final IFileStore source= EFS.getStore(uri).getChild(NAME_HISTORY_FOLDER); 729 if (source.fetchInfo(EFS.NONE, new SubProgressMonitor(monitor, 20)).exists()) { 730 IFileStore destination= history.getChild(name); 731 if (destination.fetchInfo(EFS.NONE, new SubProgressMonitor(monitor, 20)).exists()) 732 destination.delete(EFS.NONE, new SubProgressMonitor(monitor, 20)); 733 destination.mkdir(EFS.NONE, new SubProgressMonitor(monitor, 20)); 734 source.copy(destination, EFS.OVERWRITE, new SubProgressMonitor(monitor, 20)); 735 source.delete(EFS.NONE, new SubProgressMonitor(monitor, 20)); 736 } 737 } 738 } finally { 739 if (enable) 740 project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 30)); 741 else { 742 final IFolder folder= project.getFolder(NAME_HISTORY_FOLDER); 743 if (folder.exists()) 744 folder.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 30)); 745 } 746 } 747 } 748 } finally { 749 monitor.done(); 750 } 751 } 752 753 754 private final ListenerList fExecutionListeners= new ListenerList(ListenerList.EQUALITY); 755 756 757 private final ListenerList fHistoryListeners= new ListenerList(ListenerList.EQUALITY); 758 759 760 private IOperationHistoryListener fOperationListener= null; 761 762 763 private long fOverrideTimeStamp= -1; 764 765 766 private LinkedList fRedoQueue= null; 767 768 769 private int fReferenceCount= 0; 770 771 772 private IResourceChangeListener fResourceListener= null; 773 774 775 private RefactoringDescriptorStack fUndoStack= null; 776 777 780 private RefactoringHistoryService() { 781 } 783 784 787 public void addExecutionListener(final IRefactoringExecutionListener listener) { 788 Assert.isNotNull(listener); 789 fExecutionListeners.add(listener); 790 } 791 792 795 public void addHistoryListener(final IRefactoringHistoryListener listener) { 796 Assert.isNotNull(listener); 797 fHistoryListeners.add(listener); 798 } 799 800 812 public void addRefactoringDescriptor(final RefactoringDescriptorProxy proxy, IProgressMonitor monitor) { 813 Assert.isNotNull(proxy); 814 if (monitor == null) 815 monitor= new NullProgressMonitor(); 816 try { 817 final Object [] listeners= fHistoryListeners.getListeners(); 818 final int size= listeners.length; 819 monitor.beginTask("", size); for (int index= 0; index < size; index++) { 821 final IRefactoringHistoryListener listener= (IRefactoringHistoryListener) listeners[index]; 822 SafeRunner.run(new ISafeRunnable() { 823 824 public void handleException(final Throwable throwable) { 825 RefactoringCorePlugin.log(throwable); 826 } 827 828 public void run() throws Exception { 829 listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.ADDED, proxy)); 830 } 831 }); 832 monitor.worked(1); 833 } 834 } finally { 835 monitor.done(); 836 } 837 } 838 839 842 public void connect() { 843 fReferenceCount++; 844 if (fReferenceCount == 1) { 845 fOperationListener= new RefactoringOperationHistoryListener(); 846 OperationHistoryFactory.getOperationHistory().addOperationHistoryListener(fOperationListener); 847 fResourceListener= new WorkspaceChangeListener(); 848 ResourcesPlugin.getWorkspace().addResourceChangeListener(fResourceListener, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.POST_CHANGE); 849 fUndoStack= new RefactoringDescriptorStack(); 850 fRedoQueue= new LinkedList (); 851 } 852 } 853 854 875 public void deleteRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies, IProgressMonitor monitor) throws CoreException { 876 Assert.isNotNull(proxies); 877 if (monitor == null) 878 monitor= new NullProgressMonitor(); 879 try { 880 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings, proxies.length + 300); 881 final Map projects= new HashMap (); 882 for (int index= 0; index < proxies.length; index++) { 883 String project= proxies[index].getProject(); 884 if (project == null || "".equals(project)) project= RefactoringHistoryService.NAME_WORKSPACE_PROJECT; 886 Collection collection= (Collection ) projects.get(project); 887 if (collection == null) { 888 collection= new ArrayList (); 889 projects.put(project, collection); 890 } 891 collection.add(proxies[index]); 892 monitor.worked(1); 893 } 894 final SubProgressMonitor subMonitor= new SubProgressMonitor(monitor, 300); 895 try { 896 final Set entries= projects.entrySet(); 897 subMonitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings, entries.size()); 898 for (final Iterator iterator= entries.iterator(); iterator.hasNext();) { 899 final Map.Entry entry= (Map.Entry ) iterator.next(); 900 final Collection collection= (Collection ) entry.getValue(); 901 String project= (String ) entry.getKey(); 902 if (project.equals(RefactoringHistoryService.NAME_WORKSPACE_PROJECT)) 903 project= null; 904 final RefactoringHistoryManager manager= fUndoStack.getManager(project); 905 if (manager != null) 906 manager.removeRefactoringDescriptors((RefactoringDescriptorProxy[]) collection.toArray(new RefactoringDescriptorProxy[collection.size()]), new SubProgressMonitor(subMonitor, 1), RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings); 907 else 908 subMonitor.worked(1); 909 } 910 } finally { 911 subMonitor.done(); 912 } 913 } finally { 914 monitor.done(); 915 } 916 } 917 918 941 public void deleteRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies, final IRefactoringDescriptorDeleteQuery query, IProgressMonitor monitor) throws CoreException { 942 Assert.isNotNull(proxies); 943 Assert.isNotNull(query); 944 if (monitor == null) 945 monitor= new NullProgressMonitor(); 946 try { 947 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings, proxies.length + 300); 948 final Set set= new HashSet (proxies.length); 949 for (int index= 0; index < proxies.length; index++) { 950 if (query.proceed(proxies[index]).isOK()) 951 set.add(proxies[index]); 952 monitor.worked(1); 953 } 954 if (!set.isEmpty()) { 955 final RefactoringDescriptorProxy[] delete= (RefactoringDescriptorProxy[]) set.toArray(new RefactoringDescriptorProxy[set.size()]); 956 deleteRefactoringDescriptors(delete, new SubProgressMonitor(monitor, 300)); 957 for (int index= 0; index < delete.length; index++) 958 fireRefactoringDeletedEvent(delete[index]); 959 } 960 } finally { 961 monitor.done(); 962 } 963 } 964 965 987 public void deleteRefactoringHistory(final IProject project, IProgressMonitor monitor) throws CoreException { 988 Assert.isNotNull(project); 989 if (monitor == null) 990 monitor= new NullProgressMonitor(); 991 try { 992 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings, 100); 993 final String name= project.getName(); 994 final IFileStore stateStore= EFS.getLocalFileSystem().getStore(RefactoringCorePlugin.getDefault().getStateLocation()); 995 if (name.equals(NAME_WORKSPACE_PROJECT)) { 996 final IFileStore metaStore= stateStore.getChild(NAME_HISTORY_FOLDER).getChild(name); 997 metaStore.delete(EFS.NONE, new SubProgressMonitor(monitor, 100)); 998 } else { 999 final URI uri= project.getLocationURI(); 1000 if (uri != null && project.isAccessible()) { 1001 try { 1002 final IFileStore metaStore= stateStore.getChild(NAME_HISTORY_FOLDER).getChild(name); 1003 metaStore.delete(EFS.NONE, new SubProgressMonitor(monitor, 20)); 1004 final IFileStore projectStore= EFS.getStore(uri).getChild(NAME_HISTORY_FOLDER); 1005 projectStore.delete(EFS.NONE, new SubProgressMonitor(monitor, 20)); 1006 } finally { 1007 project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 60)); 1008 } 1009 } 1010 } 1011 } finally { 1012 monitor.done(); 1013 } 1014 } 1015 1016 1019 public void disconnect() { 1020 if (fReferenceCount > 0) { 1021 fUndoStack.fManagerCache.clear(); 1022 fReferenceCount--; 1023 } 1024 if (fReferenceCount == 0) { 1025 if (fOperationListener != null) 1026 OperationHistoryFactory.getOperationHistory().removeOperationHistoryListener(fOperationListener); 1027 if (fResourceListener != null) 1028 ResourcesPlugin.getWorkspace().removeResourceChangeListener(fResourceListener); 1029 fUndoStack= null; 1030 fRedoQueue= null; 1031 fOperationListener= null; 1032 } 1033 } 1034 1035 1041 void fireAboutToPerformEvent(final RefactoringDescriptorProxy proxy) { 1042 Assert.isNotNull(proxy); 1043 final Object [] listeners= fExecutionListeners.getListeners(); 1044 for (int index= 0; index < listeners.length; index++) { 1045 final IRefactoringExecutionListener listener= (IRefactoringExecutionListener) listeners[index]; 1046 SafeRunner.run(new ISafeRunnable() { 1047 1048 public final void handleException(final Throwable throwable) { 1049 RefactoringCorePlugin.log(throwable); 1050 } 1051 1052 public void run() throws Exception { 1053 listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.ABOUT_TO_PERFORM, proxy)); 1054 } 1055 }); 1056 } 1057 } 1058 1059 1065 void fireAboutToRedoEvent(final RefactoringDescriptorProxy proxy) { 1066 Assert.isNotNull(proxy); 1067 final Object [] listeners= fExecutionListeners.getListeners(); 1068 for (int index= 0; index < listeners.length; index++) { 1069 final IRefactoringExecutionListener listener= (IRefactoringExecutionListener) listeners[index]; 1070 SafeRunner.run(new ISafeRunnable() { 1071 1072 public void handleException(final Throwable throwable) { 1073 RefactoringCorePlugin.log(throwable); 1074 } 1075 1076 public void run() throws Exception { 1077 listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.ABOUT_TO_REDO, proxy)); 1078 } 1079 }); 1080 } 1081 } 1082 1083 1089 void fireAboutToUndoEvent(final RefactoringDescriptorProxy proxy) { 1090 Assert.isNotNull(proxy); 1091 final Object [] listeners= fExecutionListeners.getListeners(); 1092 for (int index= 0; index < listeners.length; index++) { 1093 final IRefactoringExecutionListener listener= (IRefactoringExecutionListener) listeners[index]; 1094 SafeRunner.run(new ISafeRunnable() { 1095 1096 public void handleException(final Throwable throwable) { 1097 RefactoringCorePlugin.log(throwable); 1098 } 1099 1100 public void run() throws Exception { 1101 listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.ABOUT_TO_UNDO, proxy)); 1102 } 1103 }); 1104 } 1105 } 1106 1107 1113 void fireRefactoringDeletedEvent(final RefactoringDescriptorProxy proxy) { 1114 Assert.isNotNull(proxy); 1115 final Object [] listeners= fHistoryListeners.getListeners(); 1116 for (int index= 0; index < listeners.length; index++) { 1117 final IRefactoringHistoryListener listener= (IRefactoringHistoryListener) listeners[index]; 1118 SafeRunner.run(new ISafeRunnable() { 1119 1120 public void handleException(final Throwable throwable) { 1121 RefactoringCorePlugin.log(throwable); 1122 } 1123 1124 public void run() throws Exception { 1125 listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.DELETED, proxy)); 1126 } 1127 }); 1128 } 1129 } 1130 1131 1137 void fireRefactoringPerformedEvent(final RefactoringDescriptorProxy proxy) { 1138 Assert.isNotNull(proxy); 1139 final Object [] listeners= fExecutionListeners.getListeners(); 1140 for (int index= 0; index < listeners.length; index++) { 1141 final IRefactoringExecutionListener listener= (IRefactoringExecutionListener) listeners[index]; 1142 SafeRunner.run(new ISafeRunnable() { 1143 1144 public void handleException(final Throwable throwable) { 1145 RefactoringCorePlugin.log(throwable); 1146 } 1147 1148 public void run() throws Exception { 1149 listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.PERFORMED, proxy)); 1150 } 1151 }); 1152 } 1153 } 1154 1155 1161 void fireRefactoringRedoneEvent(final RefactoringDescriptorProxy proxy) { 1162 Assert.isNotNull(proxy); 1163 final Object [] listeners= fExecutionListeners.getListeners(); 1164 for (int index= 0; index < listeners.length; index++) { 1165 final IRefactoringExecutionListener listener= (IRefactoringExecutionListener) listeners[index]; 1166 SafeRunner.run(new ISafeRunnable() { 1167 1168 public void handleException(final Throwable throwable) { 1169 RefactoringCorePlugin.log(throwable); 1170 } 1171 1172 public void run() throws Exception { 1173 listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.REDONE, proxy)); 1174 } 1175 }); 1176 } 1177 } 1178 1179 1185 void fireRefactoringUndoneEvent(final RefactoringDescriptorProxy proxy) { 1186 Assert.isNotNull(proxy); 1187 final Object [] listeners= fExecutionListeners.getListeners(); 1188 for (int index= 0; index < listeners.length; index++) { 1189 final IRefactoringExecutionListener listener= (IRefactoringExecutionListener) listeners[index]; 1190 SafeRunner.run(new ISafeRunnable() { 1191 1192 public void handleException(final Throwable throwable) { 1193 RefactoringCorePlugin.log(throwable); 1194 } 1195 1196 public void run() throws Exception { 1197 listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.UNDONE, proxy)); 1198 } 1199 }); 1200 } 1201 } 1202 1203 1206 public RefactoringHistory getProjectHistory(final IProject project, IProgressMonitor monitor) { 1207 return getProjectHistory(project, 0, Long.MAX_VALUE, RefactoringDescriptor.NONE, monitor); 1208 } 1209 1210 1213 public RefactoringHistory getProjectHistory(final IProject project, final long start, final long end, final int flags, IProgressMonitor monitor) { 1214 Assert.isNotNull(project); 1215 Assert.isTrue(project.exists()); 1216 Assert.isTrue(start >= 0); 1217 Assert.isTrue(end >= 0); 1218 Assert.isTrue(flags >= RefactoringDescriptor.NONE); 1219 if (project.isOpen()) { 1220 if (monitor == null) 1221 monitor= new NullProgressMonitor(); 1222 try { 1223 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_retrieving_history, 120); 1224 final String name= project.getName(); 1225 final RefactoringHistoryManager manager= fUndoStack.getManager(name); 1226 if (manager != null) { 1227 RefactoringHistory history= manager.readRefactoringHistory(start, end, new SubProgressMonitor(monitor, 20)); 1228 if (flags > RefactoringDescriptor.NONE) { 1229 final Set set= new HashSet (); 1230 filterRefactoringDescriptors(history.getDescriptors(), set, false, flags, new SubProgressMonitor(monitor, 100)); 1231 history= new RefactoringHistoryImplementation((RefactoringDescriptorProxy[]) set.toArray(new RefactoringDescriptorProxy[set.size()])); 1232 } 1233 return history; 1234 } 1235 } finally { 1236 monitor.done(); 1237 } 1238 } 1239 return NO_HISTORY; 1240 } 1241 1242 1245 public RefactoringHistory getRefactoringHistory(final IProject[] projects, final IProgressMonitor monitor) { 1246 return getRefactoringHistory(projects, 0, Long.MAX_VALUE, RefactoringDescriptor.NONE, monitor); 1247 } 1248 1249 1252 public RefactoringHistory getRefactoringHistory(final IProject[] projects, final long start, final long end, final int flags, IProgressMonitor monitor) { 1253 Assert.isNotNull(projects); 1254 Assert.isTrue(start >= 0); 1255 Assert.isTrue(end >= start); 1256 Assert.isTrue(flags >= RefactoringDescriptor.NONE); 1257 if (monitor == null) 1258 monitor= new NullProgressMonitor(); 1259 try { 1260 monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_retrieving_history, 3 * projects.length); 1261 final Set set= new HashSet (); 1262 if (flags > RefactoringDescriptor.NONE) { 1263 for (int index= 0; index < projects.length; index++) { 1264 final IProject project= projects[index]; 1265 if (project.isAccessible()) { 1266 final RefactoringDescriptorProxy[] proxies= getProjectHistory(project, start, end, flags, new SubProgressMonitor(monitor, 1)).getDescriptors(); 1267 filterRefactoringDescriptors(proxies, set, false, flags, new SubProgressMonitor(monitor, 2)); 1268 } 1269 } 1270 } else { 1271 for (int index= 0; index < projects.length; index++) { 1272 final IProject project= projects[index]; 1273 if (project.isAccessible()) { 1274 final RefactoringDescriptorProxy[] proxies= getProjectHistory(project, start, end, RefactoringDescriptor.NONE, new SubProgressMonitor(monitor, 3)).getDescriptors(); 1275 for (int offset= 0; offset < proxies.length; offset++) 1276 set.add(proxies[offset]); 1277 } 1278 } 1279 } 1280 final RefactoringDescriptorProxy[] proxies= new RefactoringDescriptorProxy[set.size()]; 1281 set.toArray(proxies); 1282 return new RefactoringHistoryImplementation(proxies); 1283 } finally { 1284 monitor.done(); 1285 } 1286 } 1287 1288 1291 public RefactoringHistory getWorkspaceHistory(IProgressMonitor monitor) { 1292 return getWorkspaceHistory(0, Long.MAX_VALUE, monitor); 1293 } 1294 1295 1298 public RefactoringHistory getWorkspaceHistory(final long start, final long end, IProgressMonitor monitor) { 1299 return getRefactoringHistory(ResourcesPlugin.getWorkspace().getRoot().getProjects(), start, end, RefactoringDescriptor.NONE, monitor); 1300 } 1301 1302 1320 public RefactoringDescriptorProxy[] readRefactoringDescriptorProxies(final InputStream stream) throws CoreException { 1321 Assert.isNotNull(stream); 1322 try { 1323 return RefactoringHistoryManager.readRefactoringDescriptorProxies(stream, null, 0, Long.MAX_VALUE); 1324 } catch (IOException exception) { 1325 throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), 0, exception.getLocalizedMessage(), null)); 1326 } 1327 } 1328 1329 1332 public RefactoringHistory readRefactoringHistory(final InputStream stream, final int flags) throws CoreException { 1333 Assert.isNotNull(stream); 1334 Assert.isTrue(flags >= RefactoringDescriptor.NONE); 1335 final List list= new ArrayList (); 1336 final RefactoringSessionDescriptor descriptor= new RefactoringSessionReader(true).readSession(new InputSource (stream)); 1337 if (descriptor != null) { 1338 final RefactoringDescriptor[] descriptors= descriptor.getRefactorings(); 1339 if (flags > RefactoringDescriptor.NONE) { 1340 for (int index= 0; index < descriptors.length; index++) { 1341 final int current= descriptors[index].getFlags(); 1342 if ((current | flags) == current) 1343 list.add(descriptors[index]); 1344 } 1345 } else 1346 list.addAll(Arrays.asList(descriptors)); 1347 } 1348 final RefactoringDescriptorProxy[] proxies= new RefactoringDescriptorProxy[list.size()]; 1349 for (int index= 0; index < list.size(); index++) 1350 proxies[index]= new RefactoringDescriptorProxyAdapter((RefactoringDescriptor) list.get(index)); 1351 return new RefactoringHistoryImplementation(proxies); 1352 } 1353 1354 1357 public void removeExecutionListener(final IRefactoringExecutionListener listener) { 1358 Assert.isNotNull(listener); 1359 fExecutionListeners.remove(listener); 1360 } 1361 1362 1365 public void removeHistoryListener(final IRefactoringHistoryListener listener) { 1366 Assert.isNotNull(listener); 1367 fHistoryListeners.remove(listener); 1368 } 1369 1370 1384 public RefactoringDescriptor requestDescriptor(final RefactoringDescriptorProxy proxy, IProgressMonitor monitor) { 1385 Assert.isNotNull(proxy); 1386 Assert.isNotNull(fUndoStack); 1387 if (monitor == null) 1388 monitor= new NullProgressMonitor(); 1389 return fUndoStack.requestDescriptor(proxy, monitor); 1390 } 1391 1392 1398 public void setOverrideTimeStamp(final long stamp) { 1399 Assert.isTrue(stamp == -1 || stamp >= 0); 1400 fOverrideTimeStamp= stamp; 1401 } 1402 1403 1426 public void setRefactoringComment(final RefactoringDescriptorProxy proxy, final String comment, IProgressMonitor monitor) throws CoreException { 1427 Assert.isNotNull(proxy); 1428 if (monitor == null) 1429 monitor= new NullProgressMonitor(); 1430 fUndoStack.setComment(proxy, comment, monitor); 1431 } 1432 1433 1436 public void writeRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies, final OutputStream stream, final int flags, final boolean time, IProgressMonitor monitor) throws CoreException { 1437 Assert.isNotNull(proxies); 1438 Assert.isNotNull(stream); 1439 Assert.isTrue(flags >= RefactoringDescriptor.NONE); 1440 if (monitor == null) 1441 monitor= new NullProgressMonitor(); 1442 try { 1443 monitor.beginTask("", 100 * proxies.length); connect(); 1445 final List list= new ArrayList (proxies.length); 1446 for (int index= 0; index < proxies.length; index++) { 1447 final RefactoringDescriptor descriptor= proxies[index].requestDescriptor(new SubProgressMonitor(monitor, 100)); 1448 if (descriptor != null) { 1449 final int current= descriptor.getFlags(); 1450 if ((current | flags) == current) 1451 list.add(descriptor); 1452 } 1453 } 1454 final RefactoringDescriptor[] descriptors= new RefactoringDescriptor[list.size()]; 1455 list.toArray(descriptors); 1456 RefactoringHistoryManager.writeRefactoringSession(stream, new RefactoringSessionDescriptor(descriptors, IRefactoringSerializationConstants.CURRENT_VERSION, null), time); 1457 } finally { 1458 disconnect(); 1459 } 1460 } 1461 1462 1465 public void writeRefactoringSession(final RefactoringSessionDescriptor descriptor, final OutputStream stream, final boolean time) throws CoreException { 1466 Assert.isNotNull(descriptor); 1467 Assert.isNotNull(stream); 1468 RefactoringHistoryManager.writeRefactoringSession(stream, descriptor, time); 1469 } 1470} 1471 | Popular Tags |