1 19 20 package org.netbeans.core.projects; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.IOException ; 25 import java.lang.ref.WeakReference ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.LinkedList ; 29 import java.util.Map.Entry; 30 import java.util.WeakHashMap ; 31 import org.netbeans.core.startup.layers.SessionManager; 32 import org.openide.filesystems.FileChangeAdapter; 33 import org.openide.filesystems.FileChangeListener; 34 import org.openide.filesystems.FileEvent; 35 import org.openide.filesystems.FileLock; 36 import org.openide.filesystems.FileObject; 37 import org.openide.filesystems.FileRenameEvent; 38 import org.openide.filesystems.FileStateInvalidException; 39 import org.openide.filesystems.FileSystem; 40 import org.openide.filesystems.FileUtil; 41 import org.openide.filesystems.Repository; 42 43 47 final class FileStateManager { 48 49 50 public static final int LAYER_SESSION = 1; 51 52 public static final int LAYER_MODULES = 2; 53 54 55 public static final int FSTATE_DEFINED = 0; 56 57 public static final int FSTATE_IGNORED = 1; 58 59 public static final int FSTATE_INHERITED = 2; 60 61 public static final int FSTATE_UNDEFINED = 3; 62 63 64 private static FileStateManager manager = null; 65 66 private WeakHashMap <FileObject, FileInfo> info = new WeakHashMap <FileObject, FileInfo> (); 67 68 private static final int LAYERS_COUNT = 3; 69 70 private FileSystem layers [] = new FileSystem [LAYERS_COUNT]; 71 72 private HashMap <FileStatusListener,LinkedList <FileObject>> listeners = new HashMap <FileStatusListener,LinkedList <FileObject>> (10); 73 74 private PropertyChangeListener propL = null; 75 76 public static synchronized FileStateManager getDefault () { 77 if (manager == null) { 78 manager = new FileStateManager (); 79 } 80 return manager; 81 } 82 83 84 private FileStateManager () { 85 getLayers (); 87 88 propL = new PropL (); 90 SessionManager.getDefault ().addPropertyChangeListener ( 91 org.openide.util.WeakListeners.propertyChange (propL, SessionManager.getDefault ())); 92 } 93 94 public void define (final FileObject mfo, int layer, boolean revert) throws IOException { 95 if (FSTATE_DEFINED == getFileState (mfo, layer)) 97 return; 98 99 FileSystem fsLayer = getLayer (layer); 100 if (fsLayer == null) 101 throw new IllegalArgumentException ("Invalid layer " + layer); 103 FileObject fo = fsLayer.findResource (mfo.getPath()); 105 106 if (fo != null && !revert) { 108 deleteImpl (mfo, fsLayer); 109 fo = null; 110 } 111 112 if (fo == null) { 114 String parent = mfo.getParent ().getPath(); 115 final FileObject fparent = FileUtil.createFolder (fsLayer.getRoot (), parent); 116 fparent.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 117 public void run () throws IOException { 118 mfo.copy (fparent, mfo.getName (), mfo.getExt ()); 119 } 120 }); 121 } 122 123 for (int i = 0; i < layer; i++) { 125 FileSystem fsl = getLayer (i); 126 if (fsl != null) 127 deleteImpl (mfo, fsl); 128 } 129 } 130 131 public void delete (FileObject mfo, int layer) throws IOException { 132 FileSystem fsLayer = getLayer (layer); 133 if (fsLayer == null) 134 throw new IllegalArgumentException ("Invalid layer " + layer); 136 deleteImpl (mfo, fsLayer); 137 } 138 139 public int getFileState (FileObject mfo, int layer) { 140 FileSystem fs = null; 142 FileInfo finf = null; 143 144 try { 145 fs = mfo.getFileSystem (); 146 } catch (FileStateInvalidException e) { 147 } 149 150 if (fs == null || !Repository.getDefault ().getDefaultFileSystem ().equals (fs)) 151 throw new IllegalArgumentException ("FileObject has to be from DefaultFileSystem - " + mfo); 152 153 synchronized (info) { 154 if (null == (finf = info.get(mfo))) { 155 finf = new FileInfo(mfo); 156 info.put(mfo, finf); 157 } 158 } 159 160 return finf.getState (layer); 161 } 162 163 public final void addFileStatusListener (FileStatusListener l, FileObject mfo) { 164 synchronized (listeners) { 165 LinkedList <FileObject> lst = null; 166 if (!listeners.containsKey (l)) { 167 lst = new LinkedList <FileObject> (); 168 listeners.put (l, lst); 169 } 170 else 171 lst = listeners.get (l); 172 173 if (!lst.contains (mfo)) 174 lst.add (mfo); 175 } 176 } 177 178 public final void removeFileStatusListener (FileStatusListener l, FileObject mfo) { 179 synchronized (listeners) { 180 if (mfo == null) 181 listeners.remove (l); 182 else { 183 LinkedList <FileObject> lst = listeners.get (l); 184 if (lst != null) { 185 lst.remove (mfo); 186 if (lst.isEmpty ()) 187 listeners.remove (l); 188 } 189 } 190 } 191 } 192 193 @SuppressWarnings ("unchecked") 194 private void fireFileStatusChanged (FileObject mfo) { 195 HashMap <FileStatusListener,LinkedList <FileObject>> h = null; 196 197 synchronized (listeners) { 198 h = (HashMap <FileStatusListener,LinkedList <FileObject>>)listeners.clone (); 199 } 200 201 for (Entry<FileStatusListener,LinkedList <FileObject>> entry: h.entrySet()) { 202 FileStatusListener l = entry.getKey(); 203 LinkedList <FileObject> lst = entry.getValue(); 204 if (lst.contains (mfo)) 205 l.fileStatusChanged (mfo); 206 } 207 } 208 209 private void deleteImpl (FileObject mfo, FileSystem fsLayer) throws IOException { 210 FileObject fo = fsLayer.findResource (mfo.getPath()); 211 if (fo != null) { 212 FileLock lock = null; 213 try { 214 lock = fo.lock (); 215 fo.delete (lock); 216 } finally { 217 if (lock != null) 218 lock.releaseLock (); 219 } 220 } 221 } 222 223 private void discard (FileObject mfo) { 224 synchronized (info) { 225 info.remove (mfo); 226 } 227 } 228 229 private void getLayers () { 230 layers [LAYER_SESSION] = SessionManager.getDefault ().getLayer (SessionManager.LAYER_SESSION); 231 layers [LAYER_MODULES] = SessionManager.getDefault ().getLayer (SessionManager.LAYER_INSTALL); 232 } 233 234 private FileSystem getLayer (int layer) { 235 return layers [layer]; 236 } 237 238 private class PropL implements PropertyChangeListener { 239 PropL() {} 240 public void propertyChange (PropertyChangeEvent evt) { 241 if (SessionManager.PROP_OPEN.equals (evt.getPropertyName ())) { 242 FileObject mfos [] = null; 243 244 synchronized (info) { 245 mfos = (FileObject [])info.keySet ().toArray (new FileObject [info.size()]); 246 247 for (int i = 0; i < mfos.length; i++) { 249 FileInfo finf = info.get(mfos[i]); 250 251 if (finf != null) 252 finf.invalidate(); 253 } 254 255 info.clear (); 257 258 getLayers (); 260 } 261 262 for (int i = 0; i < mfos.length; i++) 263 fireFileStatusChanged (mfos [i]); 264 } 265 } 266 } 267 268 public static interface FileStatusListener { 269 public void fileStatusChanged (FileObject mfo); 270 } 271 272 private class FileInfo extends FileChangeAdapter { 273 private WeakReference <FileObject> file = null; 274 275 private int state [] = new int [LAYERS_COUNT]; 276 private final Object LOCK = new Object (); 277 278 private FileObject notifiers [] = new FileObject [LAYERS_COUNT]; 279 private FileChangeListener weakL [] = new FileChangeListener [LAYERS_COUNT]; 280 281 public FileInfo (FileObject mfo) { 282 file = new WeakReference <FileObject> (mfo); 283 284 for (int i = 0; i < LAYERS_COUNT; i++) { 286 state [i] = getStateImpl (mfo, i); 287 } 288 289 for (int i = 0; i < LAYERS_COUNT; i++) { 291 attachNotifier (mfo, i); 292 } 293 } 294 295 public void invalidate () { 296 detachAllNotifiers (); 297 synchronized (LOCK) { 298 for (int i = 0; i < LAYERS_COUNT; i++) 299 state [i] = FSTATE_UNDEFINED; 300 } 301 } 302 303 public int getState (int layer) { 304 synchronized (LOCK) { 305 return state [layer]; 306 } 307 } 308 309 private void rescan (FileObject mfo) { 310 boolean changed = false; 311 312 synchronized (LOCK) { 313 for (int i = 0; i < LAYERS_COUNT; i++) { 314 int ns = getStateImpl (mfo, i); 315 if (state [i] != ns) { 316 state [i] = ns; 317 changed = true; 318 } 319 } 320 } 321 322 if (changed) 323 fireFileStatusChanged (mfo); 324 } 325 326 private int getStateImpl (FileObject mfo, int layer) { 327 boolean above = false; 328 boolean below = false; 329 330 for (int i = 0; i < layer; i++) { 332 if (isOnLayer (mfo, i)) { 333 above = true; 334 break; 335 } 336 } 337 338 for (int i = layer + 1; i < LAYERS_COUNT; i++) { 340 if (isOnLayer (mfo, i)) { 341 below = true; 342 break; 343 } 344 } 345 346 if (isOnLayer (mfo, layer)) { 347 return above ? FSTATE_IGNORED : FSTATE_DEFINED; 348 } 349 else { 350 return below && !above ? FSTATE_INHERITED : FSTATE_UNDEFINED; 351 } 352 } 353 354 private boolean isOnLayer (FileObject mfo, int layer) { 355 FileSystem fsLayer = getLayer (layer); 356 return fsLayer == null ? false : null != fsLayer.findResource (mfo.getPath()); 357 } 358 359 364 private synchronized boolean attachNotifier (FileObject mfo, int layer) { 365 FileSystem fsLayer = getLayer (layer); 366 String fn = mfo.getPath(); 367 FileObject fo = null; 368 boolean isDelegate = true; 369 370 if (fsLayer == null) 371 return false; 372 373 while (fn.length () > 0 && null == (fo = fsLayer.findResource (fn))) { 375 int pos = fn.lastIndexOf ('/'); 376 isDelegate = false; 377 378 if (-1 == pos) 379 break; 380 381 fn = fn.substring (0, pos); 382 } 383 384 if (fo == null) 385 fo = fsLayer.getRoot (); 386 387 if (fo != notifiers [layer]) { 388 if (notifiers [layer] != null) 390 notifiers [layer].removeFileChangeListener (weakL [layer]); 391 392 weakL [layer] = FileUtil.weakFileChangeListener (this, fo); 394 fo.addFileChangeListener (weakL [layer]); 395 notifiers [layer] = fo; 396 } 397 398 return isDelegate; 399 } 400 401 private synchronized void detachAllNotifiers () { 402 for (int i = 0; i < LAYERS_COUNT; i++) { 403 if (notifiers [i] != null) { 404 notifiers [i].removeFileChangeListener (weakL [i]); 405 notifiers [i] = null; 406 weakL [i] = null; 407 } 408 } 409 } 410 411 private int layerOfFile (FileObject fo) { 412 try { 413 FileSystem fs = fo.getFileSystem (); 414 for (int i = 0; i < LAYERS_COUNT; i++) { 415 if (fs.equals (getLayer (i))) 416 return i; 417 } 418 } catch (FileStateInvalidException e) { 419 throw (IllegalStateException ) new IllegalStateException ("Invalid file - " + fo).initCause(e); } 421 return -1; 422 } 424 425 427 public void fileRenamed (FileRenameEvent fe) { 428 FileObject mfo = file.get (); 432 if (mfo != null && mfo.isValid ()) { 433 discard (mfo); 434 fireFileStatusChanged (mfo); 435 } 436 else 437 detachAllNotifiers (); 438 } 439 440 public void fileDataCreated (FileEvent fe) { 441 FileObject mfo = file.get (); 442 if (mfo != null && mfo.isValid ()) { 443 String created = fe.getFile ().getPath(); 444 String mfoname = mfo.getPath(); 445 446 if (created.equals (mfoname)) { 447 int layer; 448 if (-1 != (layer = layerOfFile (fe.getFile ()))) 449 attachNotifier (mfo, layer); 450 451 rescan (mfo); 452 } 453 } 454 else 455 detachAllNotifiers (); 456 } 457 458 public void fileFolderCreated (FileEvent fe) { 459 FileObject mfo = file.get (); 460 if (mfo != null && mfo.isValid ()) { 461 String created = fe.getFile ().getPath(); 462 String mfoname = mfo.getPath(); 463 464 if (mfoname.startsWith (created)) { 465 int layer; 466 if (-1 != (layer = layerOfFile (fe.getFile ()))) 467 if (attachNotifier (mfo, layer)) { 468 rescan (mfo); 470 } 471 } 472 } 473 else 474 detachAllNotifiers (); 475 } 476 477 public void fileDeleted (FileEvent fe) { 478 FileObject mfo = file.get (); 479 if (mfo != null && mfo.isValid ()) { 480 String deleted = fe.getFile ().getPath(); 481 String mfoname = mfo.getPath(); 482 483 if (deleted.equals (mfoname)) { 484 int layer; 485 if (-1 != (layer = layerOfFile (fe.getFile ()))) 486 attachNotifier (mfo, layer); 487 488 rescan (mfo); 489 } 490 } 491 else 492 detachAllNotifiers (); 493 } 494 } 495 } 496 | Popular Tags |