KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > hierarchy > ChangeCollector


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.core.hierarchy;
12
13 import java.util.*;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17
18 import org.eclipse.jdt.core.*;
19 import org.eclipse.jdt.core.IJavaElementDelta;
20 import org.eclipse.jdt.core.IType;
21 import org.eclipse.jdt.core.JavaModelException;
22 import org.eclipse.jdt.internal.core.JavaElement;
23 import org.eclipse.jdt.internal.core.SimpleDelta;
24
25 /*
26  * Collects changes (reported through fine-grained deltas) that can affect a type hierarchy.
27  */

28 public class ChangeCollector {
29     
30     /*
31      * A table from ITypes to TypeDeltas
32      */

33     HashMap JavaDoc changes = new HashMap JavaDoc();
34     
35     TypeHierarchy hierarchy;
36     
37     public ChangeCollector(TypeHierarchy hierarchy) {
38         this.hierarchy = hierarchy;
39     }
40     
41     /*
42      * Adds the children of the given delta to the list of changes.
43      */

44     private void addAffectedChildren(IJavaElementDelta delta) throws JavaModelException {
45         IJavaElementDelta[] children = delta.getAffectedChildren();
46         for (int i = 0, length = children.length; i < length; i++) {
47             IJavaElementDelta child = children[i];
48             IJavaElement childElement = child.getElement();
49             switch (childElement.getElementType()) {
50                 case IJavaElement.IMPORT_CONTAINER:
51                     addChange((IImportContainer)childElement, child);
52                     break;
53                 case IJavaElement.IMPORT_DECLARATION:
54                     addChange((IImportDeclaration)childElement, child);
55                     break;
56                 case IJavaElement.TYPE:
57                     addChange((IType)childElement, child);
58                     break;
59                 case IJavaElement.INITIALIZER:
60                 case IJavaElement.FIELD:
61                 case IJavaElement.METHOD:
62                     addChange((IMember)childElement, child);
63                     break;
64             }
65         }
66     }
67     
68     /*
69      * Adds the given delta on a compilation unit to the list of changes.
70      */

71     public void addChange(ICompilationUnit cu, IJavaElementDelta newDelta) throws JavaModelException {
72         int newKind = newDelta.getKind();
73         switch (newKind) {
74             case IJavaElementDelta.ADDED:
75                 ArrayList JavaDoc allTypes = new ArrayList JavaDoc();
76                 getAllTypesFromElement(cu, allTypes);
77                 for (int i = 0, length = allTypes.size(); i < length; i++) {
78                     IType type = (IType)allTypes.get(i);
79                     addTypeAddition(type, (SimpleDelta)this.changes.get(type));
80                 }
81                 break;
82             case IJavaElementDelta.REMOVED:
83                 allTypes = new ArrayList JavaDoc();
84                 getAllTypesFromHierarchy((JavaElement)cu, allTypes);
85                 for (int i = 0, length = allTypes.size(); i < length; i++) {
86                     IType type = (IType)allTypes.get(i);
87                     addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
88                 }
89                 break;
90             case IJavaElementDelta.CHANGED:
91                 addAffectedChildren(newDelta);
92                 break;
93         }
94     }
95     
96     private void addChange(IImportContainer importContainer, IJavaElementDelta newDelta) throws JavaModelException {
97         int newKind = newDelta.getKind();
98         if (newKind == IJavaElementDelta.CHANGED) {
99             addAffectedChildren(newDelta);
100             return;
101         }
102         SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importContainer);
103         if (existingDelta != null) {
104             switch (newKind) {
105                 case IJavaElementDelta.ADDED:
106                     if (existingDelta.getKind() == IJavaElementDelta.REMOVED) {
107                         // REMOVED then ADDED
108
this.changes.remove(importContainer);
109                     }
110                     break;
111                 case IJavaElementDelta.REMOVED:
112                     if (existingDelta.getKind() == IJavaElementDelta.ADDED) {
113                         // ADDED then REMOVED
114
this.changes.remove(importContainer);
115                     }
116                     break;
117                     // CHANGED handled above
118
}
119         } else {
120             SimpleDelta delta = new SimpleDelta();
121             switch (newKind) {
122                 case IJavaElementDelta.ADDED:
123                     delta.added();
124                     break;
125                 case IJavaElementDelta.REMOVED:
126                     delta.removed();
127                     break;
128             }
129             this.changes.put(importContainer, delta);
130         }
131     }
132
133     private void addChange(IImportDeclaration importDecl, IJavaElementDelta newDelta) {
134         SimpleDelta existingDelta = (SimpleDelta)this.changes.get(importDecl);
135         int newKind = newDelta.getKind();
136         if (existingDelta != null) {
137             switch (newKind) {
138                 case IJavaElementDelta.ADDED:
139                     if (existingDelta.getKind() == IJavaElementDelta.REMOVED) {
140                         // REMOVED then ADDED
141
this.changes.remove(importDecl);
142                     }
143                     break;
144                 case IJavaElementDelta.REMOVED:
145                     if (existingDelta.getKind() == IJavaElementDelta.ADDED) {
146                         // ADDED then REMOVED
147
this.changes.remove(importDecl);
148                     }
149                     break;
150                 // CHANGED cannot happen for import declaration
151
}
152         } else {
153             SimpleDelta delta = new SimpleDelta();
154             switch (newKind) {
155                 case IJavaElementDelta.ADDED:
156                     delta.added();
157                     break;
158                 case IJavaElementDelta.REMOVED:
159                     delta.removed();
160                     break;
161             }
162             this.changes.put(importDecl, delta);
163         }
164     }
165     
166     /*
167      * Adds a change for the given member (a method, a field or an initializer) and the types it defines.
168      */

169     private void addChange(IMember member, IJavaElementDelta newDelta) throws JavaModelException {
170         int newKind = newDelta.getKind();
171         switch (newKind) {
172             case IJavaElementDelta.ADDED:
173                 ArrayList JavaDoc allTypes = new ArrayList JavaDoc();
174                 getAllTypesFromElement(member, allTypes);
175                 for (int i = 0, length = allTypes.size(); i < length; i++) {
176                     IType innerType = (IType)allTypes.get(i);
177                     addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
178                 }
179                 break;
180             case IJavaElementDelta.REMOVED:
181                 allTypes = new ArrayList JavaDoc();
182                 getAllTypesFromHierarchy((JavaElement)member, allTypes);
183                 for (int i = 0, length = allTypes.size(); i < length; i++) {
184                     IType type = (IType)allTypes.get(i);
185                     addTypeRemoval(type, (SimpleDelta)this.changes.get(type));
186                 }
187                 break;
188             case IJavaElementDelta.CHANGED:
189                 addAffectedChildren(newDelta);
190                 break;
191         }
192     }
193     
194     /*
195      * Adds a change for the given type and the types it defines.
196      */

197     private void addChange(IType type, IJavaElementDelta newDelta) throws JavaModelException {
198          int newKind = newDelta.getKind();
199         SimpleDelta existingDelta = (SimpleDelta)this.changes.get(type);
200         switch (newKind) {
201             case IJavaElementDelta.ADDED:
202                 addTypeAddition(type, existingDelta);
203                 ArrayList JavaDoc allTypes = new ArrayList JavaDoc();
204                 getAllTypesFromElement(type, allTypes);
205                 for (int i = 0, length = allTypes.size(); i < length; i++) {
206                     IType innerType = (IType)allTypes.get(i);
207                     addTypeAddition(innerType, (SimpleDelta)this.changes.get(innerType));
208                 }
209                 break;
210             case IJavaElementDelta.REMOVED:
211                 addTypeRemoval(type, existingDelta);
212                 allTypes = new ArrayList JavaDoc();
213                 getAllTypesFromHierarchy((JavaElement)type, allTypes);
214                 for (int i = 0, length = allTypes.size(); i < length; i++) {
215                     IType innerType = (IType)allTypes.get(i);
216                     addTypeRemoval(innerType, (SimpleDelta)this.changes.get(innerType));
217                 }
218                 break;
219             case IJavaElementDelta.CHANGED:
220                 addTypeChange(type, newDelta.getFlags(), existingDelta);
221                 addAffectedChildren(newDelta);
222                 break;
223         }
224     }
225
226     private void addTypeAddition(IType type, SimpleDelta existingDelta) throws JavaModelException {
227         if (existingDelta != null) {
228             switch (existingDelta.getKind()) {
229                 case IJavaElementDelta.REMOVED:
230                     // REMOVED then ADDED
231
boolean hasChange = false;
232                     if (hasSuperTypeChange(type)) {
233                         existingDelta.superTypes();
234                         hasChange = true;
235                     }
236                     if (hasVisibilityChange(type)) {
237                         existingDelta.modifiers();
238                         hasChange = true;
239                     }
240                     if (!hasChange) {
241                         this.changes.remove(type);
242                     }
243                     break;
244                     // CHANGED then ADDED
245
// or ADDED then ADDED: should not happen
246
}
247         } else {
248             // check whether the type addition affects the hierarchy
249
String JavaDoc typeName = type.getElementName();
250             if (this.hierarchy.hasSupertype(typeName)
251                     || this.hierarchy.subtypesIncludeSupertypeOf(type)
252                     || this.hierarchy.missingTypes.contains(typeName)) {
253                 SimpleDelta delta = new SimpleDelta();
254                 delta.added();
255                 this.changes.put(type, delta);
256             }
257         }
258     }
259     
260     private void addTypeChange(IType type, int newFlags, SimpleDelta existingDelta) throws JavaModelException {
261         if (existingDelta != null) {
262             switch (existingDelta.getKind()) {
263                 case IJavaElementDelta.CHANGED:
264                     // CHANGED then CHANGED
265
int existingFlags = existingDelta.getFlags();
266                     boolean hasChange = false;
267                     if ((existingFlags & IJavaElementDelta.F_SUPER_TYPES) != 0
268                             && hasSuperTypeChange(type)) {
269                         existingDelta.superTypes();
270                         hasChange = true;
271                     }
272                     if ((existingFlags & IJavaElementDelta.F_MODIFIERS) != 0
273                             && hasVisibilityChange(type)) {
274                         existingDelta.modifiers();
275                         hasChange = true;
276                     }
277                     if (!hasChange) {
278                         // super types and visibility are back to the ones in the existing hierarchy
279
this.changes.remove(type);
280                     }
281                     break;
282                     // ADDED then CHANGED: leave it as ADDED
283
// REMOVED then CHANGED: should not happen
284
}
285         } else {
286             // check whether the type change affects the hierarchy
287
SimpleDelta typeDelta = null;
288             if ((newFlags & IJavaElementDelta.F_SUPER_TYPES) != 0
289                     && this.hierarchy.includesTypeOrSupertype(type)) {
290                 typeDelta = new SimpleDelta();
291                 typeDelta.superTypes();
292             }
293             if ((newFlags & IJavaElementDelta.F_MODIFIERS) != 0
294                     && (this.hierarchy.hasSupertype(type.getElementName())
295                         || type.equals(this.hierarchy.focusType))) {
296                 if (typeDelta == null) {
297                     typeDelta = new SimpleDelta();
298                 }
299                 typeDelta.modifiers();
300             }
301             if (typeDelta != null) {
302                 this.changes.put(type, typeDelta);
303             }
304         }
305     }
306
307     private void addTypeRemoval(IType type, SimpleDelta existingDelta) {
308         if (existingDelta != null) {
309             switch (existingDelta.getKind()) {
310                 case IJavaElementDelta.ADDED:
311                     // ADDED then REMOVED
312
this.changes.remove(type);
313                     break;
314                 case IJavaElementDelta.CHANGED:
315                     // CHANGED then REMOVED
316
existingDelta.removed();
317                     break;
318                     // REMOVED then REMOVED: should not happen
319
}
320         } else {
321             // check whether the type removal affects the hierarchy
322
if (this.hierarchy.contains(type)) {
323                 SimpleDelta typeDelta = new SimpleDelta();
324                 typeDelta.removed();
325                 this.changes.put(type, typeDelta);
326             }
327         }
328     }
329     
330     /*
331      * Returns all types defined in the given element excluding the given element.
332      */

333     private void getAllTypesFromElement(IJavaElement element, ArrayList JavaDoc allTypes) throws JavaModelException {
334         switch (element.getElementType()) {
335             case IJavaElement.COMPILATION_UNIT:
336                 IType[] types = ((ICompilationUnit)element).getTypes();
337                 for (int i = 0, length = types.length; i < length; i++) {
338                     IType type = types[i];
339                     allTypes.add(type);
340                     getAllTypesFromElement(type, allTypes);
341                 }
342                 break;
343             case IJavaElement.TYPE:
344                 types = ((IType)element).getTypes();
345                 for (int i = 0, length = types.length; i < length; i++) {
346                     IType type = types[i];
347                     allTypes.add(type);
348                     getAllTypesFromElement(type, allTypes);
349                 }
350                 break;
351             case IJavaElement.INITIALIZER:
352             case IJavaElement.FIELD:
353             case IJavaElement.METHOD:
354                 IJavaElement[] children = ((IMember)element).getChildren();
355                 for (int i = 0, length = children.length; i < length; i++) {
356                     IType type = (IType)children[i];
357                     allTypes.add(type);
358                     getAllTypesFromElement(type, allTypes);
359                 }
360                 break;
361         }
362     }
363     
364     /*
365      * Returns all types in the existing hierarchy that have the given element as a parent.
366      */

367     private void getAllTypesFromHierarchy(JavaElement element, ArrayList JavaDoc allTypes) {
368         switch (element.getElementType()) {
369             case IJavaElement.COMPILATION_UNIT:
370                 ArrayList JavaDoc types = (ArrayList JavaDoc)this.hierarchy.files.get(element);
371                 if (types != null) {
372                     allTypes.addAll(types);
373                 }
374                 break;
375             case IJavaElement.TYPE:
376             case IJavaElement.INITIALIZER:
377             case IJavaElement.FIELD:
378             case IJavaElement.METHOD:
379                 types = (ArrayList JavaDoc)this.hierarchy.files.get(((IMember)element).getCompilationUnit());
380                 if (types != null) {
381                     for (int i = 0, length = types.size(); i < length; i++) {
382                         IType type = (IType)types.get(i);
383                         if (element.isAncestorOf(type)) {
384                             allTypes.add(type);
385                         }
386                     }
387                 }
388                 break;
389         }
390     }
391     
392     private boolean hasSuperTypeChange(IType type) throws JavaModelException {
393         // check super class
394
IType superclass = this.hierarchy.getSuperclass(type);
395         String JavaDoc existingSuperclassName = superclass == null ? null : superclass.getElementName();
396         String JavaDoc newSuperclassName = type.getSuperclassName();
397         if (existingSuperclassName != null && !existingSuperclassName.equals(newSuperclassName)) {
398             return true;
399         }
400         
401         // check super interfaces
402
IType[] existingSuperInterfaces = this.hierarchy.getSuperInterfaces(type);
403         String JavaDoc[] newSuperInterfaces = type.getSuperInterfaceNames();
404         if (existingSuperInterfaces.length != newSuperInterfaces.length) {
405             return true;
406         }
407         for (int i = 0, length = newSuperInterfaces.length; i < length; i++) {
408             String JavaDoc superInterfaceName = newSuperInterfaces[i];
409             if (!superInterfaceName.equals(newSuperInterfaces[i])) {
410                 return true;
411             }
412         }
413         
414         return false;
415     }
416     
417     private boolean hasVisibilityChange(IType type) throws JavaModelException {
418         int existingFlags = this.hierarchy.getCachedFlags(type);
419         int newFlags = type.getFlags();
420         return existingFlags != newFlags;
421     }
422
423     /*
424      * Whether the hierarchy needs refresh according to the changes collected so far.
425      */

426     public boolean needsRefresh() {
427         return changes.size() != 0;
428     }
429     
430     public String JavaDoc toString() {
431         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
432         Iterator JavaDoc iterator = this.changes.entrySet().iterator();
433         while (iterator.hasNext()) {
434             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iterator.next();
435             buffer.append(((JavaElement)entry.getKey()).toDebugString());
436             buffer.append(entry.getValue());
437             if (iterator.hasNext()) {
438                 buffer.append('\n');
439             }
440         }
441         return buffer.toString();
442     }
443 }
444
Popular Tags