KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > refactoring > api > AbstractRefactoring


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.refactoring.api;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import org.netbeans.api.queries.SharabilityQuery;
27 import org.netbeans.modules.refactoring.api.impl.APIAccessor;
28 import org.netbeans.modules.refactoring.api.impl.ProgressSupport;
29 import org.netbeans.modules.refactoring.api.impl.SPIAccessor;
30 import org.netbeans.modules.refactoring.spi.GuardedBlockHandler;
31 import org.netbeans.modules.refactoring.spi.GuardedBlockHandlerFactory;
32 import org.netbeans.modules.refactoring.spi.ProgressProvider;
33 import org.netbeans.modules.refactoring.spi.ReadOnlyFilesHandler;
34 import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
35 import org.netbeans.modules.refactoring.spi.RefactoringPluginFactory;
36 import org.openide.ErrorManager;
37 import org.openide.filesystems.FileObject;
38 import org.openide.filesystems.FileUtil;
39 import org.openide.loaders.DataObject;
40 import org.openide.loaders.DataObjectNotFoundException;
41 import org.openide.util.Lookup;
42 import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
43 import org.openide.util.lookup.InstanceContent;
44
45
46 /**
47  * Abstract superclass for particular refactorings.
48  * Methods should be typically called in following order:
49  * <ul>
50  * <li>preCheck
51  * <li>setParameter1(..), setParameter2(..) (this methods will typically be added by the subclass
52  * to allow parametrization of the implemented refactoring)
53  * <li>fastCheckParameters() (performs only fast check - useful for online error checking)
54  * <li>checkParameters() (full check of parameters)
55  * <li>prepare() (collects usages)
56  * </ul>
57  * @see RefactoringSession
58  * @author Martin Matula, Jan Becicka
59  */

60 public abstract class AbstractRefactoring {
61
62     static {
63         APIAccessor.DEFAULT = new AccessorImpl();
64     }
65     
66     /**
67      * Initial state
68      */

69     public static final int INIT = 0;
70     /** Pre-check state. */
71     public static final int PRE_CHECK = 1;
72     /** Parameters check state. */
73     public static final int PARAMETERS_CHECK = 2;
74     /** Prepare state. */
75     public static final int PREPARE = 3;
76     
77     private int currentState = INIT;
78     
79     private static final int PLUGIN_STEPS = 30;
80     
81     private ArrayList JavaDoc plugins;
82     
83     private ArrayList JavaDoc pluginsWithProgress;
84     
85     private ArrayList JavaDoc gbHandlers;
86     
87     private ProgressListener progressListener = new ProgressL();
88     
89     private ProgressSupport progressSupport;
90     AbstractRefactoring caller;
91     
92     Lookup refactoringSource;
93     
94     protected AbstractRefactoring(Lookup refactoringSource) {
95         this.refactoringSource = refactoringSource;
96     }
97     
98     private Collection JavaDoc getPlugins() {
99         if (plugins == null) {
100             plugins = new ArrayList JavaDoc();
101             // get plugins from the lookup
102
Lookup.Result result = Lookup.getDefault().lookup(new Lookup.Template(RefactoringPluginFactory.class));
103             for (Iterator JavaDoc it = result.allInstances().iterator(); it.hasNext();) {
104                 RefactoringPluginFactory factory = (RefactoringPluginFactory) it.next();
105                 RefactoringPlugin plugin = factory.createInstance(this);
106                 if (plugin != null) {
107                     if (caller == null || factory.getClass().getClassLoader().equals(getClass().getClassLoader()) || factory.createInstance(caller)==null) {
108                         //caller is internal non-api field. Plugin is always added for API calls.
109
//For non-api internal calls:
110
// Plugins from different modules are ignored,
111
// if factory for the caller return non-null plugin.
112
// This quite hacky method is used for SafeDeleteRefactoring:
113
// SafeDeleteRefactorinPlugin uses WhereUsedQuery internally.
114
// If some module implements both plugins (SafeDelete and WhereUsed),
115
// WhereUsedRefactoringPlugin should be ignored, because whole process will be handled by
116
// SafeDeleteRefactoringPlugin.
117
// #65980
118
plugins.add(plugin);
119                     }
120                 }
121             }
122         }
123         return plugins;
124     }
125     
126     Collection JavaDoc getGBHandlers() {
127         if (gbHandlers == null) {
128             gbHandlers = new ArrayList JavaDoc();
129             // get plugins from the lookup
130
Lookup.Result result = Lookup.getDefault().lookup(new Lookup.Template(GuardedBlockHandlerFactory.class));
131             for (Iterator JavaDoc it = result.allInstances().iterator(); it.hasNext();) {
132                 GuardedBlockHandler handler = ((GuardedBlockHandlerFactory) it.next()).createInstance(this);
133                 if (handler != null) gbHandlers.add(handler);
134             }
135         }
136         return gbHandlers;
137     }
138     
139     /** Perform checks to ensure that the preconditions are met for the implemented
140      * refactoring.
141      * @return Chain of problems encountered or <code>null</code> if no problems
142      * were found.
143      */

144     public final Problem preCheck() {
145 // //workaround for #68803
146
// if (!(this instanceof WhereUsedQuery)) {
147
// if (progressSupport != null)
148
// progressSupport.fireProgressListenerStart(this, ProgressEvent.START, -1);
149
// setCP();
150
// if (progressSupport != null)
151
// progressSupport.fireProgressListenerStop(this);
152
// }
153
currentState = PRE_CHECK;
154         return pluginsPreCheck(null);
155     }
156     
157     /** Collects and returns a set of refactoring elements - objects that
158      * will be affected by the refactoring.
159      * @param session RefactoringSession that the operation will use to return
160      * instances of {@link org.netbeans.modules.refactoring.api.RefactoringElement} class representing objects that
161      * will be affected by the refactoring.
162      * @return Chain of problems encountered or <code>null</code> in no problems
163      * were found.
164      */

165     public final Problem prepare(RefactoringSession session) {
166         Problem p = null;
167         if (currentState < PARAMETERS_CHECK) {
168             p = checkParameters();
169         }
170         if (p != null && p.isFatal())
171             return p;
172         
173         p = pluginsPrepare(p, session);
174         
175         return p;
176     }
177     
178     /**
179      * Checks if this refactoring has correctly set all parameters.
180      * @return Returns instancef Problem or null
181      */

182     public final Problem checkParameters() {
183 // //workaround for #68803
184
// if (this instanceof WhereUsedQuery) {
185
// if (progressSupport != null)
186
// progressSupport.fireProgressListenerStart(this, ProgressEvent.START, -1);
187
// setCP();
188
// if (progressSupport != null)
189
// progressSupport.fireProgressListenerStop(this);
190
// } else {
191
// setCP();
192
// }
193
Problem p = fastCheckParameters();
194         if (p != null && p.isFatal())
195             return p;
196         currentState = PARAMETERS_CHECK;
197         return pluginsCheckParams(p);
198     }
199     
200     /**
201      * This method checks parameters. Its implementation is fast and allows on-line checking of errors.
202      * If you want complete check of parameters, use #checkParameters()
203      * @return Returns instance of Problem or null
204      */

205     public final Problem fastCheckParameters() {
206         // Do not set classpath - use default merged class path
207
// #57558
208
// setCP();
209
Problem p = null;
210         if (currentState < PRE_CHECK) {
211             p = preCheck();
212         }
213         if (p != null && p.isFatal())
214             return p;
215         return pluginsFastCheckParams(p);
216     }
217     
218     /** Registers ProgressListener to receive events.
219      * @param listener The listener to register.
220      *
221      */

222     public final synchronized void addProgressListener(ProgressListener listener) {
223         if (progressSupport == null ) {
224             progressSupport = new ProgressSupport();
225         }
226         progressSupport.addProgressListener(listener);
227         
228         if (pluginsWithProgress == null) {
229             pluginsWithProgress = new ArrayList JavaDoc();
230             Iterator JavaDoc pIt=getPlugins().iterator();
231             while(pIt.hasNext()) {
232                 RefactoringPlugin plugin=(RefactoringPlugin)pIt.next();
233                 if (plugin instanceof ProgressProvider) {
234                     ((ProgressProvider) plugin).addProgressListener(progressListener);
235                     pluginsWithProgress.add(plugin);
236                 }
237             }
238         }
239     }
240     
241     /** Removes ProgressListener from the list of listeners.
242      * @param listener The listener to remove.
243      *
244      */

245     public final synchronized void removeProgressListener(ProgressListener listener) {
246         if (progressSupport != null ) {
247             progressSupport.removeProgressListener(listener);
248         }
249
250         if (pluginsWithProgress != null) {
251             Iterator JavaDoc pIt=pluginsWithProgress.iterator();
252             
253             while(pIt.hasNext()) {
254                 ProgressProvider plugin=(ProgressProvider)pIt.next();
255                 plugin.removeProgressListener(progressListener);
256             }
257             pluginsWithProgress.clear();
258             pluginsWithProgress = null;
259        }
260     }
261     
262     /**
263      * getter for refactoring Context
264      * @see Context
265      * @return context in which the refactoring was invoked.
266      */

267     public final Context getContext() {
268         if (this.scope == null) {
269             this.scope=new Context(new InstanceContent());
270         }
271         return this.scope;
272     }
273     
274     /**
275      * Object being refactored
276      * @return
277      */

278     public final Lookup getRefactoringSource() {
279         return refactoringSource;
280     }
281     
282     private Context scope;
283     
284     /**
285      * Asynchronous request to cancel ongoing long-term request (such as preCheck(), checkParameters() or prepare())
286      */

287     public final void cancelRequest() {
288         Iterator JavaDoc pIt=getPlugins().iterator();
289         
290         while(pIt.hasNext()) {
291             RefactoringPlugin plugin=(RefactoringPlugin)pIt.next();
292             plugin.cancelRequest();
293         }
294     }
295     
296     private Problem pluginsPreCheck(Problem problem) {
297         Iterator JavaDoc pIt=getPlugins().iterator();
298         
299         while(pIt.hasNext()) {
300             RefactoringPlugin plugin=(RefactoringPlugin)pIt.next();
301             
302             problem=chainProblems(plugin.preCheck(),problem);
303             if (problem!=null && problem.isFatal())
304                 return problem;
305         }
306         return problem;
307     }
308     
309     private Problem pluginsPrepare(Problem problem, RefactoringSession session) {
310         RefactoringElementsBag elements = session.getElementsBag();
311         Iterator JavaDoc pIt=getPlugins().iterator();
312         
313         while(pIt.hasNext()) {
314             RefactoringPlugin plugin=(RefactoringPlugin)pIt.next();
315             
316             problem=chainProblems(plugin.prepare(elements),problem);
317             if (problem!=null && problem.isFatal())
318                 return problem;
319         }
320         
321         //TODO:
322
//following condition "!(this instanceof WhereUsedQuery)" is hotfix of #65785
323
//correct solution would probably be this condition: "!isQuery()"
324
//unfortunately isQuery() is not in AbstractRefactoring class, but in RefactoringIU
325
//we should consider moving this method to AbstractRefactoring class in future release
326
if (!(this instanceof WhereUsedQuery)) {
327             ReadOnlyFilesHandler handler = getROHandler();
328             if (handler!=null) {
329                 Collection JavaDoc files = SPIAccessor.DEFAULT.getReadOnlyFiles(elements);
330                 Collection JavaDoc allFiles = new HashSet JavaDoc();
331                 for (Iterator JavaDoc i = files.iterator(); i.hasNext();) {
332                     FileObject f = (FileObject) i.next();
333                     DataObject dob;
334                     try {
335                         dob = DataObject.find(f);
336                         for (Iterator JavaDoc j = dob.files().iterator(); j.hasNext();) {
337                             FileObject file = (FileObject) j.next();
338                             if (SharabilityQuery.getSharability(FileUtil.toFile(file)) == SharabilityQuery.SHARABLE) {
339                                 allFiles.add(file);
340                             }
341                         }
342                     } catch (DataObjectNotFoundException e) {
343                         allFiles.add(f);
344                     }
345                 }
346                 problem = chainProblems(handler.createProblem(session, allFiles), problem);
347             }
348         }
349         
350         return problem;
351     }
352     
353     private ReadOnlyFilesHandler getROHandler() {
354         Lookup.Result result = Lookup.getDefault().lookup(new Lookup.Template(ReadOnlyFilesHandler.class));
355         List JavaDoc handlers = (List JavaDoc) result.allInstances();
356         if (handlers.size() == 0) {
357             return null;
358         }
359         if (handlers.size() > 1) {
360             ErrorManager.getDefault().log(ErrorManager.WARNING, "Multiple instances of ReadOnlyFilesHandler found in Lookup; only using first one: " + handlers); //NOI18N
361
}
362         return (ReadOnlyFilesHandler) handlers.get(0);
363     }
364     
365     private Problem pluginsCheckParams(Problem problem) {
366         Iterator JavaDoc pIt=getPlugins().iterator();
367         
368         while(pIt.hasNext()) {
369             RefactoringPlugin plugin=(RefactoringPlugin)pIt.next();
370             
371             problem=chainProblems(plugin.checkParameters(),problem);
372             if (problem!=null && problem.isFatal())
373                 return problem;
374         }
375         return problem;
376     }
377     
378     private Problem pluginsFastCheckParams(Problem problem) {
379         Iterator JavaDoc pIt=getPlugins().iterator();
380         
381         while(pIt.hasNext()) {
382             RefactoringPlugin plugin=(RefactoringPlugin)pIt.next();
383             
384             problem=chainProblems(plugin.fastCheckParameters(),problem);
385             if (problem!=null && problem.isFatal())
386                 return problem;
387         }
388         return problem;
389     }
390     
391     static Problem chainProblems(Problem p,Problem p1) {
392         Problem problem;
393         
394         if (p==null) return p1;
395         if (p1==null) return p;
396         problem=p;
397         while(problem.getNext()!=null) {
398             problem=problem.getNext();
399         }
400         problem.setNext(p1);
401         return p;
402     }
403     
404     
405     private class ProgressL implements ProgressListener {
406
407         private float progressStep;
408         private float current;
409         public void start(ProgressEvent event) {
410             progressStep = (float) PLUGIN_STEPS / event.getCount();
411             
412             if (pluginsWithProgress.indexOf(event.getSource()) == 0) {
413                 //first plugin
414
//let's start
415
current = 0;
416                 if (event.getCount()==-1) {
417                     fireProgressListenerStart(event.getOperationType(), -1);
418                 } else {
419                     fireProgressListenerStart(event.getOperationType(), PLUGIN_STEPS*pluginsWithProgress.size());
420                 }
421             } else {
422                 current = pluginsWithProgress.indexOf(event.getSource())*PLUGIN_STEPS;
423                 fireProgressListenerStep((int) current);
424             }
425         }
426         
427         public void step(ProgressEvent event) {
428             current = current + progressStep;
429             fireProgressListenerStep((int) current) ;
430         }
431         
432         public void stop(ProgressEvent event) {
433             if (pluginsWithProgress.indexOf(event.getSource()) == pluginsWithProgress.size()-1) {
434                 fireProgressListenerStop();
435             }
436         }
437         /** Notifies all registered listeners about the event.
438          *
439          * @param type Type of operation that is starting.
440          * @param count Number of steps the operation consists of.
441          *
442          */

443         private void fireProgressListenerStart(int type, int count) {
444             if (progressSupport != null)
445                 progressSupport.fireProgressListenerStart(this, type, count);
446         }
447         
448         /** Notifies all registered listeners about the event.
449          */

450         private void fireProgressListenerStep() {
451             if (progressSupport != null)
452                 progressSupport.fireProgressListenerStep(this);
453         }
454         
455         /**
456          * Notifies all registered listeners about the event.
457          * @param count
458          */

459         private void fireProgressListenerStep(int count) {
460             if (progressSupport != null)
461                 progressSupport.fireProgressListenerStep(this, count);
462         }
463         
464         /** Notifies all registered listeners about the event.
465          */

466         private void fireProgressListenerStop() {
467             if (progressSupport != null)
468                 progressSupport.fireProgressListenerStop(this);
469         }
470     }
471 }
472
Popular Tags