1 19 20 package org.netbeans.core; 21 22 import java.io.BufferedInputStream ; 23 import java.io.BufferedOutputStream ; 24 import java.io.BufferedReader ; 25 import java.io.File ; 26 import java.io.FileInputStream ; 27 import java.io.FileOutputStream ; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.InputStreamReader ; 31 import java.io.ObjectInputStream ; 32 import java.io.ObjectOutputStream ; 33 import java.io.OutputStream ; 34 import java.io.OutputStreamWriter ; 35 import java.io.Writer ; 36 import java.net.URI ; 37 import java.net.URISyntaxException ; 38 import java.net.URL ; 39 import java.util.ArrayList ; 40 import java.util.Collections ; 41 import java.util.Date ; 42 import java.util.Iterator ; 43 import java.util.List ; 44 import java.util.Locale ; 45 import java.util.StringTokenizer ; 46 import java.util.logging.Level ; 47 import java.util.logging.Logger ; 48 import org.openide.filesystems.FileObject; 49 import org.openide.filesystems.Repository; 50 import org.openide.loaders.DataFolder; 51 import org.openide.loaders.FolderLookup; 52 import org.openide.util.Lookup; 53 import org.openide.util.io.NbObjectInputStream; 54 import org.openide.util.io.NbObjectOutputStream; 55 import org.netbeans.Module; 56 import org.netbeans.ModuleManager; 57 import org.netbeans.core.startup.StartLog; 58 59 72 class LookupCache { 73 74 75 private static final boolean ENABLED = Boolean.valueOf(System.getProperty("netbeans.cache.lookup", "true")).booleanValue(); 77 78 private static final Logger err = Logger.getLogger("org.netbeans.core.LookupCache"); 80 85 public static Lookup load() { 86 err.fine("enabled=" + ENABLED); 87 if (ENABLED && cacheHit()) { 88 try { 89 return loadCache(); 90 } catch (Exception e) { 91 Logger.getLogger(LookupCache.class.getName()).log(Level.INFO, null, e); 92 } 93 } 94 return loadDirect(); 95 } 96 97 101 private static Lookup loadDirect() { 102 FileObject services = Repository.getDefault().getDefaultFileSystem().findResource("Services"); if (services != null) { 104 StartLog.logProgress("Got Services folder"); DataFolder servicesF; 106 try { 107 servicesF = DataFolder.findFolder(services); 108 } catch (RuntimeException e) { 109 Logger.getLogger(LookupCache.class.getName()).log(Level.INFO, null, e); 110 return Lookup.EMPTY; 111 } 112 FolderLookup f = new FolderLookup(servicesF, "SL["); StartLog.logProgress("created FolderLookup"); err.fine("loadDirect from Services"); 115 return f.getLookup(); 116 } else { 117 err.fine("loadDirect, but no Services"); 118 return Lookup.EMPTY; 119 } 120 } 121 122 129 private static boolean cacheHit() { 130 File f = cacheFile(); 131 if (f == null || !f.exists()) { 132 err.fine("no cache file"); 133 return false; 134 } 135 File stampFile = stampFile(); 136 if (stampFile == null || !stampFile.exists()) { 137 err.fine("no stamp file"); 138 return false; 139 } 140 StartLog.logStart("check for lookup cache hit"); List <File > files = relevantFiles(); 142 if (err.isLoggable(Level.FINE)) { 143 err.fine("checking against " + stampFile + " for files " + files); 144 } 145 boolean hit; 146 try { 147 Stamp stamp = new Stamp(files); 148 long newHash = stamp.getHash(); 149 BufferedReader r = new BufferedReader (new InputStreamReader (new FileInputStream (stampFile), "UTF-8")); try { 151 String line = r.readLine(); 152 long oldHash; 153 try { 154 oldHash = Long.parseLong(line); 155 } catch (NumberFormatException nfe) { 156 throw new IOException (nfe.toString()); 157 } 158 if (oldHash == newHash) { 159 err.fine("Cache hit! with hash " + oldHash); 160 hit = true; 161 } else { 162 err.fine("Cache miss, " + oldHash + " -> " + newHash); 163 hit = false; 164 } 165 } finally { 166 r.close(); 167 } 168 } catch (IOException ioe) { 169 Logger.getLogger(LookupCache.class.getName()).log(Level.INFO, null, ioe); 170 hit = false; 171 } 172 StartLog.logEnd("check for lookup cache hit"); return hit; 174 } 175 176 179 private static File cacheFile() { 180 String ud = System.getProperty("netbeans.user"); 181 if ((ud != null) && (! "memory".equals(ud))) { 182 File cachedir = new File (new File (ud, "var"), "cache"); cachedir.mkdirs(); 184 return new File (cachedir, "folder-lookup.ser"); } else { 186 return null; 187 } 188 } 189 190 194 private static File stampFile() { 195 String ud = System.getProperty("netbeans.user"); 196 if ((ud != null) && (! "memory".equals(ud))) { 197 File cachedir = new File (new File (ud, "var"), "cache"); cachedir.mkdirs(); 199 return new File (cachedir, "lookup-stamp.txt"); } else { 201 return null; 202 } 203 } 204 205 217 private static List <File > relevantFiles() { 218 final List <File > files = new ArrayList <File >(250); 219 final ModuleManager mgr = org.netbeans.core.startup.Main.getModuleSystem().getManager(); 220 mgr.mutex().readAccess(new Runnable () { 221 222 public void run() { 223 Iterator <Module> it = mgr.getEnabledModules().iterator(); 224 225 while (it.hasNext()) { 226 Module m = it.next(); 227 String layer = (String ) m.getAttribute("OpenIDE-Module-Layer"); 228 229 if (layer != null) { 230 if (m.getJarFile() != null) { 231 files.add(m.getJarFile()); 232 } else { 233 URL layerURL = m.getClassLoader().getResource(layer); 234 235 if (layerURL != null) { 236 String s = layerURL.toExternalForm(); 237 238 if (s.startsWith("jar:")) { 239 int bangSlash = s.lastIndexOf("!/"); 240 241 if (bangSlash != -1) { 242 try { 244 URI layerJarURL = new URI (s.substring(4, 245 bangSlash)); 246 247 if ("file".equals(layerJarURL.getScheme())) { 248 files.add(new File (layerJarURL)); 249 } else { 250 err.warning( 251 "Weird jar: URL: " + 252 layerJarURL); 253 } 254 } 255 catch (URISyntaxException e) { 256 Logger.getLogger(LookupCache.class.getName()).log(Level.WARNING, 257 null, 258 e); 259 } 260 } else { 261 err.warning( 262 "Malformed jar: URL: " + 263 s); 264 } 265 } else { 266 err.warning( 267 "Not a jar: URL: " + 268 s); 269 } 270 } else { 271 err.warning( 272 "Could not find " + 273 layer + " in " + 274 m); 275 } 276 } 277 } 278 } 279 } 280 }); 281 relevantFilesFromInst(files, System.getProperty("netbeans.home")); relevantFilesFromInst(files, System.getProperty("netbeans.user")); String nbdirs = System.getProperty("netbeans.dirs"); if (nbdirs != null) { 285 StringTokenizer tok = new StringTokenizer (nbdirs, File.pathSeparator); 287 while (tok.hasMoreTokens()) { 288 relevantFilesFromInst(files, tok.nextToken()); 289 } 290 } 291 return files; 292 } 293 296 private static void relevantFilesFromInst(List <File > files, String instDir) { 297 if (instDir == null) { 298 return; 299 } 300 relevantFilesFrom(files, new File (new File (new File (instDir), "system"), "Services")); } 302 305 private static void relevantFilesFrom(List <File > files, File dir) { 306 File [] kids = dir.listFiles(); 307 if (kids != null) { 308 for (int i = 0; i < kids.length; i++) { 309 File f = kids[i]; 310 if (f.isFile()) { 311 files.add(f); 312 } else { 313 relevantFilesFrom(files, f); 314 } 315 } 316 } 317 } 318 319 322 private static Lookup loadCache() throws Exception { 323 StartLog.logStart("load lookup cache"); 324 File f = cacheFile(); 325 err.fine("loading from " + f); 326 InputStream is = new FileInputStream (f); 327 try { 328 ObjectInputStream ois = new NbObjectInputStream(new BufferedInputStream (is)); 329 Lookup l = (Lookup)ois.readObject(); 330 StartLog.logEnd("load lookup cache"); 331 return l; 332 } finally { 333 is.close(); 334 } 335 } 336 337 343 public static void store(Lookup l) throws IOException { 344 if (!ENABLED) { 345 return; 346 } 347 File f = cacheFile(); 348 if (f == null) { 349 return; 350 } 351 File stampFile = stampFile(); 352 if (stampFile == null) { 353 return; 354 } 355 StartLog.logStart("store lookup cache"); 356 err.fine("storing to " + f + " with stamp in " + stampFile); 357 OutputStream os = new FileOutputStream (f); 358 try { 359 try { 360 ObjectOutputStream oos = new NbObjectOutputStream(new BufferedOutputStream (os)); 361 oos.writeObject(l); 362 oos.flush(); 363 } finally { 364 os.close(); 365 } 366 Stamp stamp = new Stamp(relevantFiles()); 367 Writer wr = new OutputStreamWriter (new FileOutputStream (stampFile), "UTF-8"); try { 369 wr.write(Long.toString(stamp.getHash())); 374 wr.write("\nLine above is identifying hash key, do not edit!\nBelow is metadata about folder lookup cache, for debugging purposes.\n"); wr.write(stamp.toString()); 376 } finally { 377 wr.close(); 378 } 379 StartLog.logEnd("store lookup cache"); 380 } catch (IOException ioe) { 381 if (f.exists()) { 383 f.delete(); 384 } 385 if (stampFile.exists()) { 386 stampFile.delete(); 387 } 388 throw ioe; 389 } 390 } 391 392 405 private static final class Stamp { 406 private final List <File > files; 407 private final long[] times; 408 private final long hash; 409 410 public Stamp(List <File > files) throws IOException { 411 this.files = new ArrayList <File >(files); 412 Collections.sort(this.files); 413 times = new long[this.files.size()]; 414 long x = 17L; 415 Iterator <File > it = this.files.iterator(); 416 int i = 0; 417 while (it.hasNext()) { 418 File f = it.next(); 419 x ^= f.hashCode(); 420 x += 98679245L; 421 long m; 422 String name = f.getName().toLowerCase(Locale.US); 423 if (name.endsWith(".jar") || ".nbattrs".equals(name)) { m = f.lastModified(); 425 } else { 426 m = 0L; 427 } 428 x ^= (times[i++] = m); 429 } 430 hash = x; 431 } 432 433 public long getHash() { 434 return hash; 435 } 436 437 public String toString() { 438 StringBuilder buf = new StringBuilder (); 439 Iterator <File > it = files.iterator(); 440 int i = 0; 441 while (it.hasNext()) { 442 long t = times[i++]; 443 if (t != 0L) { 444 buf.append(new Date (t)); 445 } else { 446 buf.append("<ignoring file contents>"); } 448 buf.append('\t'); 449 buf.append(it.next()); 450 buf.append('\n'); 451 } 452 return buf.toString(); 453 } 454 } 455 456 } 457 | Popular Tags |