1 19 20 package org.netbeans.core.startup.layers; 21 22 import java.io.BufferedReader ; 23 import java.io.File ; 24 import java.io.FileInputStream ; 25 import java.io.FileOutputStream ; 26 import java.io.IOException ; 27 import java.io.InputStreamReader ; 28 import java.io.OutputStreamWriter ; 29 import java.io.Writer ; 30 import java.lang.reflect.Constructor ; 31 import java.net.URI ; 32 import java.net.URL ; 33 import java.util.ArrayList ; 34 import java.util.Arrays ; 35 import java.util.Collection ; 36 import java.util.Collections ; 37 import java.util.Comparator ; 38 import java.util.Date ; 39 import java.util.Iterator ; 40 import java.util.List ; 41 import java.util.logging.Level ; 42 import java.util.logging.Logger ; 43 import org.netbeans.core.startup.StartLog; 44 import org.openide.filesystems.FileSystem; 45 import org.openide.filesystems.FileSystem.AtomicAction; 46 import org.openide.filesystems.MultiFileSystem; 47 import org.openide.filesystems.Repository; 48 import org.openide.util.NbBundle; 49 import org.openide.util.Utilities; 50 51 56 public class ModuleLayeredFileSystem extends MultiFileSystem { 57 58 private static final long serialVersionUID = 782910986724201983L; 59 60 private static final String LAYER_STAMP = "layer-stamp.txt"; 61 62 static final Logger err = Logger.getLogger("org.netbeans.core.projects"); 64 65 private List <URL > urls; 66 67 private LayerCacheManager manager; 68 69 private final FileSystem writableLayer; 70 71 private FileSystem cacheLayer; 72 73 private final FileSystem[] otherLayers; 74 75 80 ModuleLayeredFileSystem (FileSystem writableLayer, FileSystem[] otherLayers, File cacheDir) throws IOException { 81 this(writableLayer, otherLayers, manager(cacheDir)); 82 } 83 84 private ModuleLayeredFileSystem(FileSystem writableLayer, FileSystem[] otherLayers, LayerCacheManager mgr) throws IOException { 85 this(writableLayer, otherLayers, mgr, loadCache(mgr)); 86 } 87 88 private ModuleLayeredFileSystem(FileSystem writableLayer, FileSystem[] otherLayers, LayerCacheManager mgr, FileSystem cacheLayer) throws IOException { 89 super(appendLayers(writableLayer, otherLayers, cacheLayer)); 90 this.manager = mgr; 91 this.writableLayer = writableLayer; 92 this.otherLayers = otherLayers; 93 this.cacheLayer = cacheLayer; 94 95 setPropagateMasks (true); 100 101 urls = null; 102 } 103 104 private static LayerCacheManager manager(File cacheDir) throws IOException { 105 if (cacheDir != null) { 106 if (!cacheDir.isDirectory()) { 107 if (!cacheDir.mkdirs()) { 108 throw new IOException ("Could not make dir: " + cacheDir); } 110 } 111 String defaultManager = "org.netbeans.core.startup.layers.BinaryCacheManager"; String managerName = System.getProperty("netbeans.cache.layers", defaultManager); if (managerName.equals("-")) { err.fine("Cache manager disabled"); 115 return LayerCacheManager.emptyManager(); 116 } 117 try { 118 Class <?> c = Class.forName(managerName); 119 Constructor ctor = c.getConstructor(File .class); 120 LayerCacheManager mgr = (LayerCacheManager)ctor.newInstance(cacheDir); 121 err.fine("Using cache manager of type " + managerName + " in " + cacheDir); 122 return mgr; 123 } catch (Exception e) { 124 throw (IOException ) new IOException (e.toString()).initCause(e); 125 } 126 } else { 127 err.fine("No cache manager"); 128 return LayerCacheManager.emptyManager(); 129 } 130 } 131 132 private static FileSystem loadCache(LayerCacheManager mgr) throws IOException { 133 if (mgr.cacheExists()) { 134 setStatusText( 136 NbBundle.getMessage(ModuleLayeredFileSystem.class, "MSG_start_load_cache")); 137 String msg = "Loading layers from " + mgr.getCacheDirectory(); StartLog.logStart(msg); 139 FileSystem fs; 140 try { 141 fs = mgr.createLoadedFileSystem(); 142 } catch (IOException ioe) { 143 err.log(Level.WARNING, null, ioe); 144 mgr.cleanupCache(); 145 cleanStamp(mgr.getCacheDirectory()); 146 fs = mgr.createEmptyFileSystem(); 147 } 148 setStatusText( 149 NbBundle.getMessage(ModuleLayeredFileSystem.class, "MSG_end_load_cache")); 150 StartLog.logEnd(msg); 151 return fs; 152 } else { 153 return mgr.createEmptyFileSystem(); 154 } 155 } 156 157 private static FileSystem[] appendLayers(FileSystem fs1, FileSystem[] fs2s, FileSystem fs3) { 158 List <FileSystem> l = new ArrayList <FileSystem>(fs2s.length + 2); 159 l.add(fs1); 160 l.addAll(Arrays.asList(fs2s)); 161 l.add(fs3); 162 return l.toArray(new FileSystem[l.size()]); 163 } 164 165 private static void cleanStamp(File cacheDir) throws IOException { 166 File stampFile = new File (cacheDir, LAYER_STAMP); 167 if (stampFile.exists() && ! stampFile.delete()) { 168 throw new IOException ("Could not delete: " + stampFile); } 170 } 171 172 175 public final FileSystem[] getLayers () { 176 return getDelegates (); 177 } 178 179 182 final FileSystem getWritableLayer () { 183 return writableLayer; 184 } 185 186 190 public static ModuleLayeredFileSystem getInstallationModuleLayer () { 191 FileSystem fs = Repository.getDefault ().getDefaultFileSystem(); 192 SystemFileSystem sfs = (SystemFileSystem)fs; 193 ModuleLayeredFileSystem home = sfs.getInstallationLayer (); 194 if (home != null) 195 return home; 196 else 197 return sfs.getUserLayer (); 198 } 199 200 204 public static ModuleLayeredFileSystem getUserModuleLayer () { 205 SystemFileSystem sfs = (SystemFileSystem) 206 Repository.getDefault().getDefaultFileSystem(); 207 return sfs.getUserLayer (); 208 } 209 210 213 public void setURLs (final List <URL > urls) throws Exception { 214 if (urls.contains(null)) throw new NullPointerException ("urls=" + urls); if (err.isLoggable(Level.FINE)) { 216 err.fine("setURLs: " + urls); 217 } 218 if (this.urls != null && urls.equals(this.urls)) { 219 err.fine("no-op"); 220 return; 221 } 222 223 StartLog.logStart("setURLs"); 225 final File stampFile; 226 final Stamp stamp; 227 final File cacheDir = manager.getCacheDirectory(); 228 if (cacheDir != null) { 229 stampFile = new File (cacheDir, LAYER_STAMP); 230 stamp = new Stamp(manager.getClass().getName(), urls); 231 } else { 232 stampFile = null; 233 stamp = null; 234 } 235 if (cacheDir != null && stampFile.isFile()) { 236 err.fine("Stamp of new URLs: " + stamp.getHash()); 237 BufferedReader r = new BufferedReader (new InputStreamReader (new FileInputStream (stampFile), "UTF-8")); try { 239 String line = r.readLine(); 240 long hash; 241 try { 242 hash = Long.parseLong(line); 243 } catch (NumberFormatException nfe) { 244 throw new IOException (nfe.toString()); 245 } 246 err.fine("Stamp in the cache: " + hash); 247 if (hash == stamp.getHash()) { 248 err.fine("Cache hit!"); 249 this.urls = urls; 250 StartLog.logEnd("setURLs"); return; 252 } 253 } finally { 254 r.close(); 255 } 256 } 257 258 runAtomicAction(new AtomicAction() { 260 public void run() throws IOException { 261 synchronized (ModuleLayeredFileSystem.this) { 262 if (cacheDir != null) { 263 setStatusText( 264 NbBundle.getMessage(ModuleLayeredFileSystem.class, "MSG_start_rewrite_cache")); 265 err.fine("Rewriting cache in " + cacheDir); 266 } try { 268 if (manager.supportsLoad()) { 269 manager.store(cacheLayer, urls); 270 } else { 271 cacheLayer = manager.store(urls); 272 setDelegates(appendLayers(writableLayer, otherLayers, cacheLayer)); 273 } 274 } catch (IOException ioe) { 275 err.log(Level.WARNING, null, ioe); 276 err.fine("Abandoning cache manager"); 277 manager.cleanupCache(); 278 cleanStamp(cacheDir); 279 manager = LayerCacheManager.emptyManager(); 280 try { 282 if (manager.supportsLoad()) { 283 cacheLayer = manager.createEmptyFileSystem(); 284 manager.store(cacheLayer, urls); 285 } else { 286 cacheLayer = manager.store(urls); 287 } 288 setDelegates(appendLayers(writableLayer, otherLayers, cacheLayer)); 289 } catch (IOException ioe2) { 290 err.log(Level.WARNING, null, ioe2); 292 } 293 return; 294 } 295 if (stampFile != null) { 296 Writer wr = new OutputStreamWriter (new FileOutputStream (stampFile), "UTF-8"); try { 299 wr.write(Long.toString(stamp.getHash())); 304 wr.write("\nLine above is identifying hash key, do not edit!\nBelow is metadata about layer cache, for debugging purposes.\n"); wr.write(stamp.toString()); 306 } finally { 307 wr.close(); 308 } 309 } 310 if (cacheDir != null) { 311 setStatusText( 312 NbBundle.getMessage(ModuleLayeredFileSystem.class, "MSG_end_rewrite_cache")); 313 err.fine("Finished rewriting cache in " + cacheDir); 314 } 315 } 316 } 317 }); 318 319 this.urls = urls; 320 firePropertyChange ("layers", null, null); 322 StartLog.logEnd("setURLs"); } 324 325 327 public void addURLs(Collection <URL > urls) throws Exception { 328 if (urls.contains(null)) throw new NullPointerException ("urls=" + urls); ArrayList <URL > arr = new ArrayList <URL >(urls); 331 if (this.urls != null) arr.addAll(this.urls); 332 setURLs(arr); 333 } 334 335 337 public void removeURLs(Collection <URL > urls) throws Exception { 338 if (urls.contains(null)) throw new NullPointerException ("urls=" + urls); ArrayList <URL > arr = new ArrayList <URL >(); 340 if (this.urls != null) arr.addAll(this.urls); 341 arr.removeAll(urls); 342 setURLs(arr); 343 } 344 345 347 private static final class Stamp implements Comparator <URL > { 348 private final String managerName; 349 private final List <URL > urls; 350 private final long[] times; 351 private final long hash; 352 public Stamp(String name, List <URL > urls) throws IOException { 353 managerName = name; 354 this.urls = new ArrayList <URL >(urls); 355 Collections.sort(this.urls, this); 356 times = new long[this.urls.size()]; 357 long x = 17L ^ managerName.hashCode(); 358 Iterator it = this.urls.iterator(); 359 int i = 0; 360 while (it.hasNext()) { 361 URL u = (URL )it.next(); 362 String s = u.toExternalForm(); 363 x += 3199876987199633L; 364 x ^= s.hashCode(); 365 URL u2; 366 if (s.startsWith("jar:")) { int bangSlash = s.lastIndexOf("!/"); if (bangSlash != -1) { 369 u2 = new URL (s.substring(4, bangSlash)); 371 } else { 372 err.warning("Weird JAR URL: " + u); 373 u2 = u; 374 } 375 } else { 376 u2 = u; 378 } 379 File extracted = new File (URI.create(u2.toExternalForm())); 380 if (extracted != null) { 381 x ^= (times[i++] = extracted.lastModified()); 383 } else { 384 times[i++] = 0L; 386 } 387 } 388 hash = x; 389 } 390 public long getHash() { 391 return hash; 392 } 393 public String toString() { 394 StringBuilder buf = new StringBuilder (); 395 buf.append(managerName); 396 buf.append('\n'); 397 Iterator <URL > it = urls.iterator(); 398 int i = 0; 399 while (it.hasNext()) { 400 long t = times[i++]; 401 if (t == 0L) { 402 buf.append("<file not found>"); } else { 404 buf.append(new Date (t)); 405 } 406 buf.append('\t').append(it.next()).append('\n'); 407 } 408 return buf.toString(); 409 } 410 public int compare(URL o1, URL o2) { 411 return o1.toString().compareTo(o2.toString()); 412 } 413 } 414 private static void setStatusText (String msg) { 415 org.netbeans.core.startup.Main.setStatusText(msg); 416 } 417 418 } 419 | Popular Tags |