KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.net.URI JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21
22 import org.eclipse.core.filesystem.EFS;
23 import org.eclipse.core.filesystem.IFileInfo;
24
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.IStatus;
28 import org.eclipse.core.runtime.OperationCanceledException;
29 import org.eclipse.core.runtime.Status;
30 import org.eclipse.core.runtime.jobs.Job;
31
32 import org.eclipse.core.filebuffers.FileBuffers;
33 import org.eclipse.core.filebuffers.ITextFileBuffer;
34 import org.eclipse.core.filebuffers.ITextFileBufferManager;
35 import org.eclipse.core.filebuffers.LocationKind;
36
37 import org.eclipse.core.resources.IResource;
38
39 import org.eclipse.jdt.core.ElementChangedEvent;
40 import org.eclipse.jdt.core.ICompilationUnit;
41 import org.eclipse.jdt.core.IElementChangedListener;
42 import org.eclipse.jdt.core.IJavaElement;
43 import org.eclipse.jdt.core.IJavaElementDelta;
44 import org.eclipse.jdt.core.IPackageFragmentRoot;
45 import org.eclipse.jdt.core.IType;
46 import org.eclipse.jdt.core.JavaCore;
47 import org.eclipse.jdt.core.JavaModelException;
48 import org.eclipse.jdt.core.search.SearchEngine;
49 import org.eclipse.jdt.core.search.TypeNameMatch;
50
51 import org.eclipse.jdt.internal.corext.CorextMessages;
52
53 import org.eclipse.jdt.internal.ui.JavaPlugin;
54
55 import org.w3c.dom.Element JavaDoc;
56
57 /**
58  * History for the open type dialog. Object and keys are both {@link TypeNameMatch}s.
59  */

60 public class OpenTypeHistory extends History {
61     
62     private static class TypeHistoryDeltaListener implements IElementChangedListener {
63         public void elementChanged(ElementChangedEvent event) {
64             if (processDelta(event.getDelta())) {
65                 OpenTypeHistory.getInstance().markAsInconsistent();
66             }
67         }
68         
69         /**
70          * Computes whether the history needs a consistency check or not.
71          *
72          * @param delta the Java element delta
73          *
74          * @return <code>true</code> if consistency must be checked
75          * <code>false</code> otherwise.
76          */

77         private boolean processDelta(IJavaElementDelta delta) {
78             IJavaElement elem= delta.getElement();
79             
80             boolean isChanged= delta.getKind() == IJavaElementDelta.CHANGED;
81             boolean isRemoved= delta.getKind() == IJavaElementDelta.REMOVED;
82                         
83             switch (elem.getElementType()) {
84                 case IJavaElement.JAVA_PROJECT:
85                     if (isRemoved || (isChanged &&
86                             (delta.getFlags() & IJavaElementDelta.F_CLOSED) != 0)) {
87                         return true;
88                     }
89                     return processChildrenDelta(delta);
90                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
91                     if (isRemoved || (isChanged && (
92                             (delta.getFlags() & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0 ||
93                             (delta.getFlags() & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0))) {
94                         return true;
95                     }
96                     return processChildrenDelta(delta);
97                 case IJavaElement.TYPE:
98                     if (isChanged && (delta.getFlags() & IJavaElementDelta.F_MODIFIERS) != 0) {
99                         return true;
100                     }
101                     // type children can be inner classes: fall through
102
case IJavaElement.JAVA_MODEL:
103                 case IJavaElement.PACKAGE_FRAGMENT:
104                 case IJavaElement.CLASS_FILE:
105                     if (isRemoved) {
106                         return true;
107                     }
108                     return processChildrenDelta(delta);
109                 case IJavaElement.COMPILATION_UNIT:
110                     // Not the primary compilation unit. Ignore it
111
if (!JavaModelUtil.isPrimary((ICompilationUnit) elem)) {
112                         return false;
113                     }
114
115                     if (isRemoved || (isChanged && isUnknownStructuralChange(delta.getFlags()))) {
116                         return true;
117                     }
118                     return processChildrenDelta(delta);
119                 default:
120                     // fields, methods, imports ect
121
return false;
122             }
123         }
124         
125         private boolean isUnknownStructuralChange(int flags) {
126             if ((flags & IJavaElementDelta.F_CONTENT) == 0)
127                 return false;
128             return (flags & IJavaElementDelta.F_FINE_GRAINED) == 0;
129         }
130
131         /*
132         private boolean isPossibleStructuralChange(int flags) {
133             return (flags & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_FINE_GRAINED)) == IJavaElementDelta.F_CONTENT;
134         }
135         */

136         
137         private boolean processChildrenDelta(IJavaElementDelta delta) {
138             IJavaElementDelta[] children= delta.getAffectedChildren();
139             for (int i= 0; i < children.length; i++) {
140                 if (processDelta(children[i])) {
141                     return true;
142                 }
143             }
144             return false;
145         }
146     }
147     
148     private static class UpdateJob extends Job {
149         public static final String JavaDoc FAMILY= UpdateJob.class.getName();
150         public UpdateJob() {
151             super(CorextMessages.TypeInfoHistory_consistency_check);
152         }
153         protected IStatus run(IProgressMonitor monitor) {
154             OpenTypeHistory history= OpenTypeHistory.getInstance();
155             history.internalCheckConsistency(monitor);
156             return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
157
}
158         public boolean belongsTo(Object JavaDoc family) {
159             return FAMILY.equals(family);
160         }
161     }
162     
163     // Needs to be volatile since accesses aren't synchronized.
164
private volatile boolean fNeedsConsistencyCheck;
165     // Map of cached time stamps
166
private Map JavaDoc fTimestampMapping;
167     
168     private final IElementChangedListener fDeltaListener;
169     private final UpdateJob fUpdateJob;
170     
171     private static final String JavaDoc FILENAME= "OpenTypeHistory.xml"; //$NON-NLS-1$
172
private static final String JavaDoc NODE_ROOT= "typeInfoHistroy"; //$NON-NLS-1$
173
private static final String JavaDoc NODE_TYPE_INFO= "typeInfo"; //$NON-NLS-1$
174
private static final String JavaDoc NODE_HANDLE= "handle"; //$NON-NLS-1$
175
private static final String JavaDoc NODE_MODIFIERS= "modifiers"; //$NON-NLS-1$
176
private static final String JavaDoc NODE_TIMESTAMP= "timestamp"; //$NON-NLS-1$
177

178     private static OpenTypeHistory fgInstance;
179     
180     public static synchronized OpenTypeHistory getInstance() {
181         if (fgInstance == null)
182             fgInstance= new OpenTypeHistory();
183         return fgInstance;
184     }
185     
186     public static synchronized void shutdown() {
187         if (fgInstance == null)
188             return;
189         fgInstance.doShutdown();
190     }
191     
192     private OpenTypeHistory() {
193         super(FILENAME, NODE_ROOT, NODE_TYPE_INFO);
194         fTimestampMapping= new HashMap JavaDoc();
195         fNeedsConsistencyCheck= true;
196         load();
197         fDeltaListener= new TypeHistoryDeltaListener();
198         JavaCore.addElementChangedListener(fDeltaListener);
199         fUpdateJob= new UpdateJob();
200         // It is not necessary anymore that the update job has a rule since
201
// markAsInconsistent isn't synchronized anymore. See bugs
202
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=128399 and
203
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=135278
204
// for details.
205
fUpdateJob.setPriority(Job.SHORT);
206     }
207     
208     public void markAsInconsistent() {
209         fNeedsConsistencyCheck= true;
210         // cancel the old job. If no job is running this is a NOOP.
211
fUpdateJob.cancel();
212         fUpdateJob.schedule();
213     }
214     
215     public boolean needConsistencyCheck() {
216         return fNeedsConsistencyCheck;
217     }
218
219     public void checkConsistency(IProgressMonitor monitor) throws OperationCanceledException {
220         if (!fNeedsConsistencyCheck)
221             return;
222         if (fUpdateJob.getState() == Job.RUNNING) {
223             try {
224                 Job.getJobManager().join(UpdateJob.FAMILY, monitor);
225             } catch (OperationCanceledException e) {
226                 // Ignore and do the consistency check without
227
// waiting for the update job.
228
} catch (InterruptedException JavaDoc e) {
229                 // Ignore and do the consistency check without
230
// waiting for the update job.
231
}
232         }
233         if (!fNeedsConsistencyCheck)
234             return;
235         internalCheckConsistency(monitor);
236     }
237     
238     public synchronized boolean contains(TypeNameMatch type) {
239         return super.contains(type);
240     }
241
242     public synchronized void accessed(TypeNameMatch info) {
243         // Fetching the timestamp might not be cheap (remote file system
244
// external Jars. So check if we alreay have one.
245
if (!fTimestampMapping.containsKey(info)) {
246             fTimestampMapping.put(info, new Long JavaDoc(getContainerTimestamp(info)));
247         }
248         super.accessed(info);
249     }
250
251     public synchronized TypeNameMatch remove(TypeNameMatch info) {
252         fTimestampMapping.remove(info);
253         return (TypeNameMatch)super.remove(info);
254     }
255     
256     public synchronized void replace(TypeNameMatch old, TypeNameMatch newMatch) {
257         fTimestampMapping.remove(old);
258         fTimestampMapping.put(newMatch, new Long JavaDoc(getContainerTimestamp(newMatch)));
259         super.remove(old);
260         super.accessed(newMatch);
261     }
262
263     public synchronized TypeNameMatch[] getTypeInfos() {
264         Collection JavaDoc values= getValues();
265         int size= values.size();
266         TypeNameMatch[] result= new TypeNameMatch[size];
267         int i= size - 1;
268         for (Iterator JavaDoc iter= values.iterator(); iter.hasNext();) {
269             result[i]= (TypeNameMatch)iter.next();
270             i--;
271         }
272         return result;
273     }
274
275     public synchronized TypeNameMatch[] getFilteredTypeInfos(TypeInfoFilter filter) {
276         Collection JavaDoc values= getValues();
277         List JavaDoc result= new ArrayList JavaDoc();
278         for (Iterator JavaDoc iter= values.iterator(); iter.hasNext();) {
279             TypeNameMatch type= (TypeNameMatch)iter.next();
280             if ((filter == null || filter.matchesHistoryElement(type)) && !TypeFilter.isFiltered(type.getFullyQualifiedName()))
281                 result.add(type);
282         }
283         Collections.reverse(result);
284         return (TypeNameMatch[])result.toArray(new TypeNameMatch[result.size()]);
285         
286     }
287     
288     protected Object JavaDoc getKey(Object JavaDoc object) {
289         return object;
290     }
291
292     private synchronized void internalCheckConsistency(IProgressMonitor monitor) throws OperationCanceledException {
293         // Setting fNeedsConsistencyCheck is necessary here since
294
// markAsInconsistent isn't synchronized.
295
fNeedsConsistencyCheck= true;
296         List JavaDoc typesToCheck= new ArrayList JavaDoc(getKeys());
297         monitor.beginTask(CorextMessages.TypeInfoHistory_consistency_check, typesToCheck.size());
298         monitor.setTaskName(CorextMessages.TypeInfoHistory_consistency_check);
299         for (Iterator JavaDoc iter= typesToCheck.iterator(); iter.hasNext();) {
300             TypeNameMatch type= (TypeNameMatch)iter.next();
301             long currentTimestamp= getContainerTimestamp(type);
302             Long JavaDoc lastTested= (Long JavaDoc)fTimestampMapping.get(type);
303             if (lastTested != null && currentTimestamp != IResource.NULL_STAMP && currentTimestamp == lastTested.longValue() && !isContainerDirty(type))
304                 continue;
305             try {
306                 IType jType= type.getType();
307                 if (jType == null || !jType.exists()) {
308                     remove(type);
309                 } else {
310                     // copy over the modifiers since they may have changed
311
int modifiers= jType.getFlags();
312                     if (modifiers != type.getModifiers()) {
313                         replace(type, SearchEngine.createTypeNameMatch(jType, modifiers));
314                     } else {
315                         fTimestampMapping.put(type, new Long JavaDoc(currentTimestamp));
316                     }
317                 }
318             } catch (JavaModelException e) {
319                 remove(type);
320             }
321             if (monitor.isCanceled())
322                 throw new OperationCanceledException();
323             monitor.worked(1);
324         }
325         monitor.done();
326         fNeedsConsistencyCheck= false;
327     }
328     
329     private long getContainerTimestamp(TypeNameMatch match) {
330         try {
331             IType type= match.getType();
332             IResource resource= type.getResource();
333             if (resource != null) {
334                 URI JavaDoc location= resource.getLocationURI();
335                 if (location != null) {
336                     IFileInfo info= EFS.getStore(location).fetchInfo();
337                     if (info.exists()) {
338                         // The element could be removed from the build path. So check
339
// if the Java element still exists.
340
IJavaElement element= JavaCore.create(resource);
341                         if (element != null && element.exists())
342                             return info.getLastModified();
343                     }
344                 }
345             } else { // external JAR
346
IPackageFragmentRoot root= match.getPackageFragmentRoot();
347                 if (root.exists()) {
348                     IFileInfo info= EFS.getLocalFileSystem().getStore(root.getPath()).fetchInfo();
349                     if (info.exists()) {
350                         return info.getLastModified();
351                     }
352                 }
353             }
354         } catch (CoreException e) {
355             // Fall through
356
}
357         return IResource.NULL_STAMP;
358     }
359     
360     
361     public boolean isContainerDirty(TypeNameMatch match) {
362         ICompilationUnit cu= match.getType().getCompilationUnit();
363         if (cu == null) {
364             return false;
365         }
366         IResource resource= cu.getResource();
367         ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
368         ITextFileBuffer textFileBuffer= manager.getTextFileBuffer(resource.getFullPath(), LocationKind.IFILE);
369         if (textFileBuffer != null) {
370             return textFileBuffer.isDirty();
371         }
372         return false;
373     }
374     
375     
376     private void doShutdown() {
377         JavaCore.removeElementChangedListener(fDeltaListener);
378         save();
379     }
380     
381     protected Object JavaDoc createFromElement(Element type) {
382         String JavaDoc handle= type.getAttribute(NODE_HANDLE);
383         if (handle == null )
384             return null;
385         
386         IJavaElement element= JavaCore.create(handle);
387         if (!(element instanceof IType))
388             return null;
389         
390         int modifiers= 0;
391         try {
392             modifiers= Integer.parseInt(type.getAttribute(NODE_MODIFIERS));
393         } catch (NumberFormatException JavaDoc e) {
394             // take zero
395
}
396         TypeNameMatch info= SearchEngine.createTypeNameMatch((IType) element, modifiers);
397         long timestamp= IResource.NULL_STAMP;
398         String JavaDoc timestampValue= type.getAttribute(NODE_TIMESTAMP);
399         if (timestampValue != null && timestampValue.length() > 0) {
400             try {
401                 timestamp= Long.parseLong(timestampValue);
402             } catch (NumberFormatException JavaDoc e) {
403                 // take null stamp
404
}
405         }
406         if (timestamp != IResource.NULL_STAMP) {
407             fTimestampMapping.put(info, new Long JavaDoc(timestamp));
408         }
409         return info;
410     }
411
412     protected void setAttributes(Object JavaDoc object, Element typeElement) {
413         TypeNameMatch type= (TypeNameMatch) object;
414         String JavaDoc handleId= type.getType().getHandleIdentifier();
415         typeElement.setAttribute(NODE_HANDLE, handleId);
416         typeElement.setAttribute(NODE_MODIFIERS, Integer.toString(type.getModifiers()));
417         Long JavaDoc timestamp= (Long JavaDoc) fTimestampMapping.get(type);
418         if (timestamp == null) {
419             typeElement.setAttribute(NODE_TIMESTAMP, Long.toString(IResource.NULL_STAMP));
420         } else {
421             typeElement.setAttribute(NODE_TIMESTAMP, timestamp.toString());
422         }
423     }
424
425 }
426
Popular Tags