KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ltk > core > refactoring > participants > ProcessorBasedRefactoring


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.core.refactoring.participants;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Collections JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.NullProgressMonitor;
24 import org.eclipse.core.runtime.OperationCanceledException;
25 import org.eclipse.core.runtime.PerformanceStats;
26 import org.eclipse.core.runtime.SubProgressMonitor;
27
28 import org.eclipse.core.resources.IFile;
29
30 import org.eclipse.ltk.core.refactoring.Change;
31 import org.eclipse.ltk.core.refactoring.CompositeChange;
32 import org.eclipse.ltk.core.refactoring.Refactoring;
33 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
34 import org.eclipse.ltk.core.refactoring.TextChange;
35 import org.eclipse.ltk.core.refactoring.TextFileChange;
36
37 import org.eclipse.ltk.internal.core.refactoring.Messages;
38 import org.eclipse.ltk.internal.core.refactoring.ParticipantDescriptor;
39 import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
40 import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin;
41
42 /**
43  * An abstract base implementation for refactorings that are split into
44  * one refactoring processor and 0..n participants.
45  * <p>
46  * This class should be subclassed by clients wishing to provide a special
47  * refactoring which uses a processor/participant architecture.
48  * </p>
49  * @since 3.0
50  */

51 public abstract class ProcessorBasedRefactoring extends Refactoring {
52
53     private static final String JavaDoc PERF_CHECK_CONDITIONS= "org.eclipse.ltk.core.refactoring/perf/participants/checkConditions"; //$NON-NLS-1$
54
private static final String JavaDoc PERF_CREATE_CHANGES= "org.eclipse.ltk.core.refactoring/perf/participants/createChanges"; //$NON-NLS-1$
55

56     private List JavaDoc/*<RefactoringParticipant>*/ fParticipants;
57     
58     private Map JavaDoc/*<Object, TextChange>*/ fTextChangeMap;
59     
60     private static final List JavaDoc/*<RefactoringParticipant>*/ EMPTY_PARTICIPANTS= Collections.EMPTY_LIST;
61
62     private static class ProcessorChange extends CompositeChange {
63         private Map JavaDoc fParticipantMap;
64         public ProcessorChange(String JavaDoc name) {
65             super(name);
66             markAsSynthetic();
67         }
68         public void setParticipantMap(Map JavaDoc map) {
69             fParticipantMap= map;
70         }
71         protected void internalHandleException(Change change, Throwable JavaDoc e) {
72             if (e instanceof OperationCanceledException)
73                 return;
74                 
75             RefactoringParticipant participant= (RefactoringParticipant)fParticipantMap.get(change);
76             if (participant != null) {
77                 ParticipantDescriptor descriptor= participant.getDescriptor();
78                 descriptor.disable();
79                 RefactoringCorePlugin.logRemovedParticipant(descriptor, e);
80             }
81         }
82         protected boolean internalContinueOnCancel() {
83             return true;
84         }
85         protected boolean internalProcessOnCancel(Change change) {
86             RefactoringParticipant participant= (RefactoringParticipant)fParticipantMap.get(change);
87             if (participant == null)
88                 return false;
89             return participant.getDescriptor().processOnCancel();
90         }
91     }
92     
93     /**
94      * Creates a new processor based refactoring.
95      *
96      * @deprecated use {@link #ProcessorBasedRefactoring(RefactoringProcessor)} instead
97      */

98     protected ProcessorBasedRefactoring() {
99     }
100     
101     /**
102      * Creates a new processor based refactoring.
103      *
104      * @param processor the refactoring's main processor
105      *
106      * @since 3.1
107      */

108     protected ProcessorBasedRefactoring(RefactoringProcessor processor) {
109         processor.setRefactoring(this);
110     }
111     
112     /**
113      * Return the processor associated with this refactoring. The
114      * method must not return <code>null</code>.
115      *
116      * @return the processor associated with this refactoring
117      */

118     public abstract RefactoringProcessor getProcessor();
119     
120     
121     /**
122      * Checks whether the refactoring is applicable to the elements to be
123      * refactored or not.
124      * <p>
125      * This default implementation forwards the call to the refactoring
126      * processor.
127      * </p>
128      * @return <code>true</code> if the refactoring is applicable to the
129      * elements; otherwise <code>false</code> is returned.
130      * @throws CoreException if the test fails
131      */

132     public final boolean isApplicable() throws CoreException {
133         return getProcessor().isApplicable();
134     }
135         
136     /**
137      * {@inheritDoc}
138      */

139     public String JavaDoc getName() {
140         return getProcessor().getProcessorName();
141     }
142     
143     /**
144      * {@inheritDoc}
145      */

146     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
147         if (pm == null)
148             pm= new NullProgressMonitor();
149         RefactoringStatus result= new RefactoringStatus();
150         pm.beginTask("", 10); //$NON-NLS-1$
151
pm.setTaskName(RefactoringCoreMessages.ProcessorBasedRefactoring_initial_conditions);
152         
153         result.merge(getProcessor().checkInitialConditions(new SubProgressMonitor(pm, 8)));
154         if (result.hasFatalError()) {
155             pm.done();
156             return result;
157         }
158         pm.done();
159         return result;
160     }
161     
162     /**
163      * {@inheritDoc}
164      */

165     public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
166         if (pm == null)
167             pm= new NullProgressMonitor();
168         RefactoringStatus result= new RefactoringStatus();
169         CheckConditionsContext context= createCheckConditionsContext();
170         
171         pm.beginTask("", 9); //$NON-NLS-1$
172
pm.setTaskName(RefactoringCoreMessages.ProcessorBasedRefactoring_final_conditions);
173         
174         result.merge(getProcessor().checkFinalConditions(new SubProgressMonitor(pm, 5), context));
175         if (result.hasFatalError()) {
176             pm.done();
177             return result;
178         }
179         if (pm.isCanceled())
180             throw new OperationCanceledException();
181         
182         SharableParticipants sharableParticipants= new SharableParticipants(); // must not be shared when checkFinalConditions is called again
183
fParticipants= new ArrayList JavaDoc(Arrays.asList(getProcessor().loadParticipants(result, sharableParticipants)));
184         if (fParticipants == null)
185             fParticipants= EMPTY_PARTICIPANTS;
186         if (result.hasFatalError()) {
187             pm.done();
188             return result;
189         }
190         IProgressMonitor sm= new SubProgressMonitor(pm, 2);
191         
192         sm.beginTask("", fParticipants.size()); //$NON-NLS-1$
193
for (Iterator JavaDoc iter= fParticipants.iterator(); iter.hasNext() && !result.hasFatalError(); ) {
194             
195             RefactoringParticipant participant= (RefactoringParticipant) iter.next();
196
197             final PerformanceStats stats= PerformanceStats.getStats(PERF_CHECK_CONDITIONS, getName() + ", " + participant.getName()); //$NON-NLS-1$
198
stats.startRun();
199
200             try {
201                 result.merge(participant.checkConditions(new SubProgressMonitor(sm, 1), context));
202             } catch (RuntimeException JavaDoc e) {
203                 // remove the participant so that it will be ignored during change execution.
204
RefactoringCorePlugin.log(e);
205                 result.merge(RefactoringStatus.createErrorStatus(Messages.format(
206                     RefactoringCoreMessages.ProcessorBasedRefactoring_check_condition_participant_failed,
207                     participant.getName())));
208                 iter.remove();
209             }
210
211             stats.endRun();
212
213             if (sm.isCanceled())
214                 throw new OperationCanceledException();
215         }
216         sm.done();
217         if (result.hasFatalError()) {
218             pm.done();
219             return result;
220         }
221         result.merge(context.check(new SubProgressMonitor(pm, 1)));
222         pm.done();
223         return result;
224     }
225     
226     /**
227      * {@inheritDoc}
228      */

229     public Change createChange(IProgressMonitor pm) throws CoreException {
230         if (pm == null)
231             pm= new NullProgressMonitor();
232         pm.beginTask("", fParticipants.size() + 2); //$NON-NLS-1$
233
pm.setTaskName(RefactoringCoreMessages.ProcessorBasedRefactoring_create_change);
234         Change processorChange= getProcessor().createChange(new SubProgressMonitor(pm, 1));
235         if (pm.isCanceled())
236             throw new OperationCanceledException();
237         
238         fTextChangeMap= new HashMap JavaDoc();
239         addToTextChangeMap(processorChange);
240         
241         List JavaDoc changes= new ArrayList JavaDoc();
242         Map JavaDoc participantMap= new HashMap JavaDoc();
243         for (Iterator JavaDoc iter= fParticipants.iterator(); iter.hasNext();) {
244             final RefactoringParticipant participant= (RefactoringParticipant) iter.next();
245             
246             try {
247                 final PerformanceStats stats= PerformanceStats.getStats(PERF_CREATE_CHANGES, getName() + ", " + participant.getName()); //$NON-NLS-1$
248
stats.startRun();
249
250                 Change change= participant.createChange(new SubProgressMonitor(pm, 1));
251
252                 stats.endRun();
253
254                 if (change != null) {
255                     changes.add(change);
256                     participantMap.put(change, participant);
257                     addToTextChangeMap(change);
258                 }
259             } catch (CoreException e) {
260                 disableParticipant(participant, e);
261                 throw e;
262             } catch (RuntimeException JavaDoc e) {
263                 disableParticipant(participant, e);
264                 throw e;
265             }
266             if (pm.isCanceled())
267                 throw new OperationCanceledException();
268         }
269         
270         fTextChangeMap= null;
271         
272         Change postChange= getProcessor().postCreateChange(
273             (Change[])changes.toArray(new Change[changes.size()]),
274             new SubProgressMonitor(pm, 1));
275         
276         ProcessorChange result= new ProcessorChange(getName());
277         result.add(processorChange);
278         result.addAll((Change[]) changes.toArray(new Change[changes.size()]));
279         result.setParticipantMap(participantMap);
280         if (postChange != null)
281             result.add(postChange);
282         return result;
283     }
284     
285     /**
286      * Returns the text change for the given element or <code>null</code>
287      * if a text change doesn't exist. This method only returns a valid
288      * result during change creation. Outside of change creation always
289      * <code>null</code> is returned.
290      *
291      * @param element the element to be modified for which a text change
292      * is requested
293      *
294      * @return the text change or <code>null</code> if no text change exists
295      * for the element
296      *
297      * @since 3.1
298      */

299     public TextChange getTextChange(Object JavaDoc element) {
300         if (fTextChangeMap == null)
301             return null;
302         return (TextChange)fTextChangeMap.get(element);
303     }
304     
305     /**
306      * Adapts the refactoring to the given type. The adapter is resolved
307      * as follows:
308      * <ol>
309      * <li>the refactoring itself is checked whether it is an instance
310      * of the requested type.</li>
311      * <li>its processor is checked whether it is an instance of the
312      * requested type.</li>
313      * <li>the request is delegated to the super class.</li>
314      * </ol>
315      *
316      * @param clazz the adapter class to look up
317      *
318      * @return the requested adapter or <code>null</code>if no adapter
319      * exists.
320      */

321     public Object JavaDoc getAdapter(Class JavaDoc clazz) {
322         if (clazz.isInstance(this))
323             return this;
324         if (clazz.isInstance(getProcessor()))
325             return getProcessor();
326         return super.getAdapter(clazz);
327     }
328     
329     /* non java-doc
330      * for debugging only
331      */

332     public String JavaDoc toString() {
333         return getName();
334     }
335     
336     //---- Helper methods ---------------------------------------------------------------------
337

338     private CheckConditionsContext createCheckConditionsContext() throws CoreException {
339         CheckConditionsContext result= new CheckConditionsContext();
340         result.add(new ValidateEditChecker(getValidationContext()));
341         result.add(new ResourceChangeChecker());
342         return result;
343     }
344     
345     
346     private void disableParticipant(final RefactoringParticipant participant, Throwable JavaDoc e) {
347         ParticipantDescriptor descriptor= participant.getDescriptor();
348         descriptor.disable();
349         RefactoringCorePlugin.logRemovedParticipant(descriptor, e);
350     }
351     
352     private void addToTextChangeMap(Change change) {
353         if (change instanceof TextChange) {
354             Object JavaDoc element= ((TextChange)change).getModifiedElement();
355             if (element != null) {
356                 fTextChangeMap.put(element, change);
357             }
358             // check if we have a subclass of TextFileChange. If so also put the change
359
// under the file resource into the hash table if possible.
360
if (change instanceof TextFileChange && !change.getClass().equals(TextFileChange.class)) {
361                 IFile file= ((TextFileChange)change).getFile();
362                 fTextChangeMap.put(file, change);
363             }
364         } else if (change instanceof CompositeChange) {
365             Change[] children= ((CompositeChange)change).getChildren();
366             for (int i= 0; i < children.length; i++) {
367                 addToTextChangeMap(children[i]);
368             }
369         }
370     }
371 }
372
Popular Tags