1 19 20 package org.netbeans.modules.j2ee.metadata; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.beans.PropertyChangeSupport ; 25 import java.io.IOException ; 26 import java.lang.ref.WeakReference ; 27 import java.util.ArrayList ; 28 import java.util.Collections ; 29 import java.util.HashSet ; 30 import java.util.List ; 31 import java.util.Set ; 32 import javax.swing.event.ChangeEvent ; 33 import javax.swing.event.ChangeListener ; 34 import org.netbeans.api.java.classpath.ClassPath; 35 import org.netbeans.api.java.queries.SourceForBinaryQuery; 36 import org.openide.ErrorManager; 37 import org.openide.filesystems.FileObject; 38 import org.openide.filesystems.FileSystem; 39 import org.openide.filesystems.Repository; 40 import org.openide.util.Utilities; 41 import org.openide.util.WeakListeners; 42 43 52 public class ClassPathSourceCache { 53 54 public final static String PROP_ROOTS = ClassPath.PROP_ROOTS; 55 56 73 77 private final WeakReference <ClassPath> classPathRef; 78 private final Listener listener = new Listener (); 79 80 private final PropertyChangeSupport propChangeSupport = new PropertyChangeSupport (this); 81 82 86 List <SourceForBinaryQuery.Result> results; 87 88 91 private long invalidResults; 92 93 97 Set <FileObject> sourceRoots; 98 99 103 private long invalidSourceRoots; 104 105 109 boolean deinitialized; 110 111 private boolean resolveSources; 112 113 public static ClassPathSourceCache newInstance(ClassPath classPath, boolean resolveSources) { 114 ClassPathSourceCache created = new ClassPathSourceCache(classPath, resolveSources); 115 created.initialize(); 116 return created; 117 } 118 119 private ClassPathSourceCache(ClassPath classPath, boolean resolveSources) { 120 assert classPath != null; 121 classPathRef = new CleanupReference<ClassPath>(classPath); 122 this.resolveSources = resolveSources; 123 } 124 125 132 private void initialize() { 133 ClassPath classPath = classPathRef.get(); 134 if (classPath != null) { 135 classPath.addPropertyChangeListener(WeakListeners.propertyChange(listener, classPath)); 136 } 137 } 138 139 public void addPropertyChangeListener(PropertyChangeListener listener) { 140 propChangeSupport.addPropertyChangeListener(listener); 141 } 142 143 public void removePropertyChangeListener(PropertyChangeListener listener) { 144 propChangeSupport.removePropertyChangeListener(listener); 145 } 146 147 155 public boolean contains(FileObject f) { 156 if (findOwnerRoot(getSourceRootSet(), f) != null) { 157 return true; 158 } 159 return false; 160 } 161 162 public FileObject[] getRoots() { 163 Set <FileObject> sourceRoots = getSourceRootSet(); 164 return sourceRoots.toArray(new FileObject[sourceRoots.size()]); 165 } 166 167 private Set <FileObject> getSourceRootSet() { 168 long invalidSourceRootsCopy; 169 170 synchronized (this) { 171 if (sourceRoots != null) { 172 return sourceRoots; 173 } 174 175 invalidSourceRootsCopy = invalidSourceRoots; 176 } 177 178 final Set <FileObject> newSourceRoots = new HashSet <FileObject>(); 179 try { 182 Repository.getDefault().getDefaultFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 183 public void run() throws IOException { 184 ClassPath classPath = classPathRef.get(); 185 if (classPath != null) { 186 for (FileObject root : classPath.getRoots()) { 187 newSourceRoots.add(root); 188 } 189 } 190 } 191 }); 192 } catch (IOException e) { 193 ErrorManager.getDefault().notify(e); 195 } 196 197 if (resolveSources) { 198 for (SourceForBinaryQuery.Result result : getResults()) { 200 for (FileObject sourceRoot : result.getRoots()) { 201 newSourceRoots.add(sourceRoot); 202 } 203 } 204 } 205 206 synchronized (this) { 207 if (invalidSourceRoots == invalidSourceRootsCopy) { 208 if (sourceRoots == null) { 209 sourceRoots = newSourceRoots; 210 } 211 return sourceRoots; 212 } else { 213 return newSourceRoots; 214 } 215 } 216 } 217 218 private List <SourceForBinaryQuery.Result> getResults() { 219 long invalidResultsCopy; 220 221 synchronized (this) { 222 if (results != null) { 223 return results; 224 } 225 226 assert sourceRoots == null; 231 232 invalidResultsCopy = invalidResults; 233 } 234 235 List <SourceForBinaryQuery.Result> newResults = null; 236 ClassPath classPath = classPathRef.get(); 237 if (classPath == null) { 238 newResults = Collections.emptyList(); 239 } else { 240 newResults = new ArrayList <SourceForBinaryQuery.Result>(); 241 List <ClassPath.Entry> entries = classPath.entries(); 242 for (ClassPath.Entry entry : entries) { 243 newResults.add(SourceForBinaryQuery.findSourceRoots(entry.getURL())); 244 } 245 } 246 247 synchronized (this) { 248 if (invalidResults == invalidResultsCopy) { 249 if (results == null) { 250 for (SourceForBinaryQuery.Result result : newResults) { 251 result.addChangeListener(listener); 252 } 253 results = newResults; 254 } 255 return results; 256 } else { 257 return newResults; 258 } 259 } 260 } 261 262 private static FileObject findOwnerRoot(Set <FileObject> roots, FileObject resource) { 263 for (FileObject f = resource; f != null; f = f.getParent()) { 264 if (roots.contains(f)) { 265 return f; 266 } 267 } 268 return null; 269 } 270 271 275 private final class Listener implements PropertyChangeListener , ChangeListener { 276 277 public void propertyChange(PropertyChangeEvent evt) { 278 String propertyName = evt.getPropertyName(); 279 if (ClassPath.PROP_ENTRIES.equals(propertyName)) { 280 if (resolveSources) { 281 entriesChanged(); 282 } 283 } else if (ClassPath.PROP_ROOTS.equals(propertyName)) { 284 rootsChanged(); 285 } 286 } 287 288 public void stateChanged(ChangeEvent evt) { 289 rootsChanged(); 290 } 291 292 private void entriesChanged() { 293 synchronized (ClassPathSourceCache.this) { 294 if (!deinitialized) { 295 if (results != null) { 296 for (SourceForBinaryQuery.Result result : results) { 297 result.removeChangeListener(this); 298 } 299 } 300 results = null; 301 invalidResults++; 302 sourceRoots = null; 303 invalidSourceRoots++; 304 propChangeSupport.firePropertyChange(PROP_ROOTS, null, null); 305 } 306 } 307 } 308 309 private void rootsChanged() { 310 synchronized (ClassPathSourceCache.this) { 311 if (!deinitialized) { 312 sourceRoots = null; 313 invalidSourceRoots++; 314 propChangeSupport.firePropertyChange(PROP_ROOTS, null, null); 315 } 316 } 317 } 318 } 319 320 324 private final class CleanupReference<T> extends WeakReference <T> implements Runnable { 325 326 public CleanupReference(T referent) { 327 super(referent, Utilities.activeReferenceQueue()); 328 } 329 330 public void run() { 331 synchronized (ClassPathSourceCache.this) { 332 if (results != null) { 333 for (SourceForBinaryQuery.Result result : results) { 334 result.removeChangeListener(listener); 335 } 336 } 337 results = Collections.emptyList(); 338 invalidResults++; 339 sourceRoots = Collections.emptySet(); 340 invalidSourceRoots++; 341 342 deinitialized = true; 343 } 344 } 345 } 346 } 347 | Popular Tags |