KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > delegates > DelegateCreator


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.jdt.internal.corext.refactoring.delegates;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.text.edits.TextEdit;
17
18 import org.eclipse.core.runtime.Assert;
19
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.Document;
22 import org.eclipse.jface.text.IDocument;
23
24 import org.eclipse.ltk.core.refactoring.CategorizedTextEditGroup;
25 import org.eclipse.ltk.core.refactoring.GroupCategory;
26 import org.eclipse.ltk.core.refactoring.GroupCategorySet;
27
28 import org.eclipse.jdt.core.JavaModelException;
29 import org.eclipse.jdt.core.dom.AST;
30 import org.eclipse.jdt.core.dom.ASTNode;
31 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
32 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
33 import org.eclipse.jdt.core.dom.BodyDeclaration;
34 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
35 import org.eclipse.jdt.core.dom.ChildPropertyDescriptor;
36 import org.eclipse.jdt.core.dom.Expression;
37 import org.eclipse.jdt.core.dom.IBinding;
38 import org.eclipse.jdt.core.dom.ITypeBinding;
39 import org.eclipse.jdt.core.dom.Javadoc;
40 import org.eclipse.jdt.core.dom.Name;
41 import org.eclipse.jdt.core.dom.TagElement;
42 import org.eclipse.jdt.core.dom.TextElement;
43 import org.eclipse.jdt.core.dom.Type;
44 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
45 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
46
47 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
48 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
49 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
50 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
51 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
52 import org.eclipse.jdt.internal.corext.util.Strings;
53
54 import org.eclipse.jdt.internal.ui.JavaPlugin;
55 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
56
57 /**
58  * <p>
59  * This class implements functionality for creating delegates of renamed or moved
60  * members pointing to the original element and containing a
61  * deprecation message. The delegate is always created in the source file of the
62  * original element and is either added directly after the original element or
63  * replaces it. Use this class as follows:
64  * </p>
65  *
66  * <pre>
67  * DelegateCreator myCreator= new DelegateMethodCreator();
68  * myCreator.setRewrite(... cu-rewrite of modified file...);
69  * myCreator.setDeclaration(... declaration of moved/renamed member ...);
70  *
71  * ... additional initialization methods, see below...
72  *
73  * myCreator.prepareDelegate();
74  *
75  * ... do something with the delegate before the edit is created ...
76  *
77  * myCreator.createEdit();
78  * </pre>
79  *
80  * <p>
81  * Before prepareDelegate(), depending on whether the member is moved or
82  * renamed, or both, as well as other concerns, the following methods may be
83  * called:
84  * </p>
85  *
86  * <pre>
87  * myCreator.setNewLocation(... new location where the member was moved ...);
88  * myCreator.setNewName(... new name of the member if renamed ...);
89  * myCreator.setDeclareDeprecated(... false or true ...);
90  * myCreator.setCopy(... false or true...);
91  * </pre>
92  *
93  * <p>
94  * Note that removing or adding imports related to delegate creation is
95  * generally the responsibility of the caller. As an exception, the import for a
96  * target type set via setNewLocation() will be added by this class.
97  * </p>
98  *
99  * <p>
100  * This class is intended to be subclassed by specialized creators for concrete
101  * element types like methods or fields.
102  * </p>
103  *
104  * @since 3.2
105  *
106  */

107 public abstract class DelegateCreator {
108
109     public static final GroupCategorySet CATEGORY_DELEGATE= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.refactoring.delegates.delegate", RefactoringCoreMessages.DelegateCreator_change_category_title, RefactoringCoreMessages.DelegateCreator_change_category_description)); //$NON-NLS-1$
110

111     /*
112      * We are dealing with two CURewrites here:
113      *
114      * 1) The original rewrite which is passed in from the outside. One import may
115      * be registered with this CURewrite in case setNewLocation() is called.
116      * On createEdit(), the complete delegate code will be added to the CURewrite's
117      * ASTRewrite (add or replace).
118      *
119      * 2) A new CuRewrite from which we'll only use the ASTRewrite to build the new delegate.
120      *
121      */

122     private CompilationUnitRewrite fOriginalRewrite;
123     private CompilationUnitRewrite fDelegateRewrite;
124     
125     private boolean fIsMoveToAnotherFile;
126     private boolean fCopy;
127     private boolean fDeclareDeprecated;
128     private boolean fInsertBefore;
129
130     private BodyDeclaration fDeclaration;
131     private String JavaDoc fNewElementName;
132     private ITypeBinding fDestinationTypeBinding;
133     private Type fDestinationType;
134     private ITrackedNodePosition fTrackedPosition;
135
136     private CodeGenerationSettings fPreferences;
137
138     public DelegateCreator() {
139         fCopy= true;
140         fDeclareDeprecated= true;
141         fInsertBefore= false;
142     }
143
144     /**
145      * Sets the compilation unit rewrite of the declaration to create a delegate
146      * for. Must always be called prior to prepareDelegate(). Bindings need not
147      * be resolved.
148      *
149      * @param rewrite the CompilationUnitRewrite.
150      */

151     public void setSourceRewrite(CompilationUnitRewrite rewrite) {
152         fOriginalRewrite= rewrite;
153         fPreferences= JavaPreferencesSettings.getCodeGenerationSettings(rewrite.getCu().getJavaProject());
154
155         fDelegateRewrite= new CompilationUnitRewrite(rewrite.getCu(), rewrite.getRoot());
156         fDelegateRewrite.getASTRewrite().setTargetSourceRangeComputer(rewrite.getASTRewrite().getExtendedSourceRangeComputer());
157     }
158
159     /**
160      * Sets the old member declaration. Must always be called prior to
161      * prepareDelegate().
162      *
163      * @param declaration the BodyDeclaration
164      */

165     public void setDeclaration(BodyDeclaration declaration) {
166         fDeclaration= declaration;
167     }
168
169     /**
170      * Set the name of the new element. This is optional, but if set it must be
171      * called prior to prepareDelegate().
172      *
173      * @param newName the String with the new name
174      */

175     public void setNewElementName(String JavaDoc newName) {
176         fNewElementName= newName;
177     }
178
179     /**
180      * Set the location of the new element. This is optional, but if set it must
181      * be called prior to prepareDelegate().
182      *
183      * @param binding the ITypeBinding of the old type
184      */

185     public void setNewLocation(ITypeBinding binding) {
186         fDestinationTypeBinding= binding;
187     }
188
189     /**
190      * Set whether the existing element should be copied and the copy made
191      * delegate (true), or the original element should be changed to become the
192      * delegate (false). This is optional, but if set it must be called prior to
193      * prepareDelegate().
194      *
195      * The default is true (create a copy).
196      *
197      * @param isCopy true if a copy should be created
198      */

199     public void setCopy(boolean isCopy) {
200         fCopy= isCopy;
201     }
202
203     /**
204      * Sets whether a deprecation message including a link to the new element
205      * should be added to the javadoc of the delegate. This is optional, but if
206      * set it must be called prior to prepareDelegate().
207      *
208      * The default is true (create deprecation message).
209      *
210      * @param declareDeprecated true if the member should be deprecated
211      */

212     public void setDeclareDeprecated(boolean declareDeprecated) {
213         fDeclareDeprecated= declareDeprecated;
214     }
215     
216     /**
217      * When in copy mode, use this method to control the insertion point of the
218      * delegate. If the parameter is true, the delegate gets inserted before the
219      * original declaration. If false, the delegate gets inserted after the
220      * original declaration.
221      *
222      * The default is false (do not insert before).
223      *
224      * @param insertBefore insertion point
225      */

226     public void setInsertBefore(boolean insertBefore) {
227         fInsertBefore= insertBefore;
228     }
229
230     // Methods to be overridden by subclasses
231

232     /**
233      * Initializes the creator. Must set the "new" name of the element if not
234      * already set.
235      *
236      */

237     protected abstract void initialize();
238
239     /**
240      *
241      * Creates the body of the delegate.
242      *
243      * @param declaration the member declaration
244      * @return the body of the delegate
245      * @throws JavaModelException
246      */

247     protected abstract ASTNode createBody(BodyDeclaration declaration) throws JavaModelException;
248
249     /**
250      * Creates the javadoc reference to the old member to be put inside the
251      * javadoc comment.
252      *
253      * This method is only called if isDeclareDeprecated() == true.
254      *
255      * @param declaration the member declaration
256      * @return the javadoc link node
257      * @throws JavaModelException
258      */

259     protected abstract ASTNode createDocReference(BodyDeclaration declaration) throws JavaModelException;
260
261     /**
262      * Returns the node of the declaration on which to add the body.
263      *
264      * @param declaration the member declaration
265      * @return the body head
266      */

267     protected abstract ASTNode getBodyHead(BodyDeclaration declaration);
268
269     /**
270      * Returns the javadoc property descriptor. The javadoc will be added using
271      * this descriptor.
272      *
273      * @return property descriptor
274      */

275     protected abstract ChildPropertyDescriptor getJavaDocProperty();
276
277     /**
278      * Returns the body property descriptor. The body of the delegate will be
279      * added using this descriptor.
280      *
281      * @return property descriptor
282      */

283     protected abstract ChildPropertyDescriptor getBodyProperty();
284
285     
286     // Getters for subclasses
287

288     protected boolean isMoveToAnotherFile() {
289         return fIsMoveToAnotherFile;
290     }
291
292     protected AST getAst() {
293         return fDelegateRewrite.getAST();
294     }
295
296     protected BodyDeclaration getDeclaration() {
297         return fDeclaration;
298     }
299
300     protected String JavaDoc getNewElementName() {
301         return fNewElementName;
302     }
303
304     /**
305      * Prepares the delegate member. The delegate member will have the same
306      * signature as the old member and contain a call to the new member and a
307      * javadoc reference with a reference to the new member.
308      *
309      * All references to the new member will contain the new name of the member
310      * and/or new declaring type, if any.
311      *
312      */

313     public void prepareDelegate() throws JavaModelException {
314         Assert.isNotNull(fDelegateRewrite);
315         Assert.isNotNull(fDeclaration);
316
317         initialize();
318
319         // Moving to a new type?
320
if (fDestinationTypeBinding != null) {
321             fDestinationType= fOriginalRewrite.getImportRewrite().addImport(fDestinationTypeBinding, getAst());
322             fIsMoveToAnotherFile= true;
323         } else
324             fIsMoveToAnotherFile= false;
325
326         fTrackedPosition= fDelegateRewrite.getASTRewrite().track(fDeclaration);
327
328         ASTNode delegateBody= createBody(fDeclaration);
329         if (delegateBody != null) {
330             // is null for interface and abstract methods
331
fDelegateRewrite.getASTRewrite().set(getBodyHead(fDeclaration), getBodyProperty(), delegateBody, null);
332         }
333
334         if (fDeclareDeprecated) {
335             createJavadoc();
336         }
337     }
338
339     /**
340      * Creates the javadoc for the delegate.
341      *
342      * @throws JavaModelException
343      */

344     private void createJavadoc() throws JavaModelException {
345         TagElement tag= getDelegateJavadocTag(fDeclaration);
346
347         Javadoc comment= fDeclaration.getJavadoc();
348         if (comment == null) {
349             comment= getAst().newJavadoc();
350             comment.tags().add(tag);
351             fDelegateRewrite.getASTRewrite().set(fDeclaration, getJavaDocProperty(), comment, null);
352         } else
353             fDelegateRewrite.getASTRewrite().getListRewrite(comment, Javadoc.TAGS_PROPERTY).insertLast(tag, null);
354     }
355     
356     /**
357      * Performs the actual rewriting and adds an edit to the ASTRewrite set with
358      * {@link #setSourceRewrite(CompilationUnitRewrite)}.
359      *
360      * @throws JavaModelException
361      */

362     public void createEdit() throws JavaModelException {
363         try {
364             IDocument document= new Document(fDelegateRewrite.getCu().getBuffer().getContents());
365             TextEdit edit= fDelegateRewrite.getASTRewrite().rewriteAST(document, fDelegateRewrite.getCu().getJavaProject().getOptions(true));
366             edit.apply(document, TextEdit.UPDATE_REGIONS);
367
368             String JavaDoc newSource= Strings.trimIndentation(document.get(fTrackedPosition.getStartPosition(), fTrackedPosition.getLength()),
369                     fPreferences.tabWidth, fPreferences.indentWidth, false);
370
371             ASTNode placeholder= fOriginalRewrite.getASTRewrite().createStringPlaceholder(newSource, fDeclaration.getNodeType());
372
373             CategorizedTextEditGroup groupDescription= fOriginalRewrite.createCategorizedGroupDescription(getTextEditGroupLabel(), CATEGORY_DELEGATE);
374             ListRewrite bodyDeclarationsListRewrite= fOriginalRewrite.getASTRewrite().getListRewrite(fDeclaration.getParent(), getTypeBodyDeclarationsProperty());
375             if (fCopy)
376                 if (fInsertBefore)
377                     bodyDeclarationsListRewrite.insertBefore(placeholder, fDeclaration, groupDescription);
378                 else
379                     bodyDeclarationsListRewrite.insertAfter(placeholder, fDeclaration, groupDescription);
380             else
381                 bodyDeclarationsListRewrite.replace(fDeclaration, placeholder, groupDescription);
382             
383         } catch (BadLocationException e) {
384             JavaPlugin.log(e);
385         }
386     }
387
388     protected abstract String JavaDoc getTextEditGroupLabel();
389
390     /**
391      * Returns the binding of the declaration.
392      *
393      * @return the binding of the declaration
394      */

395     protected abstract IBinding getDeclarationBinding();
396
397     /**
398      * Returns a new rewrite with the delegate changes registered. This rewrite
399      * can be used in-between calls to prepareDelegate() and createEdit() to add
400      * additional changes to the delegate.
401      *
402      * @return CompilationUnitRewrite the new rewrite
403      */

404     public CompilationUnitRewrite getDelegateRewrite() {
405         return fDelegateRewrite;
406     }
407
408     // ******************* INTERNAL HELPERS ***************************
409

410     private TagElement getDelegateJavadocTag(BodyDeclaration declaration) throws JavaModelException {
411         Assert.isNotNull(declaration);
412         
413         String JavaDoc msg= RefactoringCoreMessages.DelegateCreator_use_member_instead;
414         int firstParam= msg.indexOf("{0}"); //$NON-NLS-1$
415
Assert.isTrue(firstParam != -1);
416         
417         List JavaDoc fragments= new ArrayList JavaDoc();
418         TextElement text= getAst().newTextElement();
419         text.setText(msg.substring(0, firstParam).trim());
420         fragments.add(text);
421         
422         fragments.add(createJavadocMemberReferenceTag(declaration, getAst()));
423         
424         text= getAst().newTextElement();
425         text.setText(msg.substring(firstParam + 3).trim());
426         fragments.add(text);
427         
428         final TagElement tag= getAst().newTagElement();
429         tag.setTagName(TagElement.TAG_DEPRECATED);
430         tag.fragments().addAll(fragments);
431         return tag;
432     }
433
434     private TagElement createJavadocMemberReferenceTag(BodyDeclaration declaration, final AST ast) throws JavaModelException {
435         Assert.isNotNull(ast);
436         Assert.isNotNull(declaration);
437         ASTNode javadocReference= createDocReference(declaration);
438         final TagElement element= ast.newTagElement();
439         element.setTagName(TagElement.TAG_LINK);
440         element.fragments().add(javadocReference);
441         return element;
442     }
443
444     protected Expression getAccess() {
445         return isMoveToAnotherFile() ? createDestinationTypeName() : null;
446     }
447     
448     protected Name createDestinationTypeName() {
449         return ASTNodeFactory.newName(getAst(), ASTNodes.asString(fDestinationType));
450     }
451
452     private ChildListPropertyDescriptor getTypeBodyDeclarationsProperty() {
453         ASTNode parent= fDeclaration.getParent();
454
455         if (parent instanceof AbstractTypeDeclaration)
456             return ((AbstractTypeDeclaration) parent).getBodyDeclarationsProperty();
457         else if (parent instanceof AnonymousClassDeclaration)
458             return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY;
459
460         Assert.isTrue(false);
461         return null;
462     }
463 }
464
Popular Tags