1 19 20 package org.openide.loaders; 21 22 23 import java.io.*; 24 import java.lang.ref.Reference ; 25 import java.lang.ref.WeakReference ; 26 import java.util.*; 27 import java.util.logging.*; 28 import org.openide.cookies.InstanceCookie; 29 import org.openide.filesystems.FileObject; 30 import org.openide.util.*; 31 import org.openide.util.lookup.*; 32 33 42 public class FolderLookup extends FolderInstance { 43 44 45 private static final Object LOCK = new Object (); 46 47 48 private ProxyLkp lookup; 49 50 51 private String rootName; 52 53 55 private final boolean isRoot; 56 57 58 63 public FolderLookup (DataObject.Container df) { 64 this (df, "FL["); } 66 67 71 public FolderLookup (DataObject.Container df, String prefix) { 72 this(df, prefix, true); 73 } 74 75 81 private FolderLookup(DataObject.Container df, String prefix, boolean isRoot) { 82 super(df); 83 84 this.rootName = prefix; 85 this.isRoot = isRoot; 86 } 87 88 89 91 public final Class <?> instanceClass () { 92 return ProxyLkp.class; 93 } 94 95 100 public final Lookup getLookup () { 101 boolean inited = false; 102 synchronized(LOCK) { 103 if(lookup == null) { 104 lookup = new ProxyLkp(this); 105 inited = true; 106 } 107 } 108 109 if(inited) { 110 checkRecreate(); 111 } 112 113 return lookup; 114 } 115 116 123 protected final Object createInstance(InstanceCookie[] cookies) 124 throws IOException, ClassNotFoundException { 125 FolderLookupData flData = new FolderLookupData(); 126 127 if(isRoot) { 130 flData.lookups.add(null); 131 } 132 133 for (int i = 0; i < cookies.length; i++) { 134 try { 135 Object obj = cookies[i].instanceCreate (); 137 138 if(obj instanceof FolderLookupData) { 139 flData.items.addAll(((FolderLookupData)obj).items); 141 flData.lookups.addAll(((FolderLookupData)obj).lookups); 142 } else if(obj instanceof Lookup) { 143 flData.lookups.add((Lookup)obj); 144 } else { 145 flData.items.add((ICItem)obj); 147 } 148 } catch(IOException ex) { 149 exception(ex); 150 } catch(ClassNotFoundException ex) { 151 exception(ex); 152 } 153 } 154 155 if(!isRoot) { 158 return flData; 159 } 160 161 163 getLookup(); 165 166 lookup.update(flData.items, flData.lookups); 167 168 return lookup; 169 } 170 171 180 protected Object instanceForCookie(DataObject dobj, InstanceCookie cookie) 181 throws IOException, ClassNotFoundException { 182 boolean isLookup; 183 184 if(cookie instanceof InstanceCookie.Of) { 185 isLookup = ((InstanceCookie.Of)cookie).instanceOf(Lookup.class); 186 } else { 187 isLookup = Lookup.class.isAssignableFrom(cookie.instanceClass ()); 188 } 189 190 if(isLookup) { 191 return cookie.instanceCreate(); 193 } else { 194 return new ICItem(dobj, rootName, cookie); 195 } 196 } 197 198 203 protected InstanceCookie acceptFolder (DataFolder df) { 204 return new FolderLookup(df, objectName(rootName, df), false); 205 } 206 207 212 protected InstanceCookie acceptContainer (DataObject.Container df) { 213 return new FolderLookup( 214 df, 215 rootName == null ? "<container>" : rootName + "<container>", false 217 ); 218 } 219 220 221 229 protected final Task postCreationTask (Runnable run) { 230 run.run (); 231 return null; 232 } 233 234 239 private static String objectName (String name, DataObject obj) { 240 if (name == null) { 241 return obj.getName (); 242 } else { 243 return name + '/' + obj.getName (); 244 } 245 } 246 247 248 private static void exception (Exception e) { 249 Logger.getLogger(FolderLookup.class.getName()).log(Level.WARNING, null, e); 250 } 251 private static void exception(Exception e, FileObject fo) { 252 Exceptions.attachMessage(e, "Bad file: " + fo); exception(e); 254 } 255 256 257 258 static final class ProxyLkp extends ProxyLookup implements Serializable { 259 260 private static final long serialVersionUID = 1L; 261 262 263 private transient FolderLookup fl; 264 265 266 private transient AbstractLookup.Content content; 267 268 private transient boolean readFromStream; 269 270 272 public ProxyLkp(FolderLookup folder) { 273 this(folder, new AbstractLookup.Content()); 274 } 275 276 277 private ProxyLkp(FolderLookup folder, AbstractLookup.Content content) { 278 super(new Lookup[] {new AbstractLookup(content)}); 279 280 this.fl = folder; 281 this.content = content; 282 } 283 284 public String toString() { 285 return "FolderLookup.lookup[\"" + fl.rootName + "\"]"; 286 } 287 288 private void writeObject (ObjectOutputStream oos) throws IOException { 289 Lookup[] ls = getLookups(); 290 for (int i = 0; i < ls.length; i++) { 291 oos.writeObject(ls[i]); 292 } 293 oos.writeObject(null); 294 oos.writeObject (fl.folder); 295 oos.writeObject (fl.rootName); 296 oos.writeObject (content); 297 } 298 299 private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { 300 List<Lookup> ls = new ArrayList<Lookup>(); 301 Lookup l; 302 while ((l = (Lookup)ois.readObject()) != null) { 303 ls.add(l); 304 } 305 Lookup[] arr = ls.toArray(new Lookup[ls.size()]); 306 DataFolder df = (DataFolder)ois.readObject (); 307 String root = (String )ois.readObject (); 308 309 fl = new FolderLookup (df, root, true); 310 fl.lookup = this; 311 312 content = (AbstractLookup.Content)ois.readObject (); 313 314 setLookups (arr); 315 316 readFromStream = true; 317 org.openide.util.RequestProcessor.getDefault ().post (fl, 0, Thread.MIN_PRIORITY); 318 } 319 320 321 325 public void update(Collection<ICItem> items, List<Lookup> lookups) { 326 readFromStream = false; 327 328 Lookup pairs = getLookups ()[0]; 330 331 content.setPairs (items); 333 if (fl.err().isLoggable(Level.FINE)) fl.err ().fine("Changed pairs: " + items); 335 lookups.set(0, pairs); 336 337 Lookup[] arr = (Lookup[])lookups.toArray (new Lookup[lookups.size ()]); 338 setLookups (arr); 339 if (fl.err().isLoggable(Level.FINE)) fl.err ().fine("Changed lookups: " + lookups); } 341 342 343 protected void beforeLookup (Template template) { 344 if (readFromStream) { 345 return; 347 } 348 349 if ( 351 !FolderList.isFolderRecognizerThread() && 352 ICItem.DANGEROUS.get() == null 353 ) { 354 if (!DataObjectPool.isConstructorAllowed()) { 355 fl.waitFinished(); 356 } else { 357 try { 358 while (!fl.waitFinished(10000)) { 360 long blocked = DataObjectPool.getPOOL().timeInWaitNotified(); 361 if (blocked > 10000L) { 362 fl.err().log(Level.INFO, "Preventing deadlock #65543: Do not call FolderLookup from inside DataObject operations!", new Exception ("Thread dump")); return; 367 } 368 } 369 } catch (InterruptedException ex) { 370 fl.err().log(Level.WARNING, null, ex); 371 } 372 } 373 } 374 } 375 376 379 public void waitFinished () { 380 fl.waitFinished (); 381 } 382 383 } 385 386 388 private static final class ICItem extends AbstractLookup.Pair { 389 static final long serialVersionUID = 10L; 390 391 static final ThreadLocal <ICItem> DANGEROUS = new ThreadLocal <ICItem> (); 392 393 394 private static final Logger ERR = Logger.getLogger(ICItem.class.getName()); 395 396 397 private FileObject fo; 398 399 private transient InstanceCookie ic; 400 401 private transient DataObject obj; 402 403 private transient Reference <Object > ref; 404 405 private String rootName; 406 407 408 public ICItem (DataObject obj, String rootName, InstanceCookie ic) { 409 this.ic = ic; 410 this.obj = obj; 411 this.rootName = rootName; 412 this.fo = obj.getPrimaryFile(); 413 414 if (ERR.isLoggable(Level.FINE)) ERR.fine("New ICItem: " + obj); } 416 417 419 public void init () { 420 if (ic != null) return; 421 422 ICItem prev = DANGEROUS.get (); 423 try { 424 DANGEROUS.set (this); 425 if (obj == null) { 426 try { 427 obj = DataObject.find(fo); 428 } catch (DataObjectNotFoundException donfe) { 429 ic = new BrokenInstance("No DataObject for " + fo.getPath(), donfe); return; 431 } 432 } 433 434 ic = (InstanceCookie)obj.getCookie (InstanceCookie.class); 435 if (ic == null) { 436 ic = new BrokenInstance("No cookie for " + fo.getPath(), null); } 438 } finally { 439 DANGEROUS.set (prev); 440 } 441 } 442 443 448 private static final class BrokenInstance implements InstanceCookie.Of { 449 private final String message; 450 private final Exception ex; 451 public BrokenInstance(String message, Exception ex) { 452 this.message = message; 453 this.ex = ex; 454 } 455 public String instanceName() { 456 return "java.lang.Object"; } 458 private ClassNotFoundException die() { 459 if (ex != null) { 460 return new ClassNotFoundException (message, ex); 461 } else { 462 return new ClassNotFoundException (message); 463 } 464 } 465 public Class instanceClass() throws IOException, ClassNotFoundException { 466 throw die(); 467 } 468 public Object instanceCreate() throws IOException, ClassNotFoundException { 469 throw die(); 470 } 471 public boolean instanceOf(Class type) { 472 return false; 473 } 474 } 475 476 477 480 protected boolean instanceOf (Class clazz) { 481 init (); 482 483 if (ERR.isLoggable(Level.FINE)) ERR.fine("instanceOf: " + clazz.getName() + " obj: " + obj); 485 if (ic instanceof InstanceCookie.Of) { 486 InstanceCookie.Of of = (InstanceCookie.Of)ic; 488 boolean res = of.instanceOf (clazz); 489 if (ERR.isLoggable(Level.FINE)) ERR.fine(" of: " + res); return res; 491 } 492 493 try { 495 boolean res = clazz.isAssignableFrom (ic.instanceClass ()); 496 if (ERR.isLoggable(Level.FINE)) ERR.fine(" plain: " + res); return res; 498 } catch (ClassNotFoundException ex) { 499 exception(ex, fo); 500 } catch (IOException ex) { 501 exception(ex, fo); 502 } 503 return false; 504 } 505 506 509 public Object getInstance() { 510 init (); 511 512 try { 513 Object obj = ic.instanceCreate(); 514 if (ERR.isLoggable(Level.FINE)) ERR.fine(" getInstance: " + obj + " for " + this.obj); ref = new WeakReference <Object > (obj); 516 return obj; 517 } catch (ClassNotFoundException ex) { 518 exception(ex, fo); 519 } catch (IOException ex) { 520 exception(ex, fo); 521 } 522 return null; 523 } 524 525 526 public int hashCode () { 527 init (); 528 529 return System.identityHashCode (ic); 530 } 531 532 533 public boolean equals (Object obj) { 534 if (obj instanceof ICItem) { 535 ICItem i = (ICItem)obj; 536 i.init (); 537 init (); 538 return ic == i.ic; 539 } 540 return false; 541 } 542 543 546 public String getId() { 547 init (); 548 549 if (obj == null) { 550 return "<broken: " + fo.getPath() + ">"; } 553 554 return objectName(rootName, obj); 555 } 556 557 558 public String getDisplayName () { 559 init (); 560 561 if (obj == null) { 562 return "<broken: " + fo.getPath() + ">"; } 565 566 return obj.getNodeDelegate ().getDisplayName (); 567 } 568 569 576 protected boolean creatorOf(Object obj) { 577 Reference w = ref; 578 if (w != null && w.get () == obj) { 579 return true; 580 } 581 if (this.obj instanceof InstanceDataObject) { 582 return ((InstanceDataObject)this.obj).creatorOf (obj); 583 } 584 return false; 585 } 586 587 590 public Class getType() { 591 init (); 592 593 try { 594 return ic.instanceClass (); 595 } catch (IOException ex) { 596 } catch (ClassNotFoundException ex) { 598 } 600 return Object .class; 601 } 602 603 } 605 606 609 private static class FolderLookupData { 610 611 613 private Collection<ICItem> items; 614 615 617 private List<Lookup> lookups; 618 619 620 621 public FolderLookupData() { 622 items = new ArrayList<ICItem>(30); 623 lookups = new ArrayList<Lookup>(5); 624 } 625 626 } } 628 | Popular Tags |