]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/util/SuperTypeHierarchyCache.java
9706a173d8b15c731bfc8463658c7fbd3ee242e2
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / util / SuperTypeHierarchyCache.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 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.util;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.Map;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18
19 import org.eclipse.jdt.core.IType;
20 import org.eclipse.jdt.core.ITypeHierarchy;
21 import org.eclipse.jdt.core.ITypeHierarchyChangedListener;
22 import org.eclipse.jdt.core.JavaModelException;
23
24 /**
25  * A thread-safe cache for super type hierarchies.
26  */
27 public class SuperTypeHierarchyCache {
28
29         private static class HierarchyCacheEntry implements ITypeHierarchyChangedListener {
30
31                 private ITypeHierarchy fTypeHierarchy;
32                 private long fLastAccess;
33
34                 public HierarchyCacheEntry(ITypeHierarchy hierarchy) {
35                         fTypeHierarchy= hierarchy;
36                         fTypeHierarchy.addTypeHierarchyChangedListener(this);
37                         markAsAccessed();
38                 }
39
40                 public void typeHierarchyChanged(ITypeHierarchy typeHierarchy) {
41                         removeHierarchyEntryFromCache(this);
42                 }
43
44                 public ITypeHierarchy getTypeHierarchy() {
45                         return fTypeHierarchy;
46                 }
47
48                 public void markAsAccessed() {
49                         fLastAccess= System.currentTimeMillis();
50                 }
51
52                 public long getLastAccess() {
53                         return fLastAccess;
54                 }
55
56                 public void dispose() {
57                         if (fTypeHierarchy != null) {
58                                 fTypeHierarchy.removeTypeHierarchyChangedListener(this);
59                                 fTypeHierarchy= null;
60                         }
61                 }
62
63                 /* (non-Javadoc)
64                  * @see java.lang.Object#toString()
65                  */
66                 @Override
67                 public String toString() {
68                         return "Super hierarchy of: " + fTypeHierarchy.getType().getElementName(); //$NON-NLS-1$
69                 }
70
71         }
72
73
74         private static final int CACHE_SIZE= 8;
75
76         private static ArrayList<HierarchyCacheEntry> fgHierarchyCache= new ArrayList<HierarchyCacheEntry>(CACHE_SIZE);
77         private static Map<IType, MethodOverrideTester> fgMethodOverrideTesterCache= new LRUMap<IType, MethodOverrideTester>(CACHE_SIZE);
78
79         private static int fgCacheHits= 0;
80         private static int fgCacheMisses= 0;
81
82         /**
83          * Returns a super type hierarchy that contains the given type.
84          * The returned hierarchy may actually be based on a subtype of the
85          * requested type. Therefore, queries such as {@link ITypeHierarchy#getAllClasses()}
86          * or {@link ITypeHierarchy#getRootInterfaces()} may return more types than the same
87          * queries on a type hierarchy for just the given type.
88          *
89          * @param type the focus type
90          * @return a supertype hierarchy that contains <code>type</code>
91          * @throws JavaModelException if a problem occurs
92          */
93         public static ITypeHierarchy getTypeHierarchy(IType type) throws JavaModelException {
94                 return getTypeHierarchy(type, null);
95         }
96
97         public static MethodOverrideTester getMethodOverrideTester(IType type) throws JavaModelException {
98                 MethodOverrideTester test= null;
99                 synchronized (fgMethodOverrideTesterCache) {
100                         test= fgMethodOverrideTesterCache.get(type);
101                 }
102                 if (test == null) {
103                         ITypeHierarchy hierarchy= getTypeHierarchy(type); // don't nest the locks
104                         synchronized (fgMethodOverrideTesterCache) {
105                                 test= fgMethodOverrideTesterCache.get(type); // test again after waiting a long time for 'getTypeHierarchy'
106                                 if (test == null) {
107                                         test= new MethodOverrideTester(type, hierarchy);
108                                         fgMethodOverrideTesterCache.put(type, test);
109                                 }
110                         }
111                 }
112                 return test;
113         }
114
115         private static void removeMethodOverrideTester(ITypeHierarchy hierarchy) {
116                 synchronized (fgMethodOverrideTesterCache) {
117                         for (Iterator<MethodOverrideTester> iter= fgMethodOverrideTesterCache.values().iterator(); iter.hasNext();) {
118                                 MethodOverrideTester curr= iter.next();
119                                 if (curr.getTypeHierarchy().equals(hierarchy)) {
120                                         iter.remove();
121                                 }
122                         }
123                 }
124         }
125
126         /**
127          * Returns a super type hierarchy that contains the given type.
128          * The returned hierarchy may actually be based on a subtype of the
129          * requested type. Therefore, queries such as {@link ITypeHierarchy#getAllClasses()}
130          * or {@link ITypeHierarchy#getRootInterfaces()} may return more types than the same
131          * queries on a type hierarchy for just the given type.
132          *
133          * @param type the focus type
134          * @param progressMonitor progress monitor
135          * @return a supertype hierarchy that contains <code>type</code>
136          * @throws JavaModelException if a problem occurs
137          */
138         public static ITypeHierarchy getTypeHierarchy(IType type, IProgressMonitor progressMonitor) throws JavaModelException {
139                 ITypeHierarchy hierarchy= findTypeHierarchyInCache(type);
140                 if (hierarchy == null) {
141                         fgCacheMisses++;
142                         hierarchy= type.newSupertypeHierarchy(progressMonitor);
143                         addTypeHierarchyToCache(hierarchy);
144                 } else {
145                         fgCacheHits++;
146                 }
147                 return hierarchy;
148         }
149
150         private static void addTypeHierarchyToCache(ITypeHierarchy hierarchy) {
151                 synchronized (fgHierarchyCache) {
152                         int nEntries= fgHierarchyCache.size();
153                         if (nEntries >= CACHE_SIZE) {
154                                 // find obsolete entries or remove entry that was least recently accessed
155                                 HierarchyCacheEntry oldest= null;
156                                 ArrayList<HierarchyCacheEntry> obsoleteHierarchies= new ArrayList<HierarchyCacheEntry>(CACHE_SIZE);
157                                 for (int i= 0; i < nEntries; i++) {
158                                         HierarchyCacheEntry entry= fgHierarchyCache.get(i);
159                                         ITypeHierarchy curr= entry.getTypeHierarchy();
160                                         if (!curr.exists() || hierarchy.contains(curr.getType())) {
161                                                 obsoleteHierarchies.add(entry);
162                                         } else {
163                                                 if (oldest == null || entry.getLastAccess() < oldest.getLastAccess()) {
164                                                         oldest= entry;
165                                                 }
166                                         }
167                                 }
168                                 if (!obsoleteHierarchies.isEmpty()) {
169                                         for (int i= 0; i < obsoleteHierarchies.size(); i++) {
170                                                 removeHierarchyEntryFromCache(obsoleteHierarchies.get(i));
171                                         }
172                                 } else if (oldest != null) {
173                                         removeHierarchyEntryFromCache(oldest);
174                                 }
175                         }
176                         HierarchyCacheEntry newEntry= new HierarchyCacheEntry(hierarchy);
177                         fgHierarchyCache.add(newEntry);
178                 }
179         }
180
181
182         /**
183          * Check if the given type is in the hierarchy cache.
184          * @param type a type
185          * @return <code>true</code> if a hierarchy for the given type is cached
186          */
187         public static boolean hasInCache(IType type) {
188                 return findTypeHierarchyInCache(type) != null;
189         }
190
191
192         private static ITypeHierarchy findTypeHierarchyInCache(IType type) {
193                 synchronized (fgHierarchyCache) {
194                         for (int i= fgHierarchyCache.size() - 1; i>= 0; i--) {
195                                 HierarchyCacheEntry curr= fgHierarchyCache.get(i);
196                                 ITypeHierarchy hierarchy= curr.getTypeHierarchy();
197                                 if (!hierarchy.exists()) {
198                                         removeHierarchyEntryFromCache(curr);
199                                 } else {
200                                         if (hierarchy.contains(type)) {
201                                                 curr.markAsAccessed();
202                                                 return hierarchy;
203                                         }
204                                 }
205                         }
206                 }
207                 return null;
208         }
209
210         private static void removeHierarchyEntryFromCache(HierarchyCacheEntry entry) {
211                 synchronized (fgHierarchyCache) {
212                         removeMethodOverrideTester(entry.getTypeHierarchy());
213                         entry.dispose();
214                         fgHierarchyCache.remove(entry);
215                 }
216         }
217
218
219         /**
220          * Gets the number of times the hierarchy could be taken from the hierarchy.
221          * @return Returns a int
222          */
223         public static int getCacheHits() {
224                 return fgCacheHits;
225         }
226
227         /**
228          * Gets the number of times the hierarchy was build. Used for testing.
229          * @return Returns a int
230          */
231         public static int getCacheMisses() {
232                 return fgCacheMisses;
233         }
234 }