KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > callhierarchy > MethodWrapper


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  * Jesper Kamstrup Linnet (eclipse@kamstrup-linnet.dk) - initial API and implementation
10  * (report 36180: Callers/Callees view)
11  *******************************************************************************/

12 package org.eclipse.jdt.internal.corext.callhierarchy;
13
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.eclipse.core.runtime.Assert;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.OperationCanceledException;
21 import org.eclipse.core.runtime.PlatformObject;
22
23 import org.eclipse.ui.model.IWorkbenchAdapter;
24
25 import org.eclipse.jdt.core.IJavaElement;
26 import org.eclipse.jdt.core.IMember;
27
28
29 import org.eclipse.jdt.internal.ui.callhierarchy.MethodWrapperWorkbenchAdapter;
30
31 /**
32  * This class represents the general parts of a method call (either to or from a
33  * method).
34  *
35  */

36 public abstract class MethodWrapper extends PlatformObject {
37     private Map JavaDoc fElements = null;
38
39     /*
40      * A cache of previously found methods. This cache should be searched
41      * before adding a "new" method object reference to the list of elements.
42      * This way previously found methods won't be searched again.
43      */

44     private Map JavaDoc fMethodCache;
45     private MethodCall fMethodCall;
46     private MethodWrapper fParent;
47     private int fLevel;
48
49     /**
50      * Constructor CallerElement.
51      */

52     public MethodWrapper(MethodWrapper parent, MethodCall methodCall) {
53         Assert.isNotNull(methodCall);
54
55         if (parent == null) {
56             setMethodCache(new HashMap JavaDoc());
57             fLevel = 1;
58         } else {
59             setMethodCache(parent.getMethodCache());
60             fLevel = parent.getLevel() + 1;
61         }
62
63         this.fMethodCall = methodCall;
64         this.fParent = parent;
65     }
66
67     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
68         if (adapter == IJavaElement.class) {
69             return getMember();
70         } else if (adapter == IWorkbenchAdapter.class){
71             return new MethodWrapperWorkbenchAdapter(this);
72         } else {
73             return null;
74         }
75     }
76
77     /**
78      * @return the child caller elements of this element
79      */

80     public MethodWrapper[] getCalls(IProgressMonitor progressMonitor) {
81         if (fElements == null) {
82             doFindChildren(progressMonitor);
83         }
84
85         MethodWrapper[] result = new MethodWrapper[fElements.size()];
86         int i = 0;
87
88         for (Iterator JavaDoc iter = fElements.keySet().iterator(); iter.hasNext();) {
89             MethodCall methodCall = getMethodCallFromMap(fElements, iter.next());
90             result[i++] = createMethodWrapper(methodCall);
91         }
92
93         return result;
94     }
95
96     public int getLevel() {
97         return fLevel;
98     }
99
100     public IMember getMember() {
101         return getMethodCall().getMember();
102     }
103
104     public MethodCall getMethodCall() {
105         return fMethodCall;
106     }
107
108     public String JavaDoc getName() {
109         if (getMethodCall() != null) {
110             return getMethodCall().getMember().getElementName();
111         } else {
112             return ""; //$NON-NLS-1$
113
}
114     }
115
116     public MethodWrapper getParent() {
117         return fParent;
118     }
119
120     public boolean equals(Object JavaDoc oth) {
121         if (this == oth) {
122             return true;
123         }
124
125         if (oth == null) {
126             return false;
127         }
128         
129         if (oth instanceof MethodWrapperWorkbenchAdapter) {
130             //Note: A MethodWrapper is equal to a referring MethodWrapperWorkbenchAdapter and vice versa (bug 101677).
131
oth= ((MethodWrapperWorkbenchAdapter) oth).getMethodWrapper();
132         }
133         
134         if (oth.getClass() != getClass()) {
135             return false;
136         }
137
138         MethodWrapper other = (MethodWrapper) oth;
139
140         if (this.fParent == null) {
141             if (other.fParent != null) {
142                 return false;
143             }
144         } else {
145             if (!this.fParent.equals(other.fParent)) {
146                 return false;
147             }
148         }
149
150         if (this.getMethodCall() == null) {
151             if (other.getMethodCall() != null) {
152                 return false;
153             }
154         } else {
155             if (!this.getMethodCall().equals(other.getMethodCall())) {
156                 return false;
157             }
158         }
159
160         return true;
161     }
162
163     public int hashCode() {
164         final int PRIME = 1000003;
165         int result = 0;
166
167         if (fParent != null) {
168             result = (PRIME * result) + fParent.hashCode();
169         }
170
171         if (getMethodCall() != null) {
172             result = (PRIME * result) + getMethodCall().getMember().hashCode();
173         }
174
175         return result;
176     }
177
178     private void setMethodCache(Map JavaDoc methodCache) {
179         fMethodCache = methodCache;
180     }
181
182     protected abstract String JavaDoc getTaskName();
183
184     private void addCallToCache(MethodCall methodCall) {
185         Map JavaDoc cachedCalls = lookupMethod(this.getMethodCall());
186         cachedCalls.put(methodCall.getKey(), methodCall);
187     }
188
189     protected abstract MethodWrapper createMethodWrapper(MethodCall methodCall);
190
191     private void doFindChildren(IProgressMonitor progressMonitor) {
192         Map JavaDoc existingResults = lookupMethod(getMethodCall());
193
194         if (existingResults != null) {
195             fElements = new HashMap JavaDoc();
196             fElements.putAll(existingResults);
197         } else {
198             initCalls();
199
200             if (progressMonitor != null) {
201                 progressMonitor.beginTask(getTaskName(), 100);
202             }
203
204             try {
205                 performSearch(progressMonitor);
206             } finally {
207                 if (progressMonitor != null) {
208                     progressMonitor.done();
209                 }
210             }
211
212             // ModalContext.run(getRunnableWithProgress(), true, getProgressMonitor(),
213
// Display.getCurrent());
214
}
215     }
216
217     /**
218      * Determines if the method represents a recursion call (i.e. whether the
219      * method call is already in the cache.)
220      *
221      * @return True if the call is part of a recursion
222      */

223     public boolean isRecursive() {
224         MethodWrapper current = getParent();
225
226         while (current != null) {
227             if (getMember().getHandleIdentifier().equals(current.getMember()
228                                                                         .getHandleIdentifier())) {
229                 return true;
230             }
231
232             current = current.getParent();
233         }
234
235         return false;
236     }
237
238     /**
239      * This method finds the children of the current IMethod (either callers or
240      * callees, depending on the concrete subclass.
241      * @return The result of the search for children
242      */

243     protected abstract Map JavaDoc findChildren(IProgressMonitor progressMonitor);
244
245     private Map JavaDoc getMethodCache() {
246         return fMethodCache;
247     }
248
249     private void initCalls() {
250         this.fElements = new HashMap JavaDoc();
251
252         initCacheForMethod();
253     }
254
255     /**
256      * Looks up a previously created search result in the "global" cache.
257      * @return the List of previously found search results
258      */

259     private Map JavaDoc lookupMethod(MethodCall methodCall) {
260         return (Map JavaDoc) getMethodCache().get(methodCall.getKey());
261     }
262
263     private void performSearch(IProgressMonitor progressMonitor) {
264         fElements = findChildren(progressMonitor);
265
266         for (Iterator JavaDoc iter = fElements.keySet().iterator(); iter.hasNext();) {
267             checkCanceled(progressMonitor);
268
269             MethodCall methodCall = getMethodCallFromMap(fElements, iter.next());
270             addCallToCache(methodCall);
271         }
272     }
273
274     private MethodCall getMethodCallFromMap(Map JavaDoc elements, Object JavaDoc key) {
275         return (MethodCall) elements.get(key);
276     }
277
278     private void initCacheForMethod() {
279         Map JavaDoc cachedCalls = new HashMap JavaDoc();
280         getMethodCache().put(this.getMethodCall().getKey(), cachedCalls);
281     }
282
283     /**
284      * Checks with the progress monitor to see whether the creation of the type hierarchy
285      * should be canceled. Should be regularly called
286      * so that the user can cancel.
287      *
288      * @exception OperationCanceledException if cancelling the operation has been requested
289      * @see IProgressMonitor#isCanceled
290      */

291     protected void checkCanceled(IProgressMonitor progressMonitor) {
292         if (progressMonitor != null && progressMonitor.isCanceled()) {
293             throw new OperationCanceledException();
294         }
295     }
296     
297     /**
298      * Allows a visitor to traverse the call hierarchy. The visiting is stopped when
299      * a recursive node is reached.
300      *
301      * @param visitor
302      */

303     public void accept(CallHierarchyVisitor visitor, IProgressMonitor progressMonitor) {
304         if (getParent() != null && getParent().isRecursive()) {
305             return;
306         }
307         checkCanceled(progressMonitor);
308         
309         visitor.preVisit(this);
310         if (visitor.visit(this)) {
311             MethodWrapper[] methodWrappers= getCalls(progressMonitor);
312             for (int i= 0; i < methodWrappers.length; i++) {
313                 methodWrappers[i].accept(visitor, progressMonitor);
314             }
315         }
316         visitor.postVisit(this);
317
318         if (progressMonitor != null) {
319             progressMonitor.worked(1);
320         }
321     }
322 }
323
Popular Tags