1 19 20 package org.openide.loaders; 21 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeEvent ; 24 import java.io.IOException ; 25 import java.util.*; 26 import java.util.logging.Level ; 27 import java.util.logging.Logger ; 28 29 import org.openide.*; 30 import org.openide.filesystems.*; 31 import org.openide.cookies.InstanceCookie; 32 import org.openide.util.Task; 33 import org.openide.util.TaskListener; 34 import org.openide.util.RequestProcessor; 35 36 76 public abstract class FolderInstance extends Task implements InstanceCookie { 78 79 80 81 82 83 private static final RequestProcessor PROCESSOR = new RequestProcessor ( 84 "Folder Instance Processor" ); 86 87 90 private static final ThreadLocal <Object > CURRENT = new ThreadLocal <Object > (); 91 92 96 private static final ThreadLocal <Object > LAST_CURRENT = new ThreadLocal <Object > (); 97 98 99 100 101 102 105 protected DataFolder folder; 106 107 108 private DataObject.Container container; 109 110 111 private HashMap<FileObject, HoldInstance> map = new HashMap<FileObject, HoldInstance> (17); 112 113 116 private Task[] waitFor; 117 118 123 private Object object = CURRENT; 124 125 126 private Listener listener; 127 128 129 private Logger err; 130 131 132 private Task recognizingTask; 133 134 137 private Task creationTask; 138 139 140 141 142 143 146 public FolderInstance (DataFolder df) { 147 this ((DataObject.Container)df); 148 } 149 150 154 public FolderInstance (DataObject.Container container) { 155 this (container, null); 156 } 157 158 162 private FolderInstance (DataObject.Container container, String logName) { 163 if (container instanceof DataFolder) { 164 folder = (DataFolder)container; 165 if (logName == null) { 166 logName = folder.getPrimaryFile().getPath().replace('/','.'); 167 } 168 container = FolderList.find (folder.getPrimaryFile (), true); 169 } 170 171 listener = new Listener (); 172 173 if (logName == null) { 174 logName = "org.openide.loaders.FolderInstance"; } else { 176 logName = "org.openide.loaders.FolderInstance" + '.' + logName; } 178 179 err = Logger.getLogger(logName); 180 181 this.container = container; 182 container.addPropertyChangeListener ( 183 org.openide.util.WeakListeners.propertyChange (listener, container) 184 ); 185 186 if (err.isLoggable(Level.FINE)) { 187 err.fine("new " + this); } 189 } 190 191 192 193 194 195 198 public String instanceName () { 199 try { 200 return instanceClass ().getName (); 201 } catch (java.io.IOException ex) { 202 return "java.lang.Object"; } catch (ClassNotFoundException ex) { 204 return "java.lang.Object"; } 206 } 207 208 215 public Class <?> instanceClass () 216 throws java.io.IOException , ClassNotFoundException { 217 Object object = this.object; 218 if (object != null) { 219 if (object instanceof java.io.IOException ) { 220 throw (java.io.IOException )object; 221 } 222 if (object instanceof ClassNotFoundException ) { 223 throw (ClassNotFoundException )object; 224 } 225 return object.getClass (); 226 } 227 228 return Object .class; 229 } 230 231 236 public Object instanceCreate () 237 throws java.io.IOException , ClassNotFoundException { 238 Object object = CURRENT.get (); 239 240 if (object == null || LAST_CURRENT.get () != this) { 241 err.fine("do into waitFinished"); waitFinished (); 243 244 object = FolderInstance.this.object; 245 } 246 247 if (err.isLoggable(Level.FINE)) { 248 err.fine("instanceCreate: " + object); } 250 251 if (object instanceof java.io.IOException ) { 252 throw (java.io.IOException )object; 253 } 254 if (object instanceof ClassNotFoundException ) { 255 throw (ClassNotFoundException )object; 256 } 257 258 if (object == CURRENT) { 259 throw new IOException ("Cyclic reference. Somebody is trying to get value from FolderInstance (" + getClass ().getName () + ") from the same thread that is processing the instance"); } 262 263 return object; 264 } 265 266 267 268 269 270 272 public final void instanceFinished () { 273 waitFinished (); 274 } 275 276 277 278 279 280 283 public void waitFinished () { 284 boolean isLog = err.isLoggable(Level.FINE); 285 for (;;) { 286 err.fine("waitProcessingFinished on container"); waitProcessingFinished (container); 288 289 Task originalRecognizing = checkRecognizingStarted (); 290 if (isLog) { 291 err.fine("checkRecognizingStarted: " + originalRecognizing); } 293 originalRecognizing.waitFinished (); 294 295 Task t = creationTask; 296 if (isLog) { 297 err.fine("creationTask: " + creationTask); } 299 if (t != null) { 300 t.waitFinished (); 301 } 302 303 304 Task[] toWait = waitFor; 305 if (isLog) { 306 err.fine("toWait: " + toWait); } 308 if (toWait != null) { 309 for (int i = 0; i < toWait.length; i++) { 310 if (isLog) { 311 err.fine(" wait[" + i + "]: " + toWait[i]); } 313 toWait[i].waitFinished (); 314 } 315 } 316 317 if (originalRecognizing == checkRecognizingStarted ()) { 320 if (isLog) { 321 err.fine("breaking the wait loop"); } 323 break; 324 } 325 326 } 330 } 331 332 333 public void run () { 334 recreate (); 335 instanceFinished (); 336 } 337 338 339 340 341 342 365 protected InstanceCookie acceptDataObject(DataObject dob) { 366 int acceptType = -1; 367 368 InstanceCookie cookie; 369 cookie = (InstanceCookie)dob.getCookie (InstanceCookie.class); 372 try { 373 cookie = cookie == null ? null : acceptCookie (cookie); 374 acceptType = 1; 375 } catch (IOException ex) { 376 err.log(Level.WARNING, null, ex); 378 cookie = null; 379 } catch (ClassNotFoundException ex) { 380 err.log(Level.WARNING, null, ex); 382 cookie = null; 383 } 384 385 if (cookie == null) { 386 DataFolder folder = (DataFolder) dob.getCookie (DataFolder.class); 387 if (folder != null) { 388 HoldInstance previous = map.get (folder.getPrimaryFile ()); 389 if (previous != null && previous.cookie != null) { 390 cookie = previous; 392 acceptType = 2; 393 } else { 394 cookie = acceptFolder (folder); 395 acceptType = 3; 396 } 397 } 398 } 399 400 if (cookie == null) { 401 DataObject.Container c = (DataObject.Container)dob.getCookie (DataObject.Container.class); 403 if (c != null) { 404 cookie = acceptContainer (c); 405 acceptType = 4; 406 } 407 } 408 409 if (err.isLoggable(Level.FINE)) { 410 err.fine("acceptDataObject: " + dob + " cookie: " + cookie + " acceptType: " + acceptType); } 412 413 return cookie; 414 } 415 416 431 protected InstanceCookie acceptCookie (InstanceCookie cookie) 432 throws java.io.IOException , ClassNotFoundException { 433 return cookie; 434 } 435 436 452 protected InstanceCookie acceptFolder (DataFolder df) { 453 return acceptContainer (df); 454 } 455 456 475 protected InstanceCookie acceptContainer (DataObject.Container container) { 476 return null; 477 } 478 479 480 481 482 483 506 protected abstract Object createInstance (InstanceCookie[] cookies) 507 throws java.io.IOException , ClassNotFoundException ; 508 509 510 511 512 513 523 protected Object instanceForCookie (DataObject obj, InstanceCookie cookie) 524 throws IOException , ClassNotFoundException { 525 return cookie.instanceCreate (); 526 } 527 528 529 530 531 532 534 public synchronized void recreate () { 535 err.fine("recreate"); 542 recognizingTask = computeChildrenList (container, listener); 543 if (err.isLoggable(Level.FINE)) { 544 err.fine(" recognizing task is now " + recognizingTask); 545 } 546 notifyRunning (); 547 } 548 549 555 final void checkRecreate() { 556 if(isFinished()) { 557 recreate(); 558 } 559 } 560 561 564 private final synchronized Task checkRecognizingStarted () { 565 if(recognizingTask == null) { 566 recreate(); 567 } 568 569 return recognizingTask; 570 } 571 572 573 574 575 576 577 582 private static void waitProcessingFinished ( 583 DataObject.Container c 584 ) { 585 if (c instanceof FolderList) { 586 ((FolderList)c).waitProcessingFinished (); 587 } 588 } 589 590 597 private static Task computeChildrenList ( 598 final DataObject.Container container, final FolderListListener listener 599 ) { 600 if (container instanceof FolderList) { 601 FolderList list = (FolderList)container; 602 return list.computeChildrenList (listener); 603 } 604 605 return PROCESSOR.post (new Runnable () { 608 public void run () { 609 DataObject[] arr = container.getChildren (); 610 ArrayList<DataObject> list = new ArrayList<DataObject> (arr.length); 611 for (int i = 0; i < arr.length; i++) { 612 listener.process (arr[i], list); 613 } 614 listener.finished (list); 615 } 616 }); 617 } 618 619 620 621 622 623 629 final void processObjects (final Collection<DataObject> arr) { 630 creationTask = postCreationTask (new Runnable () { 631 public void run () { 632 defaultProcessObjects (arr); 633 } 634 }); 635 } 636 637 640 private final void defaultProcessObjects (Collection<DataObject> arr) { 641 err.fine("defaultProcessObjects"); 642 HashSet<FileObject> toRemove; 643 ArrayList<HoldInstance> cookies = new ArrayList<HoldInstance> (); 644 645 synchronized (CURRENT) { 647 toRemove = new HashSet<FileObject> (map.keySet ()); 648 } 649 650 for (DataObject obj: arr) { 651 if (! obj.isValid()) { 652 continue; 655 } 656 657 InstanceCookie cookie = acceptDataObject(obj); 659 if (cookie != null) { 660 FileObject fo = obj.getPrimaryFile (); 662 663 boolean attachListener = true; 664 HoldInstance prevCookie = null; 665 if (toRemove.remove (fo)) { 666 prevCookie = map.get (fo); 668 if (prevCookie != null && (prevCookie.cookie == null || !prevCookie.cookie.equals (cookie))) { 669 prevCookie = null; 670 attachListener = false; 672 } 673 } 674 675 if (prevCookie == null) { 676 HoldInstance hold; 678 679 if (cookie instanceof HoldInstance) { 680 hold = (HoldInstance)cookie; 681 } else { 682 hold = new HoldInstance(obj, cookie); 683 } 684 685 synchronized (CURRENT) { 687 map.put (fo, hold); 688 } 689 690 if (attachListener) { 692 obj.addPropertyChangeListener ( 693 org.openide.util.WeakListeners.propertyChange (listener, obj) 694 ); 695 } 696 697 cookies.add (hold); 698 } else { 699 cookies.add (prevCookie); 701 } 702 } else { 703 synchronized (CURRENT) { 705 FileObject fo = obj.getPrimaryFile (); 706 toRemove.remove (fo); 707 708 HoldInstance hold = map.get (fo); 709 if (hold != null && hold.cookie == null) { 710 continue; 712 } 713 714 716 hold = new HoldInstance (obj, null); 717 718 map.put (fo, hold); 719 } 720 721 obj.addPropertyChangeListener ( 723 org.openide.util.WeakListeners.propertyChange (listener, obj) 724 ); 725 726 } 727 728 } 729 730 synchronized (CURRENT) { 732 map.keySet ().removeAll (toRemove); 734 } 735 736 HoldInstance[] all = new HoldInstance[cookies.size ()]; 738 cookies.toArray (all); 739 740 updateWaitFor (all); 741 742 Object result = null; 743 try { 744 result = createInstance (all); 745 } catch (IOException ex) { 746 result = ex; 747 } catch (ClassNotFoundException ex) { 748 result = ex; 749 } finally { 750 if (err.isLoggable(Level.FINE)) { 751 err.fine("notifying finished"); for (int log = 0; log < all.length; log++) { 753 err.fine(" #" + log + ": " + all[log]); } 755 } 756 object = result; 757 758 Object prevResult = CURRENT.get (); 759 CURRENT.set (result); 760 Object prevLast = LAST_CURRENT.get (); 761 LAST_CURRENT.set (this); 762 763 try { 764 notifyFinished (); 765 } finally { 766 CURRENT.set (prevResult); 767 LAST_CURRENT.set (prevLast); 768 } 769 } 770 } 771 772 775 private void updateWaitFor (HoldInstance[] arr) { 776 ArrayList<Task> out = new ArrayList<Task> (arr.length); 777 for (int i = 0; i < arr.length; i++) { 778 Task t = arr[i].getTask (); 779 if (t != null) { 780 out.add (t); 781 } 782 } 783 waitFor = out.toArray (new Task[out.size ()]); 784 } 785 786 787 788 789 790 803 protected Task postCreationTask (Runnable run) { 804 return PROCESSOR.post (run); 805 } 806 807 808 809 810 811 813 final Logger err () { 814 return err; 815 } 816 817 public String toString () { 818 return getClass ().getName () + "@" + Integer.toHexString (System.identityHashCode (this)) + "(" + this.container + ")"; } 820 821 822 823 824 825 840 private class Listener implements PropertyChangeListener , FolderListListener { 841 842 Listener() {} 843 844 849 public void propertyChange (PropertyChangeEvent ev) { 850 Object s = ev.getSource (); 851 if (s == container) { 852 if (DataObject.Container.PROP_CHILDREN.equals(ev.getPropertyName ())) { 853 err.fine("PROP_CHILDREN"); 854 855 recreate(); 856 } 857 return; 858 } 859 860 if (DataObject.PROP_NAME.equals(ev.getPropertyName())) { 861 if (s instanceof DataObject) { 862 err.fine("PROP_NAME"); 863 recreate(); 864 } 865 } 866 867 869 if (DataObject.PROP_COOKIE.equals(ev.getPropertyName ())) { 870 if (s instanceof DataObject) { 871 DataObject source = (DataObject)s; 872 err.fine("PROP_COOKIE: " + source); 874 InstanceCookie ic = acceptDataObject (source); 875 876 HoldInstance hi; 877 FileObject fo = source.getPrimaryFile(); 878 synchronized (CURRENT) { 879 hi = map.get(fo); 880 } 881 882 if (hi != null) { 883 err.fine("previous instance: " + hi + " new instance " + ic); 891 if (ic == null || (ic != hi && !ic.equals (hi.cookie))) { 892 hi = new HoldInstance(source, ic); 893 894 synchronized (CURRENT) { 896 map.put (fo, hi); 897 } 898 recreate (); 899 } 900 } 901 } 902 } 903 } 904 905 910 public void finished(java.util.List <DataObject> arr) { 911 processObjects (arr); 912 } 913 914 919 public void process(DataObject obj, java.util.List <DataObject> arr) { 920 arr.add (obj); 921 } 922 923 } 924 925 926 927 928 929 933 private class HoldInstance extends Object 934 implements InstanceCookie.Of, TaskListener { 935 936 private final DataObject source; 937 938 protected final InstanceCookie cookie; 939 940 public HoldInstance (DataObject source, InstanceCookie cookie) { 941 this.cookie = cookie; 942 this.source = source; 943 944 if (cookie instanceof Task) { 945 Task t = (Task)cookie; 948 t.addTaskListener ( 949 (TaskListener)org.openide.util.WeakListeners.create (TaskListener.class, this, t) 950 ); 951 } 952 } 953 954 957 public String instanceName () { 958 return cookie.instanceName (); 959 } 960 961 973 public boolean instanceOf(Class <?> type) { 974 if (cookie instanceof InstanceCookie.Of) { 975 InstanceCookie.Of of = (InstanceCookie.Of)cookie; 976 return of.instanceOf (type); 977 } 978 try { 980 Class <?> clazz = cookie.instanceClass (); 981 return type.isAssignableFrom (clazz); 982 } catch (IOException ex) { 983 return false; 984 } catch (ClassNotFoundException ex) { 985 return false; 986 } 987 } 988 989 996 public Class instanceClass () 997 throws java.io.IOException , ClassNotFoundException { 998 return cookie.instanceClass (); 999 } 1000 1001 1006 public Object instanceCreate () 1007 throws java.io.IOException , ClassNotFoundException { 1008 return instanceForCookie (source, cookie); 1009 } 1010 1011 1014 public void taskFinished(Task task) { 1015 checkRecreate(); 1016 } 1017 1018 1020 public Task getTask () { 1021 if (cookie instanceof Task) { 1022 return (Task)cookie; 1025 } else { 1026 return null; 1027 } 1028 } 1029 } 1031} 1032 | Popular Tags |