KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ltk > internal > core > refactoring > history > RefactoringHistoryService


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ltk.internal.core.refactoring.history;
12
13 import com.ibm.icu.text.DateFormat;
14
15 import java.io.IOException JavaDoc;
16 import java.io.InputStream JavaDoc;
17 import java.io.OutputStream JavaDoc;
18 import java.net.URI JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Arrays JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Date JavaDoc;
23 import java.util.EmptyStackException JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.LinkedHashMap JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
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 JavaDoc;
90
91 /**
92  * Default implementation of a refactoring history service.
93  *
94  * @since 3.2
95  */

96 public final class RefactoringHistoryService implements IRefactoringHistoryService {
97
98     /** Refactoring descriptor to denote a non-refactoring change */
99     private static final class NoRefactoringDescriptor extends RefactoringDescriptor {
100
101         /**
102          * Creates a new no refactoring descriptor.
103          */

104         private NoRefactoringDescriptor() {
105             super("org.eclipse.ltk.core.refactoring.none", null, "N/A", null, RefactoringDescriptor.NONE); //$NON-NLS-1$ //$NON-NLS-2$
106
}
107
108         /**
109          * {@inheritDoc}
110          */

111         public Refactoring createRefactoring(final RefactoringStatus status) throws CoreException {
112             return null;
113         }
114     }
115
116     /** The null refactoring history */
117     private static final class NullRefactoringHistory extends RefactoringHistory {
118
119         /** The no proxies constant */
120         private static final RefactoringDescriptorProxy[] NO_PROXIES= {};
121
122         /**
123          * {@inheritDoc}
124          */

125         public RefactoringDescriptorProxy[] getDescriptors() {
126             return NO_PROXIES;
127         }
128
129         /**
130          * {@inheritDoc}
131          */

132         public boolean isEmpty() {
133             return true;
134         }
135
136         /**
137          * {@inheritDoc}
138          */

139         public RefactoringHistory removeAll(final RefactoringHistory history) {
140             return this;
141         }
142     }
143
144     /** Stack of refactoring descriptors */
145     private final class RefactoringDescriptorStack {
146
147         /** Maximal number of refactoring managers */
148         private static final int MAX_MANAGERS= 2;
149
150         /** The internal implementation */
151         private final LinkedList JavaDoc fImplementation= new LinkedList JavaDoc();
152
153         /**
154          * The refactoring history manager cache (element type:
155          * <code>&lt;IFileStore, RefactoringHistoryManager&gt;</code>)
156          */

157         private final Map JavaDoc fManagerCache= new LinkedHashMap JavaDoc(MAX_MANAGERS, 0.75f, true) {
158
159             private static final long serialVersionUID= 1L;
160
161             protected final boolean removeEldestEntry(final Map.Entry JavaDoc entry) {
162                 return size() > MAX_MANAGERS;
163             }
164         };
165
166         /**
167          * Checks whether the refactoring descriptor is valid according to the
168          * API of {@link RefactoringDescriptor}.
169          *
170          * @param descriptor
171          * the refactoring descriptor to check
172          * @throws CoreException
173          * if the refactoring descriptor is invalid
174          */

175         private void checkDescriptor(final RefactoringDescriptor descriptor) throws CoreException {
176             final Map JavaDoc arguments= RefactoringHistoryManager.getArgumentMap(descriptor);
177             if (arguments != null)
178                 RefactoringHistoryManager.checkArgumentMap(arguments);
179         }
180
181         /**
182          * Returns the cached refactoring history manager for the specified
183          * history location.
184          *
185          * @param store
186          * the file store describing the history location
187          * @param name
188          * the non-empty project name, or <code>null</code> for the
189          * workspace
190          * @return the refactoring history manager
191          */

192         private RefactoringHistoryManager getManager(final IFileStore store, final String JavaDoc 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         /**
203          * Returns the refactoring history manager corresponding to the project
204          * with the specified name.
205          *
206          * @param name
207          * the name of the project, or <code>null</code> for the
208          * workspace
209          * @return the refactoring history manager, or <code>null</code>
210          */

211         private RefactoringHistoryManager getManager(final String JavaDoc name) {
212             final IFileStore store= EFS.getLocalFileSystem().getStore(RefactoringCorePlugin.getDefault().getStateLocation()).getChild(NAME_HISTORY_FOLDER);
213             if (name != null && !"".equals(name)) {//$NON-NLS-1$
214
try {
215                     final IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(name);
216                     if (project.isAccessible()) {
217                         if (hasSharedRefactoringHistory(project)) {
218                             final URI JavaDoc 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                     // Do nothing
226
}
227             } else
228                 return getManager(store.getChild(NAME_WORKSPACE_PROJECT), null);
229             return null;
230         }
231
232         /**
233          * Returns the current descriptor on the top of the stack.
234          *
235          * @return the current descriptor on top
236          * @throws EmptyStackException
237          * if the stack is empty
238          */

239         private RefactoringDescriptor peek() throws EmptyStackException JavaDoc {
240             if (!fImplementation.isEmpty())
241                 return (RefactoringDescriptor) fImplementation.getFirst();
242             throw new EmptyStackException JavaDoc();
243         }
244
245         /**
246          * Pops the top descriptor off the stack.
247          *
248          * @throws EmptyStackException
249          * if the stack is empty
250          */

251         private void pop() throws EmptyStackException JavaDoc {
252             final RefactoringDescriptor descriptor= peek();
253             if (!fImplementation.isEmpty())
254                 fImplementation.removeFirst();
255             else
256                 throw new EmptyStackException JavaDoc();
257             final Object JavaDoc[] 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 JavaDoc throwable) {
263                         RefactoringCorePlugin.log(throwable);
264                     }
265
266                     public void run() throws Exception JavaDoc {
267                         listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.POPPED, new RefactoringDescriptorProxyAdapter(descriptor)));
268                     }
269                 });
270             }
271         }
272
273         /**
274          * Pushes the given descriptor onto the stack.
275          *
276          * @param descriptor
277          * the descriptor to push onto the stack
278          * @throws CoreException
279          * if the refactoring descriptor is invalid
280          */

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 JavaDoc time= DateFormat.getDateTimeInstance().format(new Date JavaDoc(descriptor.getTimeStamp()));
289                     final String JavaDoc message= "The refactoring executed at " + time + " contributed a refactoring descriptor with invalid format:"; //$NON-NLS-1$//$NON-NLS-2$
290
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 JavaDoc[] 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 JavaDoc throwable) {
305                         RefactoringCorePlugin.log(throwable);
306                     }
307
308                     public void run() throws Exception JavaDoc {
309                         listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.PUSHED, new RefactoringDescriptorProxyAdapter(descriptor)));
310                     }
311                 });
312             }
313         }
314
315         /**
316          * Requests the resolved refactoring descriptor associated with the
317          * given proxy.
318          *
319          * @param proxy
320          * the refactoring descriptor proxy
321          * @param monitor
322          * the progress monitor to use
323          *
324          * @return the resolved refactoring descriptor, or <code>null</code>
325          */

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 JavaDoc 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         /**
366          * Sets the comment of the specified refactoring.
367          *
368          * @param proxy
369          * the refactoring descriptor proxy
370          * @param comment
371          * the comment
372          * @param monitor
373          * the progress monitor to use
374          * @throws CoreException
375          * if an error occurs while setting the comment
376          */

377         private void setComment(final RefactoringDescriptorProxy proxy, final String JavaDoc 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 JavaDoc 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 JavaDoc 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     /** Operation history listener for refactoring operation events */
413     private final class RefactoringOperationHistoryListener implements IOperationHistoryListener {
414
415         /** The last recently performed refactoring */
416         private RefactoringDescriptor fDescriptor= null;
417
418         /**
419          * {@inheritDoc}
420          */

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                                 // Cannot happen
459
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                             // Cannot happen
493
}
494                         break;
495                     }
496                 }
497             }
498         }
499     }
500
501     /** Workspace resource change listener */
502     private final class WorkspaceChangeListener implements IResourceChangeListener {
503
504         /**
505          * Moves the project history from the old project to the new one.
506          *
507          * @param oldProject
508          * the old project, which does not exist anymore
509          * @param newProject
510          * the new project, which already exists
511          * @param monitor
512          * the progress monitor to use
513          */

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 JavaDoc oldName= oldProject.getName();
519                 final String JavaDoc 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 JavaDoc 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 JavaDoc 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         /**
545          * {@inheritDoc}
546          */

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     /** The singleton history */
576     private static RefactoringHistoryService fInstance= null;
577
578     /** The maximum size of the undo stack */
579     private static final int MAX_UNDO_STACK= 5;
580
581     /** The refactoring history file */
582     public static final String JavaDoc NAME_HISTORY_FILE= "refactorings.history"; //$NON-NLS-1$
583

584     /** The refactoring history folder */
585     public static final String JavaDoc NAME_HISTORY_FOLDER= ".refactorings"; //$NON-NLS-1$
586

587     /** The refactoring history index file name */
588     public static final String JavaDoc NAME_INDEX_FILE= "refactorings.index"; //$NON-NLS-1$
589

590     /** The name of the special workspace project */
591     public static final String JavaDoc NAME_WORKSPACE_PROJECT= ".workspace"; //$NON-NLS-1$
592

593     /** The no history constant */
594     private static final NullRefactoringHistory NO_HISTORY= new NullRefactoringHistory();
595
596     /** The no refactoring descriptor constant */
597     private static final RefactoringDescriptor NO_REFACTORING= new NoRefactoringDescriptor();
598
599     /**
600      * Filters the given array of refactoring proxies and returns the result in
601      * the specified refactoring descriptor proxy set.
602      * <p>
603      * Clients wishing to benefit from the resolving of refactoring descriptors
604      * to determine its flags can set resolve to <code>true</code> if they
605      * would like to have resolved refactoring descriptor proxies as result.
606      * </p>
607      *
608      * @param proxies
609      * the refactoring descriptor proxies
610      * @param set
611      * the result set
612      * @param resolve
613      * <code>true</code> to return the filtered refactoring
614      * descriptors as resolved refactoring proxies,
615      * <code>false</code> otherwise
616      * @param flags
617      * the refactoring descriptor flags which must be present in
618      * order to be returned in the refactoring history object
619      * @param monitor
620      * the progress monitor to use
621      */

622     private static void filterRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies, final Set JavaDoc 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     /**
644      * Returns the singleton instance of the refactoring history.
645      *
646      * @return the singleton instance
647      */

648     public static RefactoringHistoryService getInstance() {
649         if (fInstance == null)
650             fInstance= new RefactoringHistoryService();
651         return fInstance;
652     }
653
654     /**
655      * Returns whether a project has a shared refactoring history.
656      *
657      * @param project
658      * the project to test
659      * @return <code>true</code> if the project has a shared project history,
660      * <code>false</code> otherwise
661      */

662     public static boolean hasSharedRefactoringHistory(final IProject project) {
663         Assert.isNotNull(project);
664         final IScopeContext[] contexts= new IScopeContext[] { new ProjectScope(project)};
665         final String JavaDoc 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     /**
672      * Determines whether a project has a shared refactoring history.
673      * <p>
674      * If a shared refactoring history is enabled, refactorings executed on that
675      * particular project are stored in a hidden refactoring history folder of
676      * the project folder. If no shared refactoring history is enabled, all
677      * refactorings are tracked as well, but persisted internally in a
678      * plugin-specific way without altering the project.
679      * </p>
680      * <p>
681      * Note: this method simply copies the content of the refactoring history
682      * folder to the location corresponding to the shared history setting.
683      * Clients wishing to programmatically change the refactoring history
684      * location have to update the preference
685      * {@link RefactoringPreferenceConstants#PREFERENCE_SHARED_REFACTORING_HISTORY}
686      * located in the preference store of the
687      * <code>org.eclipse.ltk.core.refactoring</code> plugin accordingly.
688      * </p>
689      *
690      * @param project
691      * the project to set the shared refactoring history property
692      * @param enable
693      * <code>true</code> to enable a shared refactoring history,
694      * <code>false</code> otherwise
695      * @param monitor
696      * the progress monitor to use, or <code>null</code>
697      * @throws CoreException
698      * if an error occurs while changing the shared refactoring
699      * history property. Reasons include:
700      * <ul>
701      * <li>An I/O error occurs while changing the shared
702      * refactoring history property.</li>
703      * </ul>
704      */

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); //$NON-NLS-1$
712
final String JavaDoc name= project.getName();
713             final URI JavaDoc 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     /** The execution listeners */
754     private final ListenerList fExecutionListeners= new ListenerList(ListenerList.EQUALITY);
755
756     /** The history listeners */
757     private final ListenerList fHistoryListeners= new ListenerList(ListenerList.EQUALITY);
758
759     /** The operation listener, or <code>null</code> */
760     private IOperationHistoryListener fOperationListener= null;
761
762     /** The override time stamp */
763     private long fOverrideTimeStamp= -1;
764
765     /** The redo refactoring descriptor queue, or <code>null</code> */
766     private LinkedList JavaDoc fRedoQueue= null;
767
768     /** The history reference count */
769     private int fReferenceCount= 0;
770
771     /** The resource listener, or <code>null</code> */
772     private IResourceChangeListener fResourceListener= null;
773
774     /** The undo refactoring descriptor stack, or <code>null</code> */
775     private RefactoringDescriptorStack fUndoStack= null;
776
777     /**
778      * Creates a new refactoring history.
779      */

780     private RefactoringHistoryService() {
781         // Do nothing
782
}
783
784     /**
785      * {@inheritDoc}
786      */

787     public void addExecutionListener(final IRefactoringExecutionListener listener) {
788         Assert.isNotNull(listener);
789         fExecutionListeners.add(listener);
790     }
791
792     /**
793      * {@inheritDoc}
794      */

795     public void addHistoryListener(final IRefactoringHistoryListener listener) {
796         Assert.isNotNull(listener);
797         fHistoryListeners.add(listener);
798     }
799
800     /**
801      * Adds the specified refactoring descriptor to the corresponding
802      * refactoring history.
803      * <p>
804      * If a descriptor with the same timestamp already exists, nothing happens.
805      * </p>
806      *
807      * @param proxy
808      * the refactoring descriptor proxy
809      * @param monitor
810      * the progress monitor to use, or <code>null</code>
811      */

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 JavaDoc[] listeners= fHistoryListeners.getListeners();
818             final int size= listeners.length;
819             monitor.beginTask("", size); //$NON-NLS-1$
820
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 JavaDoc throwable) {
825                         RefactoringCorePlugin.log(throwable);
826                     }
827
828                     public void run() throws Exception JavaDoc {
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     /**
840      * {@inheritDoc}
841      */

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 JavaDoc();
851         }
852     }
853
854     /**
855      * Deletes the specified refactoring descriptors from their associated
856      * refactoring histories.
857      *
858      * @param proxies
859      * the refactoring descriptor proxies
860      * @param monitor
861      * the progress monitor to use, or <code>null</code>
862      * @throws CoreException
863      * if an error occurs while deleting the refactoring
864      * descriptors. Reasons include:
865      * <ul>
866      * <li>The refactoring history has an illegal format, contains
867      * illegal arguments or otherwise illegal information.</li>
868      * <li>An I/O error occurs while deleting the refactoring
869      * descriptors from the refactoring history.</li>
870      * </ul>
871      *
872      * @see IRefactoringCoreStatusCodes#REFACTORING_HISTORY_FORMAT_ERROR
873      * @see IRefactoringCoreStatusCodes#REFACTORING_HISTORY_IO_ERROR
874      */

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 JavaDoc projects= new HashMap JavaDoc();
882             for (int index= 0; index < proxies.length; index++) {
883                 String JavaDoc project= proxies[index].getProject();
884                 if (project == null || "".equals(project)) //$NON-NLS-1$
885
project= RefactoringHistoryService.NAME_WORKSPACE_PROJECT;
886                 Collection JavaDoc collection= (Collection JavaDoc) projects.get(project);
887                 if (collection == null) {
888                     collection= new ArrayList JavaDoc();
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 JavaDoc entries= projects.entrySet();
897                 subMonitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings, entries.size());
898                 for (final Iterator JavaDoc iterator= entries.iterator(); iterator.hasNext();) {
899                     final Map.Entry JavaDoc entry= (Map.Entry JavaDoc) iterator.next();
900                     final Collection JavaDoc collection= (Collection JavaDoc) entry.getValue();
901                     String JavaDoc project= (String JavaDoc) 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     /**
919      * Deletes the specified refactoring descriptors from their associated
920      * refactoring histories.
921      *
922      * @param proxies
923      * the refactoring descriptor proxies
924      * @param query
925      * the refactoring descriptor delete query to use
926      * @param monitor
927      * the progress monitor to use, or <code>null</code>
928      * @throws CoreException
929      * if an error occurs while deleting the refactoring
930      * descriptors. Reasons include:
931      * <ul>
932      * <li>The refactoring history has an illegal format, contains
933      * illegal arguments or otherwise illegal information.</li>
934      * <li>An I/O error occurs while deleting the refactoring
935      * descriptors from the refactoring history.</li>
936      * </ul>
937      *
938      * @see IRefactoringCoreStatusCodes#REFACTORING_HISTORY_FORMAT_ERROR
939      * @see IRefactoringCoreStatusCodes#REFACTORING_HISTORY_IO_ERROR
940      */

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 JavaDoc set= new HashSet JavaDoc(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     /**
966      * Deletes the refactoring history of a project. Refactorings associated
967      * with the workspace are not deleted.
968      * <p>
969      * If a refactoring history is deleted, all files stored in the hidden
970      * refactoring history folder of the project folder are removed. If no
971      * shared refactoring history is enabled, the refactoring history
972      * information is removed from the internal workspace refactoring history.
973      * </p>
974      *
975      * @param project
976      * the project to delete its history
977      * @param monitor
978      * the progress monitor to use, or <code>null</code>
979      * @throws CoreException
980      * if an error occurs while deleting the refactoring history.
981      * Reasons include:
982      * <ul>
983      * <li>An I/O error occurs while deleting the refactoring
984      * history.</li>
985      * </ul>
986      */

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 JavaDoc 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 JavaDoc 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    /**
1017     * {@inheritDoc}
1018     */

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    /**
1036     * Fires the about to perform event.
1037     *
1038     * @param proxy
1039     * the refactoring descriptor proxy
1040     */

1041    void fireAboutToPerformEvent(final RefactoringDescriptorProxy proxy) {
1042        Assert.isNotNull(proxy);
1043        final Object JavaDoc[] 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 JavaDoc throwable) {
1049                    RefactoringCorePlugin.log(throwable);
1050                }
1051
1052                public void run() throws Exception JavaDoc {
1053                    listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.ABOUT_TO_PERFORM, proxy));
1054                }
1055            });
1056        }
1057    }
1058
1059    /**
1060     * Fires the about to redo event.
1061     *
1062     * @param proxy
1063     * the refactoring descriptor proxy
1064     */

1065    void fireAboutToRedoEvent(final RefactoringDescriptorProxy proxy) {
1066        Assert.isNotNull(proxy);
1067        final Object JavaDoc[] 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 JavaDoc throwable) {
1073                    RefactoringCorePlugin.log(throwable);
1074                }
1075
1076                public void run() throws Exception JavaDoc {
1077                    listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.ABOUT_TO_REDO, proxy));
1078                }
1079            });
1080        }
1081    }
1082
1083    /**
1084     * Fires the about to undo event.
1085     *
1086     * @param proxy
1087     * the refactoring descriptor proxy
1088     */

1089    void fireAboutToUndoEvent(final RefactoringDescriptorProxy proxy) {
1090        Assert.isNotNull(proxy);
1091        final Object JavaDoc[] 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 JavaDoc throwable) {
1097                    RefactoringCorePlugin.log(throwable);
1098                }
1099
1100                public void run() throws Exception JavaDoc {
1101                    listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.ABOUT_TO_UNDO, proxy));
1102                }
1103            });
1104        }
1105    }
1106
1107    /**
1108     * Fires the refactoring deleted event.
1109     *
1110     * @param proxy
1111     * the refactoring descriptor proxy
1112     */

1113    void fireRefactoringDeletedEvent(final RefactoringDescriptorProxy proxy) {
1114        Assert.isNotNull(proxy);
1115        final Object JavaDoc[] 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 JavaDoc throwable) {
1121                    RefactoringCorePlugin.log(throwable);
1122                }
1123
1124                public void run() throws Exception JavaDoc {
1125                    listener.historyNotification(new RefactoringHistoryEvent(RefactoringHistoryService.this, RefactoringHistoryEvent.DELETED, proxy));
1126                }
1127            });
1128        }
1129    }
1130
1131    /**
1132     * Fires the refactoring performed event.
1133     *
1134     * @param proxy
1135     * the refactoring descriptor proxy
1136     */

1137    void fireRefactoringPerformedEvent(final RefactoringDescriptorProxy proxy) {
1138        Assert.isNotNull(proxy);
1139        final Object JavaDoc[] 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 JavaDoc throwable) {
1145                    RefactoringCorePlugin.log(throwable);
1146                }
1147
1148                public void run() throws Exception JavaDoc {
1149                    listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.PERFORMED, proxy));
1150                }
1151            });
1152        }
1153    }
1154
1155    /**
1156     * Fires the refactoring redone event.
1157     *
1158     * @param proxy
1159     * the refactoring descriptor proxy
1160     */

1161    void fireRefactoringRedoneEvent(final RefactoringDescriptorProxy proxy) {
1162        Assert.isNotNull(proxy);
1163        final Object JavaDoc[] 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 JavaDoc throwable) {
1169                    RefactoringCorePlugin.log(throwable);
1170                }
1171
1172                public void run() throws Exception JavaDoc {
1173                    listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.REDONE, proxy));
1174                }
1175            });
1176        }
1177    }
1178
1179    /**
1180     * Fires the refactoring undone event.
1181     *
1182     * @param proxy
1183     * the refactoring descriptor proxy
1184     */

1185    void fireRefactoringUndoneEvent(final RefactoringDescriptorProxy proxy) {
1186        Assert.isNotNull(proxy);
1187        final Object JavaDoc[] 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 JavaDoc throwable) {
1193                    RefactoringCorePlugin.log(throwable);
1194                }
1195
1196                public void run() throws Exception JavaDoc {
1197                    listener.executionNotification(new RefactoringExecutionEvent(RefactoringHistoryService.this, RefactoringExecutionEvent.UNDONE, proxy));
1198                }
1199            });
1200        }
1201    }
1202
1203    /**
1204     * {@inheritDoc}
1205     */

1206    public RefactoringHistory getProjectHistory(final IProject project, IProgressMonitor monitor) {
1207        return getProjectHistory(project, 0, Long.MAX_VALUE, RefactoringDescriptor.NONE, monitor);
1208    }
1209
1210    /**
1211     * {@inheritDoc}
1212     */

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 JavaDoc 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 JavaDoc set= new HashSet JavaDoc();
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    /**
1243     * {@inheritDoc}
1244     */

1245    public RefactoringHistory getRefactoringHistory(final IProject[] projects, final IProgressMonitor monitor) {
1246        return getRefactoringHistory(projects, 0, Long.MAX_VALUE, RefactoringDescriptor.NONE, monitor);
1247    }
1248
1249    /**
1250     * {@inheritDoc}
1251     */

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 JavaDoc set= new HashSet JavaDoc();
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    /**
1289     * {@inheritDoc}
1290     */

1291    public RefactoringHistory getWorkspaceHistory(IProgressMonitor monitor) {
1292        return getWorkspaceHistory(0, Long.MAX_VALUE, monitor);
1293    }
1294
1295    /**
1296     * {@inheritDoc}
1297     */

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    /**
1303     * Reads refactoring descriptor proxies from the input stream.
1304     * <p>
1305     * Note that calling this method with a flag argument unequal to
1306     * <code>RefactoringDescriptor#NONE</code> may result in a performance
1307     * degradation, since the actual descriptors have to be eagerly resolved.
1308     * This in turn results in faster execution of any subsequent calls to
1309     * {@link RefactoringDescriptorProxy#requestDescriptor(IProgressMonitor)}
1310     * which try to request a descriptor from the returned refactoring history.
1311     * </p>
1312     *
1313     * @param stream
1314     * the input stream to read from
1315     * @return the refactoring descriptor proxies
1316     * @throws CoreException
1317     * if an error occurs while reading the refactoring descriptor
1318     * proxies
1319     */

1320    public RefactoringDescriptorProxy[] readRefactoringDescriptorProxies(final InputStream JavaDoc stream) throws CoreException {
1321        Assert.isNotNull(stream);
1322        try {
1323            return RefactoringHistoryManager.readRefactoringDescriptorProxies(stream, null, 0, Long.MAX_VALUE);
1324        } catch (IOException JavaDoc exception) {
1325            throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), 0, exception.getLocalizedMessage(), null));
1326        }
1327    }
1328
1329    /**
1330     * {@inheritDoc}
1331     */

1332    public RefactoringHistory readRefactoringHistory(final InputStream JavaDoc stream, final int flags) throws CoreException {
1333        Assert.isNotNull(stream);
1334        Assert.isTrue(flags >= RefactoringDescriptor.NONE);
1335        final List JavaDoc list= new ArrayList JavaDoc();
1336        final RefactoringSessionDescriptor descriptor= new RefactoringSessionReader(true).readSession(new InputSource JavaDoc(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    /**
1355     * {@inheritDoc}
1356     */

1357    public void removeExecutionListener(final IRefactoringExecutionListener listener) {
1358        Assert.isNotNull(listener);
1359        fExecutionListeners.remove(listener);
1360    }
1361
1362    /**
1363     * {@inheritDoc}
1364     */

1365    public void removeHistoryListener(final IRefactoringHistoryListener listener) {
1366        Assert.isNotNull(listener);
1367        fHistoryListeners.remove(listener);
1368    }
1369
1370    /**
1371     * Returns the resolved refactoring descriptor associated with the specified
1372     * proxy.
1373     * <p>
1374     * The refactoring history must be in connected state.
1375     * </p>
1376     *
1377     * @param proxy
1378     * the refactoring descriptor proxy
1379     * @param monitor
1380     * the progress monitor to use, or <code>null</code>
1381     *
1382     * @return the resolved refactoring descriptor, or <code>null</code>
1383     */

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    /**
1393     * Sets the override time stamp for the next refactoring performed.
1394     *
1395     * @param stamp
1396     * the override time stamp, or <code>-1</code> to clear it
1397     */

1398    public void setOverrideTimeStamp(final long stamp) {
1399        Assert.isTrue(stamp == -1 || stamp >= 0);
1400        fOverrideTimeStamp= stamp;
1401    }
1402
1403    /**
1404     * Sets the comment of a refactoring in the refactoring history.
1405     *
1406     * @param proxy
1407     * the refactoring descriptor proxy
1408     * @param comment
1409     * the new non-empty comment of the refactoring, or
1410     * <code>null</code>
1411     * @param monitor
1412     * the progress monitor to use, or <code>null</code>
1413     * @throws CoreException
1414     * if an error occurs while setting the comment of the
1415     * refactoring. Reasons include:
1416     * <ul>
1417     * <li>The refactoring history has an illegal format, contains
1418     * illegal arguments or otherwise illegal information.</li>
1419     * <li>An I/O error occurs while setting the refactoring
1420     * comment in the refactoring history.</li>
1421     * </ul>
1422     *
1423     * @see IRefactoringCoreStatusCodes#REFACTORING_HISTORY_FORMAT_ERROR
1424     * @see IRefactoringCoreStatusCodes#REFACTORING_HISTORY_IO_ERROR
1425     */

1426    public void setRefactoringComment(final RefactoringDescriptorProxy proxy, final String JavaDoc 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    /**
1434     * {@inheritDoc}
1435     */

1436    public void writeRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies, final OutputStream JavaDoc 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); //$NON-NLS-1$
1444
connect();
1445            final List JavaDoc list= new ArrayList JavaDoc(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    /**
1463     * {@inheritDoc}
1464     */

1465    public void writeRefactoringSession(final RefactoringSessionDescriptor descriptor, final OutputStream JavaDoc 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