KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > reorg > MoveCuUpdateCreator


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.reorg;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19
20 import org.eclipse.text.edits.ReplaceEdit;
21 import org.eclipse.text.edits.TextEdit;
22
23 import org.eclipse.core.runtime.Assert;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.OperationCanceledException;
27 import org.eclipse.core.runtime.SubProgressMonitor;
28
29 import org.eclipse.core.resources.IResource;
30
31 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
32 import org.eclipse.ltk.core.refactoring.TextChange;
33
34 import org.eclipse.jdt.core.Flags;
35 import org.eclipse.jdt.core.IBuffer;
36 import org.eclipse.jdt.core.ICompilationUnit;
37 import org.eclipse.jdt.core.IImportDeclaration;
38 import org.eclipse.jdt.core.IJavaElement;
39 import org.eclipse.jdt.core.IPackageFragment;
40 import org.eclipse.jdt.core.IType;
41 import org.eclipse.jdt.core.JavaModelException;
42 import org.eclipse.jdt.core.ToolFactory;
43 import org.eclipse.jdt.core.compiler.IScanner;
44 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
45 import org.eclipse.jdt.core.compiler.InvalidInputException;
46 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
47 import org.eclipse.jdt.core.search.IJavaSearchConstants;
48 import org.eclipse.jdt.core.search.SearchEngine;
49 import org.eclipse.jdt.core.search.SearchMatch;
50 import org.eclipse.jdt.core.search.SearchPattern;
51 import org.eclipse.jdt.core.search.TypeReferenceMatch;
52
53 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
54 import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor;
55 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
56 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
57 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
58 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
59 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
60 import org.eclipse.jdt.internal.corext.refactoring.structure.ReferenceFinderUtil;
61 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
62 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
63 import org.eclipse.jdt.internal.corext.util.Messages;
64 import org.eclipse.jdt.internal.corext.util.SearchUtils;
65
66 import org.eclipse.jdt.internal.ui.JavaPlugin;
67
68 public class MoveCuUpdateCreator {
69     
70     private final String JavaDoc fNewPackage;
71     private ICompilationUnit[] fCus;
72     private IPackageFragment fDestination;
73     
74     private Map JavaDoc fImportRewrites; //ICompilationUnit -> ImportEdit
75

76     public MoveCuUpdateCreator(ICompilationUnit cu, IPackageFragment pack){
77         this(new ICompilationUnit[]{cu}, pack);
78     }
79     
80     public MoveCuUpdateCreator(ICompilationUnit[] cus, IPackageFragment pack){
81         Assert.isNotNull(cus);
82         Assert.isNotNull(pack);
83         fCus= cus;
84         fDestination= pack;
85         fImportRewrites= new HashMap JavaDoc();
86         fNewPackage= fDestination.isDefaultPackage() ? "" : fDestination.getElementName() + '.'; //$NON-NLS-1$
87
}
88     
89     public TextChangeManager createChangeManager(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException{
90         pm.beginTask("", 5); //$NON-NLS-1$
91
try{
92             TextChangeManager changeManager= new TextChangeManager();
93             addUpdates(changeManager, new SubProgressMonitor(pm, 4), status);
94             addImportRewriteUpdates(changeManager);
95             return changeManager;
96         } catch (JavaModelException e){
97             throw e;
98         } catch (CoreException e){
99             throw new JavaModelException(e);
100         } finally{
101             pm.done();
102         }
103         
104     }
105
106     private void addImportRewriteUpdates(TextChangeManager changeManager) throws CoreException {
107         for (Iterator JavaDoc iter= fImportRewrites.keySet().iterator(); iter.hasNext();) {
108             ICompilationUnit cu= (ICompilationUnit) iter.next();
109             ImportRewrite importRewrite= (ImportRewrite) fImportRewrites.get(cu);
110             if (importRewrite != null && importRewrite.hasRecordedChanges()) {
111                 TextChangeCompatibility.addTextEdit(changeManager.get(cu), RefactoringCoreMessages.MoveCuUpdateCreator_update_imports, importRewrite.rewriteImports(null));
112             }
113         }
114     }
115
116     private void addUpdates(TextChangeManager changeManager, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
117         pm.beginTask("", fCus.length); //$NON-NLS-1$
118
for (int i= 0; i < fCus.length; i++){
119             if (pm.isCanceled())
120                 throw new OperationCanceledException();
121         
122             addUpdates(changeManager, fCus[i], new SubProgressMonitor(pm, 1), status);
123         }
124     }
125     
126     private void addUpdates(TextChangeManager changeManager, ICompilationUnit movedUnit, IProgressMonitor pm, RefactoringStatus status) throws CoreException{
127         try{
128             pm.beginTask("", 3); //$NON-NLS-1$
129
pm.subTask(Messages.format(RefactoringCoreMessages.MoveCuUpdateCreator_searching, movedUnit.getElementName()));
130             
131             if (isInAnotherFragmentOfSamePackage(movedUnit, fDestination)){
132                 pm.worked(3);
133                 return;
134             }
135
136             addImportToSourcePackageTypes(movedUnit, new SubProgressMonitor(pm, 1));
137             removeImportsToDestinationPackageTypes(movedUnit);
138             addReferenceUpdates(changeManager, movedUnit, new SubProgressMonitor(pm, 2), status);
139         } finally{
140             pm.done();
141         }
142     }
143
144     private void addReferenceUpdates(TextChangeManager changeManager, ICompilationUnit movedUnit, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException, CoreException {
145         List JavaDoc cuList= Arrays.asList(fCus);
146         SearchResultGroup[] references= getReferences(movedUnit, pm, status);
147         for (int i= 0; i < references.length; i++) {
148             SearchResultGroup searchResultGroup= references[i];
149             ICompilationUnit referencingCu= searchResultGroup.getCompilationUnit();
150             if (referencingCu == null)
151                 continue;
152
153             boolean simpleReferencesNeedNewImport= simpleReferencesNeedNewImport(movedUnit, referencingCu, cuList);
154             SearchMatch[] results= searchResultGroup.getSearchResults();
155             for (int j= 0; j < results.length; j++) {
156                 // TODO: should update type references with results from addImport
157
TypeReference reference= (TypeReference) results[j];
158                 if (reference.isImportDeclaration()) {
159                     ImportRewrite rewrite= getImportRewrite(referencingCu);
160                     IImportDeclaration importDecl= (IImportDeclaration) SearchUtils.getEnclosingJavaElement(results[j]);
161                     if (Flags.isStatic(importDecl.getFlags())) {
162                         rewrite.removeStaticImport(importDecl.getElementName());
163                         addStaticImport(movedUnit, importDecl, rewrite);
164                     } else {
165                         rewrite.removeImport(importDecl.getElementName());
166                         rewrite.addImport(createStringForNewImport(movedUnit, importDecl));
167                     }
168                 } else if (reference.isQualified()) {
169                     TextChange textChange= changeManager.get(referencingCu);
170                     String JavaDoc changeName= RefactoringCoreMessages.MoveCuUpdateCreator_update_references;
171                     TextEdit replaceEdit= new ReplaceEdit(reference.getOffset(), reference.getSimpleNameStart() - reference.getOffset(), fNewPackage);
172                     TextChangeCompatibility.addTextEdit(textChange, changeName, replaceEdit);
173                 } else if (simpleReferencesNeedNewImport) {
174                     ImportRewrite importEdit= getImportRewrite(referencingCu);
175                     String JavaDoc typeName= reference.getSimpleName();
176                     importEdit.addImport(getQualifiedType(fDestination.getElementName(), typeName));
177                 }
178             }
179         }
180     }
181
182     private void addStaticImport(ICompilationUnit movedUnit, IImportDeclaration importDecl, ImportRewrite rewrite) {
183         String JavaDoc old= importDecl.getElementName();
184         int oldPackLength= movedUnit.getParent().getElementName().length();
185
186         StringBuffer JavaDoc result= new StringBuffer JavaDoc(fDestination.getElementName());
187         if (oldPackLength == 0) // move FROM default package
188
result.append('.').append(old);
189         else if (result.length() == 0) // move TO default package
190
result.append(old.substring(oldPackLength + 1)); // cut "."
191
else
192             result.append(old.substring(oldPackLength));
193         int index= result.lastIndexOf("."); //$NON-NLS-1$
194
if (index > 0 && index < result.length() - 1)
195             rewrite.addStaticImport(result.substring(0, index), result.substring(index + 1, result.length()), true);
196     }
197
198     private String JavaDoc getQualifiedType(String JavaDoc packageName, String JavaDoc typeName) {
199         if (packageName.length() == 0)
200             return typeName;
201         else
202             return packageName + '.' + typeName;
203     }
204
205     private String JavaDoc createStringForNewImport(ICompilationUnit movedUnit, IImportDeclaration importDecl) {
206         String JavaDoc old= importDecl.getElementName();
207         int oldPackLength= movedUnit.getParent().getElementName().length();
208         
209         StringBuffer JavaDoc result= new StringBuffer JavaDoc(fDestination.getElementName());
210         if (oldPackLength == 0) // move FROM default package
211
result.append('.').append(old);
212         else if (result.length() == 0) // move TO default package
213
result.append(old.substring(oldPackLength + 1)); // cut "."
214
else
215             result.append(old.substring(oldPackLength));
216         return result.toString();
217     }
218     
219     private void removeImportsToDestinationPackageTypes(ICompilationUnit movedUnit) throws CoreException{
220         ImportRewrite importEdit= getImportRewrite(movedUnit);
221         IType[] destinationTypes= getDestinationPackageTypes();
222         for (int i= 0; i < destinationTypes.length; i++) {
223             importEdit.removeImport(JavaModelUtil.getFullyQualifiedName(destinationTypes[i]));
224         }
225     }
226     
227     private IType[] getDestinationPackageTypes() throws JavaModelException {
228         List JavaDoc types= new ArrayList JavaDoc();
229         if (fDestination.exists()) {
230             ICompilationUnit[] cus= fDestination.getCompilationUnits();
231             for (int i= 0; i < cus.length; i++) {
232                 types.addAll(Arrays.asList(cus[i].getAllTypes()));
233             }
234         }
235         return (IType[]) types.toArray(new IType[types.size()]);
236     }
237     
238     private void addImportToSourcePackageTypes(ICompilationUnit movedUnit, IProgressMonitor pm) throws CoreException{
239         List JavaDoc cuList= Arrays.asList(fCus);
240         IType[] allCuTypes= movedUnit.getAllTypes();
241         IType[] referencedTypes= ReferenceFinderUtil.getTypesReferencedIn(allCuTypes, pm);
242         ImportRewrite importEdit= getImportRewrite(movedUnit);
243         importEdit.setFilterImplicitImports(false);
244         IPackageFragment srcPack= (IPackageFragment)movedUnit.getParent();
245         for (int i= 0; i < referencedTypes.length; i++) {
246                 IType iType= referencedTypes[i];
247                 if (! iType.exists())
248                     continue;
249                 if (! iType.getPackageFragment().equals(srcPack))
250                     continue;
251                 if (cuList.contains(iType.getCompilationUnit()))
252                     continue;
253                 importEdit.addImport(JavaModelUtil.getFullyQualifiedName(iType));
254         }
255     }
256     
257     private ImportRewrite getImportRewrite(ICompilationUnit cu) throws CoreException{
258         if (fImportRewrites.containsKey(cu))
259             return (ImportRewrite)fImportRewrites.get(cu);
260         ImportRewrite importEdit= StubUtility.createImportRewrite(cu, true);
261         fImportRewrites.put(cu, importEdit);
262         return importEdit;
263     }
264     
265     private boolean simpleReferencesNeedNewImport(ICompilationUnit movedUnit, ICompilationUnit referencingCu, List JavaDoc cuList) {
266         if (referencingCu.equals(movedUnit))
267             return false;
268         if (cuList.contains(referencingCu))
269             return false;
270         if (isReferenceInAnotherFragmentOfSamePackage(referencingCu, movedUnit)) {
271             /* Destination package is different from source, since
272              * isDestinationAnotherFragmentOfSamePackage(movedUnit) was false in addUpdates(.) */

273             return true;
274         }
275         
276         //heuristic
277
if (referencingCu.getImport(movedUnit.getParent().getElementName() + ".*").exists()) //$NON-NLS-1$
278
return true; // has old star import
279
if (referencingCu.getParent().equals(movedUnit.getParent()))
280             return true; //is moved away from same package
281
return false;
282     }
283
284     private boolean isReferenceInAnotherFragmentOfSamePackage(ICompilationUnit referencingCu, ICompilationUnit movedUnit) {
285         if (referencingCu == null)
286             return false;
287         if (! (referencingCu.getParent() instanceof IPackageFragment))
288             return false;
289         IPackageFragment pack= (IPackageFragment) referencingCu.getParent();
290         return isInAnotherFragmentOfSamePackage(movedUnit, pack);
291     }
292     
293     private static boolean isInAnotherFragmentOfSamePackage(ICompilationUnit cu, IPackageFragment pack) {
294         if (! (cu.getParent() instanceof IPackageFragment))
295             return false;
296         IPackageFragment cuPack= (IPackageFragment) cu.getParent();
297         return ! cuPack.equals(pack) && JavaModelUtil.isSamePackage(cuPack, pack);
298     }
299
300     private static SearchResultGroup[] getReferences(ICompilationUnit unit, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
301         final SearchPattern pattern= RefactoringSearchEngine.createOrPattern(unit.getTypes(), IJavaSearchConstants.REFERENCES);
302         if (pattern != null)
303             return RefactoringSearchEngine.search(pattern, RefactoringScopeFactory.create(unit), new Collector(((IPackageFragment) unit.getParent())), new SubProgressMonitor(pm, 1), status);
304         return new SearchResultGroup[] {};
305     }
306
307     private final static class Collector extends CollectingSearchRequestor {
308         private IPackageFragment fSource;
309         private IScanner fScanner;
310         
311         public Collector(IPackageFragment source) {
312             fSource= source;
313             fScanner= ToolFactory.createScanner(false, false, false, false);
314         }
315         
316         /* (non-Javadoc)
317          * @see org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor#acceptSearchMatch(SearchMatch)
318          */

319         public void acceptSearchMatch(SearchMatch match) throws CoreException {
320             /*
321              * Processing is done in collector to reuse the buffer which was
322              * already required by the search engine to locate the matches.
323              */

324             // [start, end[ include qualification.
325
IJavaElement element= SearchUtils.getEnclosingJavaElement(match);
326             int accuracy= match.getAccuracy();
327             int start= match.getOffset();
328             int length= match.getLength();
329             boolean insideDocComment= match.isInsideDocComment();
330             IResource res= match.getResource();
331             if (element.getAncestor(IJavaElement.IMPORT_DECLARATION) != null) {
332                 super.acceptSearchMatch(TypeReference.createImportReference(element, accuracy, start, length, insideDocComment, res));
333             } else {
334                 ICompilationUnit unit= (ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT);
335                 if (unit != null) {
336                     IBuffer buffer= unit.getBuffer();
337                     String JavaDoc matchText= buffer.getText(start, length);
338                     if (fSource.isDefaultPackage()) {
339                         super.acceptSearchMatch(TypeReference.createSimpleReference(element, accuracy, start, length, insideDocComment, res, matchText));
340                     } else {
341                         // assert: matchText doesn't start nor end with comment
342
int simpleNameStart= getLastSimpleNameStart(matchText);
343                         if (simpleNameStart != 0) {
344                             super.acceptSearchMatch(TypeReference.createQualifiedReference(element, accuracy, start, length, insideDocComment, res, start + simpleNameStart));
345                         } else {
346                             super.acceptSearchMatch(TypeReference.createSimpleReference(element, accuracy, start, length, insideDocComment, res, matchText));
347                         }
348                     }
349                 }
350             }
351         }
352         
353         private int getLastSimpleNameStart(String JavaDoc reference) {
354             fScanner.setSource(reference.toCharArray());
355             int lastIdentifierStart= -1;
356             try {
357                 int tokenType= fScanner.getNextToken();
358                 while (tokenType != ITerminalSymbols.TokenNameEOF) {
359                     if (tokenType == ITerminalSymbols.TokenNameIdentifier)
360                         lastIdentifierStart= fScanner.getCurrentTokenStartPosition();
361                     tokenType= fScanner.getNextToken();
362                 }
363             } catch (InvalidInputException e) {
364                 JavaPlugin.log(e);
365             }
366             return lastIdentifierStart;
367         }
368     }
369     
370     
371     private final static class TypeReference extends TypeReferenceMatch {
372         private String JavaDoc fSimpleTypeName;
373         private int fSimpleNameStart;
374         
375         private TypeReference(IJavaElement enclosingElement, int accuracy, int start, int length,
376                 boolean insideDocComment, IResource resource, int simpleNameStart, String JavaDoc simpleName) {
377             super(enclosingElement, accuracy, start, length,
378                     insideDocComment, SearchEngine.getDefaultSearchParticipant(), resource);
379             fSimpleNameStart= simpleNameStart;
380             fSimpleTypeName= simpleName;
381         }
382         
383         public static TypeReference createQualifiedReference(IJavaElement enclosingElement, int accuracy, int start, int length,
384                 boolean insideDocComment, IResource resource, int simpleNameStart) {
385             Assert.isTrue(start < simpleNameStart && simpleNameStart < start + length);
386             return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, simpleNameStart, null);
387         }
388         
389         public static TypeReference createImportReference(IJavaElement enclosingElement, int accuracy, int start, int length,
390                 boolean insideDocComment, IResource resource) {
391             return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, -1, null);
392         }
393         
394         public static TypeReference createSimpleReference(IJavaElement enclosingElement, int accuracy, int start, int length,
395                 boolean insideDocComment, IResource resource, String JavaDoc simpleName) {
396             return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, -1, simpleName);
397         }
398         
399         public boolean isImportDeclaration() {
400             return SearchUtils.getEnclosingJavaElement(this).getAncestor(IJavaElement.IMPORT_DECLARATION) != null;
401         }
402         
403         public boolean isQualified() {
404             return fSimpleNameStart != -1;
405         }
406         
407         public boolean isSimpleReference() {
408             return fSimpleTypeName != null;
409         }
410         
411         /**
412          * @return start offset of simple type name, or -1 iff ! isQualified()
413          */

414         public int getSimpleNameStart() {
415             return fSimpleNameStart;
416         }
417         
418         /**
419          * @return simple type name, or null iff ! isSimpleName()
420          */

421         public String JavaDoc getSimpleName() {
422             return fSimpleTypeName;
423         }
424     }
425
426 }
427
Popular Tags