1 19 package org.netbeans.modules.turbo; 20 21 import org.openide.util.Lookup; 22 import org.openide.util.RequestProcessor; 23 import org.openide.ErrorManager; 24 25 import java.util.*; 26 import java.lang.ref.WeakReference ; 27 28 66 public final class Turbo { 67 68 69 private static Lookup.Result providers; 70 71 72 private final CustomProviders customProviders; 73 74 private static WeakReference defaultInstance; 75 76 private List listeners = new ArrayList(100); 77 78 79 private final Memory memory; 80 81 private final Statistics statistics; 82 83 private static Environment env; 84 85 90 public static synchronized Turbo getDefault() { 91 Turbo turbo = null; 92 if (defaultInstance != null) { 93 turbo = (Turbo) defaultInstance.get(); 94 } 95 96 if (turbo == null) { 97 turbo = new Turbo(null, 47, -1); 98 defaultInstance = new WeakReference (turbo); 99 } 100 101 return turbo; 102 } 103 104 111 public static synchronized Turbo createCustom(CustomProviders providers, int min, int max) { 112 return new Turbo(providers, min, max); 113 } 114 115 private Turbo(CustomProviders customProviders, int min, int max) { 116 statistics = Statistics.createInstance(); 117 memory = new Memory(statistics, min, max); 118 this.customProviders = customProviders; 119 if (customProviders == null && providers == null) { 120 Lookup.Template t = new Lookup.Template(TurboProvider.class); 121 synchronized(Turbo.class) { 122 if (env == null) env = new Environment(); 123 } 124 providers = env.getLookup().lookup(t); 125 } 126 } 127 128 129 static synchronized void initEnvironment(Environment environment) { 130 assert env == null; 131 env = environment; 132 providers = null; 133 } 134 135 136 protected void finalize() throws Throwable { 137 super.finalize(); 138 statistics.shutdown(); 139 } 140 141 147 public Object readEntry(Object key, String name) { 148 149 statistics.attributeRequest(); 150 151 153 if (memory.existsEntry(key, name)) { 154 Object value = memory.get(key, name); 155 statistics.memoryHit(); 156 return value; 157 } 158 159 List speculative = new ArrayList(57); 161 Object value = loadEntry(key, name, speculative); 162 memory.put(key, name, value != null ? value : Memory.NULL); 163 166 Iterator it = speculative.iterator(); 169 while (it.hasNext()) { 170 Object [] next = (Object []) it.next(); 171 Object sKey = next[0]; 172 String sName = (String ) next[1]; 173 Object sValue = next[2]; 174 assert sKey != null; 175 assert sName != null; 176 fireEntryChange(sKey, sName, sValue); 177 } 178 179 return value; 180 } 181 182 private Iterator providers() { 183 if (customProviders == null) { 184 Collection plugins = providers.allInstances(); 185 List all = new ArrayList(plugins.size() +1); 186 all.addAll(plugins); 187 all.add(DefaultTurboProvider.getDefault()); 188 return all.iterator(); 189 } else { 190 return customProviders.providers(); 191 } 192 } 193 194 197 private Object loadEntry(Object key, String name, List speculative) { 198 199 TurboProvider provider; 200 Iterator it = providers(); 201 while (it.hasNext()) { 202 provider = (TurboProvider) it.next(); 203 try { 204 if (provider.recognizesAttribute(name) && provider.recognizesEntity(key)) { 205 TurboProvider.MemoryCache cache = TurboProvider.MemoryCache.createDefault(memory, speculative); 206 Object value = provider.readEntry(key, name, cache); 207 statistics.providerHit(); 208 return value; 209 } 210 } catch (ThreadDeath td) { 211 throw td; 212 } catch (Throwable t) { 213 ErrorManager.getDefault().annotate(t, "Error in provider " + provider + ", skipping... "); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); } 217 } 218 219 return null; 220 } 221 222 255 public boolean writeEntry(Object key, String name, Object value) { 256 257 if (value != null) { 258 Object oldValue = memory.get(key, name); 259 if (oldValue != null && oldValue.equals(value)) return true; } 261 262 int result = storeEntry(key, name, value); 263 if (result >= 0) { 264 memory.put(key, name, value); 266 fireEntryChange(key, name, value); 267 return true; 268 } else { 269 return false; 270 } 271 } 272 273 277 int storeEntry(Object key, String name, Object value) { 278 TurboProvider provider; 279 Iterator it = providers(); 280 while (it.hasNext()) { 281 provider = (TurboProvider) it.next(); 282 try { 283 if (provider.recognizesAttribute(name) && provider.recognizesEntity(key)) { 284 if (provider.writeEntry(key, name, value)) { 285 return 0; 286 } else { 287 IllegalArgumentException ex = new IllegalArgumentException ("Attribute[" + name + "] value rejected by " + provider); 289 ErrorManager.getDefault().notify(ErrorManager.WARNING, ex); 290 return -1; 291 } 292 } 293 } catch (ThreadDeath td) { 294 throw td; 295 } catch (Throwable t) { 296 ErrorManager.getDefault().annotate(t, "Error in provider " + provider + ", skipping... "); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 299 } 300 } 301 return 1; 302 } 303 304 320 public boolean prepareEntry(Object key, String name) { 321 322 statistics.attributeRequest(); 323 324 326 if (memory.existsEntry(key, name)) { 327 statistics.memoryHit(); 328 return true; 329 } 330 331 scheduleLoad(key, name); 333 return false; 334 } 335 336 350 public boolean isPrepared(Object key, String name) { 351 return memory.existsEntry(key, name); 352 } 353 354 363 public Object getMonitoredKey(Object key) { 364 return memory.getMonitoredKey(key); 365 } 366 367 public void addTurboListener(TurboListener l) { 368 synchronized(listeners) { 369 List copy = new ArrayList(listeners); 370 copy.add(l); 371 listeners = copy; 372 } 373 } 374 375 public void removeTurboListener(TurboListener l) { 376 synchronized(listeners) { 377 List copy = new ArrayList(listeners); 378 copy.remove(l); 379 listeners = copy; 380 } 381 382 } 383 384 protected void fireEntryChange(Object key, String name, Object value) { 385 Iterator it = listeners.iterator(); 386 while (it.hasNext()) { 387 TurboListener next = (TurboListener) it.next(); 388 next.entryChanged(key, name, value); 389 } 390 } 391 392 393 public String toString() { 394 StringBuffer sb = new StringBuffer ("Turbo delegating to:"); Iterator it = providers(); 396 while (it.hasNext()) { 397 TurboProvider provider = (TurboProvider) it.next(); 398 sb.append(" [" + provider + "]"); } 400 return sb.toString(); 401 } 402 403 404 static class Environment { 405 406 public Lookup getLookup() { 407 return Lookup.getDefault(); 408 } 409 } 410 411 413 414 415 private final Set prepareRequests = Collections.synchronizedSet(new LinkedHashSet(27)); 416 417 private static PreparationTask preparationTask; 418 419 420 private void scheduleLoad(Object key, String name) { 421 synchronized(prepareRequests) { 422 if (preparationTask == null) { 423 preparationTask = new PreparationTask(prepareRequests); 424 RequestProcessor.getDefault().post(preparationTask); 425 statistics.backgroundThread(); 426 } 427 preparationTask.notifyNewRequest(new Request(key, name)); 428 } 429 } 430 431 432 private final static class Request { 433 private final Object key; 434 private final String name; 435 436 public Request(Object key, String name) { 437 this.name = name; 438 this.key = key; 439 } 440 441 public boolean equals(Object o) { 442 if (this == o) return true; 443 if (!(o instanceof Request)) return false; 444 445 final Request request = (Request) o; 446 447 if (name != null ? !name.equals(request.name) : request.name != null) return false; 448 if (key != null ? !key.equals(request.key) : request.key != null) return false; 449 450 return true; 451 } 452 453 public int hashCode() { 454 int result; 455 result = (key != null ? key.hashCode() : 0); 456 result = 29 * result + (name != null ? name.hashCode() : 0); 457 return result; 458 } 459 460 public String toString() { 461 return "Request[key=" + key + ", attr=" + name + "]"; 462 } 463 } 464 465 468 private final class PreparationTask implements Runnable { 469 470 private final Set requests; 471 472 private static final int INACTIVITY_TIMEOUT = 123 * 1000; 474 public PreparationTask(Set requests) { 475 this.requests = requests; 476 } 477 478 public void run() { 479 try { 480 Thread.currentThread().setName("Turbo Async Fetcher"); while (waitForRequests()) { 482 Request request; 483 synchronized (requests) { 484 request = (Request) requests.iterator().next(); 485 requests.remove(request); 486 } 487 Object key = request.key; 488 String name = request.name; 489 Object value; 490 boolean fire; 491 if (memory.existsEntry(key, name)) { 492 493 synchronized(Memory.class) { 494 fire = memory.existsEntry(key, name) == false; 495 value = memory.get(key, name); 496 } 497 if (fire) { 498 statistics.providerHit(); } 500 } else { 501 value = loadEntry(key, name, null); 502 synchronized(Memory.class) { 504 fire = memory.existsEntry(key, name) == false; 505 Object oldValue = memory.get(key, name); 506 memory.put(key, name, value != null ? value : Memory.NULL); 507 fire |= (oldValue != null && !oldValue.equals(value)) 508 || (oldValue == null && value != null); 509 } 510 } 511 512 fireEntryChange(key, name, value); 519 } 520 } catch (InterruptedException ex) { 521 synchronized(requests) { 522 requests.clear(); 524 } 525 } finally { 526 synchronized(requests) { 527 preparationTask = null; 528 } 529 } 530 } 531 532 536 private boolean waitForRequests() throws InterruptedException { 537 synchronized(requests) { 538 if (requests.size() == 0) { 539 requests.wait(INACTIVITY_TIMEOUT); 540 } 541 return requests.size() > 0; 542 } 543 } 544 545 public void notifyNewRequest(Request request) { 546 synchronized(requests) { 547 if (requests.add(request)) { 548 statistics.queueSize(requests.size()); 549 requests.notify(); 550 } else { 551 statistics.duplicate(); 552 statistics.providerHit(); 553 } 554 } 555 } 556 557 public String toString() { 558 return "Turbo.PreparationTask queue=[" + requests +"]"; } 560 } 561 562 563 } 564 | Popular Tags |