KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > util > SuperTypeHierarchyCache


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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 JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.Map JavaDoc;
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 public class SuperTypeHierarchyCache {
25     
26     private static class HierarchyCacheEntry implements ITypeHierarchyChangedListener {
27         
28         private ITypeHierarchy fTypeHierarchy;
29         private long fLastAccess;
30         
31         public HierarchyCacheEntry(ITypeHierarchy hierarchy) {
32             fTypeHierarchy= hierarchy;
33             fTypeHierarchy.addTypeHierarchyChangedListener(this);
34             markAsAccessed();
35         }
36         
37         public void typeHierarchyChanged(ITypeHierarchy typeHierarchy) {
38             removeHierarchyEntryFromCache(this);
39         }
40
41         public ITypeHierarchy getTypeHierarchy() {
42             return fTypeHierarchy;
43         }
44
45         public void markAsAccessed() {
46             fLastAccess= System.currentTimeMillis();
47         }
48         
49         public long getLastAccess() {
50             return fLastAccess;
51         }
52         
53         public void dispose() {
54             fTypeHierarchy.removeTypeHierarchyChangedListener(this);
55             fTypeHierarchy= null;
56         }
57         
58         /* (non-Javadoc)
59          * @see java.lang.Object#toString()
60          */

61         public String JavaDoc toString() {
62             return "Super hierarchy of: " + fTypeHierarchy.getType().getElementName(); //$NON-NLS-1$
63
}
64
65     }
66     
67
68     private static final int CACHE_SIZE= 8;
69
70     private static ArrayList JavaDoc fgHierarchyCache= new ArrayList JavaDoc(CACHE_SIZE);
71     private static Map JavaDoc fgMethodOverrideTesterCache= new LRUMap(CACHE_SIZE);
72     
73     private static int fgCacheHits= 0;
74     private static int fgCacheMisses= 0;
75     
76     /**
77      * Get a hierarchy for the given type
78      */

79     public static ITypeHierarchy getTypeHierarchy(IType type) throws JavaModelException {
80         return getTypeHierarchy(type, null);
81     }
82
83     public static MethodOverrideTester getMethodOverrideTester(IType type) throws JavaModelException {
84         MethodOverrideTester test= null;
85         synchronized (fgMethodOverrideTesterCache) {
86             test= (MethodOverrideTester) fgMethodOverrideTesterCache.get(type);
87         }
88         if (test == null) {
89             ITypeHierarchy hierarchy= getTypeHierarchy(type); // don't nest the locks
90
synchronized (fgMethodOverrideTesterCache) {
91                 test= (MethodOverrideTester) fgMethodOverrideTesterCache.get(type); // test again after waiting a long time for 'getTypeHierarchy'
92
if (test == null) {
93                     test= new MethodOverrideTester(type, hierarchy);
94                     fgMethodOverrideTesterCache.put(type, test);
95                 }
96             }
97         }
98         return test;
99     }
100     
101     private static void removeMethodOverrideTester(ITypeHierarchy hierarchy) {
102         synchronized (fgMethodOverrideTesterCache) {
103             for (Iterator JavaDoc iter= fgMethodOverrideTesterCache.values().iterator(); iter.hasNext();) {
104                 MethodOverrideTester curr= (MethodOverrideTester) iter.next();
105                 if (curr.getTypeHierarchy().equals(hierarchy)) {
106                     iter.remove();
107                 }
108             }
109         }
110     }
111
112     
113     /**
114      * Get a hierarchy for the given type
115      */

116     public static ITypeHierarchy getTypeHierarchy(IType type, IProgressMonitor progressMonitor) throws JavaModelException {
117         ITypeHierarchy hierarchy= findTypeHierarchyInCache(type);
118         if (hierarchy == null) {
119             fgCacheMisses++;
120             hierarchy= type.newSupertypeHierarchy(progressMonitor);
121             addTypeHierarchyToCache(hierarchy);
122         } else {
123             fgCacheHits++;
124         }
125         return hierarchy;
126     }
127     
128     private static void addTypeHierarchyToCache(ITypeHierarchy hierarchy) {
129         synchronized (fgHierarchyCache) {
130             int nEntries= fgHierarchyCache.size();
131             if (nEntries >= CACHE_SIZE) {
132                 // find obsolete entries or remove entry that was least recently accessed
133
HierarchyCacheEntry oldest= null;
134                 ArrayList JavaDoc obsoleteHierarchies= new ArrayList JavaDoc(CACHE_SIZE);
135                 for (int i= 0; i < nEntries; i++) {
136                     HierarchyCacheEntry entry= (HierarchyCacheEntry) fgHierarchyCache.get(i);
137                     ITypeHierarchy curr= entry.getTypeHierarchy();
138                     if (!curr.exists() || hierarchy.contains(curr.getType())) {
139                         obsoleteHierarchies.add(entry);
140                     } else {
141                         if (oldest == null || entry.getLastAccess() < oldest.getLastAccess()) {
142                             oldest= entry;
143                         }
144                     }
145                 }
146                 if (!obsoleteHierarchies.isEmpty()) {
147                     for (int i= 0; i < obsoleteHierarchies.size(); i++) {
148                         removeHierarchyEntryFromCache((HierarchyCacheEntry) obsoleteHierarchies.get(i));
149                     }
150                 } else if (oldest != null) {
151                     removeHierarchyEntryFromCache(oldest);
152                 }
153             }
154             HierarchyCacheEntry newEntry= new HierarchyCacheEntry(hierarchy);
155             fgHierarchyCache.add(newEntry);
156         }
157     }
158     
159
160     /**
161      * Check if the given type is in the hierarchy
162      * @param type
163      * @return Return <code>true</code> if a hierarchy for the given type is cached.
164      */

165     public static boolean hasInCache(IType type) {
166         return findTypeHierarchyInCache(type) != null;
167     }
168     
169             
170     private static ITypeHierarchy findTypeHierarchyInCache(IType type) {
171         synchronized (fgHierarchyCache) {
172             for (int i= fgHierarchyCache.size() - 1; i>= 0; i--) {
173                 HierarchyCacheEntry curr= (HierarchyCacheEntry) fgHierarchyCache.get(i);
174                 ITypeHierarchy hierarchy= curr.getTypeHierarchy();
175                 if (!hierarchy.exists()) {
176                     removeHierarchyEntryFromCache(curr);
177                 } else {
178                     if (hierarchy.contains(type)) {
179                         curr.markAsAccessed();
180                         return hierarchy;
181                     }
182                 }
183             }
184         }
185         return null;
186     }
187     
188     private static void removeHierarchyEntryFromCache(HierarchyCacheEntry entry) {
189         synchronized (fgHierarchyCache) {
190             removeMethodOverrideTester(entry.getTypeHierarchy());
191             entry.dispose();
192             fgHierarchyCache.remove(entry);
193         }
194     }
195     
196     
197     /**
198      * Gets the number of times the hierarchy could be taken from the hierarchy.
199      * @return Returns a int
200      */

201     public static int getCacheHits() {
202         return fgCacheHits;
203     }
204     
205     /**
206      * Gets the number of times the hierarchy was build. Used for testing.
207      * @return Returns a int
208      */

209     public static int getCacheMisses() {
210         return fgCacheMisses;
211     }
212 }
213
Popular Tags