1 19 20 package org.openide.nodes; 21 22 import java.lang.ref.*; 23 import java.util.*; 24 import org.openide.ErrorManager; 25 import junit.framework.*; 26 import org.netbeans.junit.*; 27 28 public class ChildrenKeysIssue30907Test extends NbTestCase { 29 30 public ChildrenKeysIssue30907Test(java.lang.String testName) { 31 super(testName); 32 } 33 34 protected void setUp () throws Exception { 35 System.setProperty("org.openide.util.Lookup", "org.openide.nodes.ChildrenKeysIssue30907Test$Lkp"); 36 assertNotNull ("ErrManager has to be in lookup", org.openide.util.Lookup.getDefault ().lookup (ErrManager.class)); 37 ErrManager.messages.delete (0, ErrManager.messages.length ()); 38 } 39 40 41 protected void runTest () throws Throwable { 42 try { 43 super.runTest(); 44 } catch (Error err) { 45 AssertionFailedError newErr = new AssertionFailedError (err.getMessage () + "\n" + ErrManager.messages); 46 newErr.initCause (err); 47 throw newErr; 48 } 49 50 waitRemoveNotified (); 51 } 52 53 private Object FINAL_LOCK; 54 private boolean removeNotified; 55 protected void doRemoveNotify () { 56 synchronized (FINAL_LOCK) { 57 removeNotified = true; 58 notifyAll (); 59 } 60 } 61 62 private final void waitRemoveNotified () throws Exception { 63 if (FINAL_LOCK == null) { 64 return; 65 } 66 67 int cnt = 0; 68 for (;;) { 69 synchronized (FINAL_LOCK) { 70 if (removeNotified) { 71 return; 72 } 73 FINAL_LOCK.wait (500); 74 } 75 if (cnt++ == 10) { 76 fail ("waitRemoveNotified failed, too many waits: " + cnt); 77 } 78 System.gc (); 79 System.runFinalization(); 80 } 81 } 82 83 84 public void testProperInitializationEvenIfInvokedFromMultipleThreadsBug30907SlowAddNotifyWithReadAccess () throws Exception { 85 doBug30907 (true, true, 0, 2); 86 } 87 88 public void testProperInitializationEvenIfInvokedFromMultipleThreadsBug30907QuickAddNotifyWithReadAccess () throws Exception { 89 doBug30907 (false, true, 0, 2); 90 } 91 92 public void testProperInitializationEvenIfInvokedFromMultipleThreadsBug30907QuickAddNotify () throws Exception { 93 doBug30907 (false, false, 2, 2); 94 } 95 public void testProperInitializationEvenIfInvokedFromMultipleThreadsBug30907SlowAddNotify () throws Exception { 96 doBug30907 (true, false, 2, 2); 97 } 98 99 public void testProperInitializationEvenIfInvokedFromMultipleThreadsBug30907AddNotifyWithException () throws Exception { 100 doBug30907 (true, true, false, 0, 0); 101 } 102 103 public void testDeadlock50379 () throws Exception { 104 class K extends Children.Keys<Object > implements Runnable { 105 106 public void run () { 107 if (!MUTEX.isWriteAccess ()) { 108 MUTEX.writeAccess (this); 109 return; 110 } 111 112 synchronized (this) { 113 notifyAll (); 114 } 115 116 try { 117 Thread.sleep (100); 118 } catch (InterruptedException ex) { 119 fail ("No interrupts"); 120 } 121 122 123 setKeys (java.util.Collections.singleton(this)); 124 } 125 126 @Override 127 protected synchronized void addNotify () { 128 org.openide.util.RequestProcessor.getDefault().post (this); 129 try { 130 wait (); 131 } catch (InterruptedException ex) { 132 fail ("No interrupts"); 133 } 134 } 135 136 protected Node[] createNodes (Object key) { 137 return new Node[0]; 138 } 139 140 } 141 142 143 K keys = new K (); 144 keys.getNodes (); 146 } 147 148 private void doBug30907 (final boolean slowAddNotify, boolean readAccess, int mainCount, int threadCount) throws Exception { 149 doBug30907 (slowAddNotify, false, readAccess, mainCount, threadCount); 150 } 151 152 private void doBug30907 (final boolean slowAddNotify, final boolean throwException, boolean readAccess, int mainCount, int threadCount) throws Exception { 153 FINAL_LOCK = new Object (); 154 155 ErrManager.messages.append ("doBug30907 slowAddNotify: " + slowAddNotify 156 + " throwException: " + throwException + " readAccess: " + readAccess + " mainCount: " + mainCount + 157 " threadCount: " + threadCount + '\n'); 158 159 164 165 final Node node[] = { null }; 166 167 final Object LOCK = new Object (); 168 169 class K extends Children.Keys implements Runnable { 170 private String [] arr; 171 172 public K (String [] arr) { 173 this.arr = arr; 174 } 175 176 protected Node[] createNodes(Object key) { 177 AbstractNode an = new AbstractNode (Children.LEAF); 178 an.setName (key.toString ()); 179 ErrManager.messages.append (" creating node: " + key.toString () + " by thread: " + Thread.currentThread ().getName () + "\n"); 180 181 return new Node[] { an }; 182 } 183 184 public void addNotify () { 185 if (slowAddNotify) { 186 try { 187 synchronized (LOCK) { 189 ErrManager.messages.append (" blocking in addNotify: " + Thread.currentThread ().getName () + "\n"); 190 LOCK.notify (); } 192 193 Thread.sleep (300); 195 ErrManager.messages.append (" end of blocking in addNotify: " + Thread.currentThread ().getName () + "\n"); 196 } catch (InterruptedException ex) { 197 fail ("Exception"); 198 } 199 } 200 201 ErrManager.messages.append (" set keys: " + java.util.Arrays.asList (arr) + " by " + Thread.currentThread ().getName () + "\n"); 202 setKeys (arr); 203 ErrManager.messages.append (" end of keys by " + Thread.currentThread ().getName () + "\n"); 204 205 if (throwException) { 206 ErrManager.messages.append (" throwing exception by " + Thread.currentThread ().getName () + "\n"); 207 throw new IllegalStateException ( "testing exception" ); 208 } 209 } 210 211 Node[] result; 212 public void run () { 213 Node[] arr = new Node[]{}; 215 try { 216 ErrManager.messages.append ("Run: computing nodes\n"); 217 arr = node[0].getChildren ().getNodes (); 218 ErrManager.messages.append ("Run: nodes computed" + Arrays.asList (arr) + "\n"); 219 } 220 catch ( IllegalStateException e ) { 221 ErrManager.messages.append ("Run: exception caught: " + e.getMessage () + "\n"); 223 } 224 225 if (!slowAddNotify) { 226 synchronized (LOCK) { 229 ErrManager.messages.append ("Run: Notifying others to run\n"); 230 LOCK.notify (); } 232 } 233 234 synchronized (LOCK) { 235 ErrManager.messages.append ("Run: Assigning result: " + Arrays.asList (arr) + "\n"); 236 result = arr; 237 LOCK.notify (); } 239 } 240 241 protected void removeNotify () { 242 super.removeNotify(); 243 doRemoveNotify (); 244 } 245 } 246 247 K k = new K (new String [] { "1", "2" }); 248 node[0] = new FilterNode (new AbstractNode (k)); 249 250 Node[] result; 251 synchronized (LOCK) { 252 try { 253 if (readAccess) { 254 ErrManager.messages.append ("Main: Before read access\n"); 255 Children.PR.enterReadAccess (); 256 ErrManager.messages.append ("Main: In read access\n"); 257 } 258 259 Thread t = new Thread (k, "testProperInitializationEvenIfInvokedFromMultipleThreadsBug30907Thread"); 260 t.setDaemon(true); 261 ErrManager.messages.append ("Main: Starting the thread\n"); 262 t.start (); 263 264 if (!readAccess) { 265 ErrManager.messages.append ("Main: Wait for N1\n"); 266 LOCK.wait (); ErrManager.messages.append ("Main: Waiting for N1 is over\n"); 268 } 269 270 ErrManager.messages.append ("Main: Calling getNodes()\n"); 271 result = node[0].getChildren ().getNodes (); 272 ErrManager.messages.append ("Main: getNodes() finished: " + Arrays.asList (result) + "\n"); 273 assertNotNull("Get nodes cannot return null", result); 274 assertEquals ("Returns proper value for children as it waits until addNotify finishes", mainCount, result.length); 275 } finally { 276 if (readAccess) { 277 ErrManager.messages.append ("Main: before exitReadAccess\n"); 278 Children.PR.exitReadAccess (); 279 ErrManager.messages.append ("Main: after exitReadAccess\n"); 280 } 281 } 282 283 if (readAccess) { 284 ErrManager.messages.append ("Main: wait for N1 two\n"); 285 LOCK.wait (); ErrManager.messages.append ("Main: wait for N1 two finished\n"); 287 } 288 289 while (k.result == null) { 291 LOCK.wait (); } 293 } 294 assertEquals ("Two children there even in the initialization thread", threadCount, k.result.length); 295 } 296 297 public static final class Lkp extends org.openide.util.lookup.AbstractLookup { 298 public Lkp () { 299 this (new org.openide.util.lookup.InstanceContent ()); 300 } 301 302 private Lkp (org.openide.util.lookup.InstanceContent ic) { 303 super (ic); 304 ic.add (new ErrManager ()); 305 } 306 } 307 308 private static final class ErrManager extends org.openide.ErrorManager { 309 public static final StringBuffer messages = new StringBuffer (); 310 311 public Throwable annotate (Throwable t, int severity, String message, String localizedMessage, Throwable stackTrace, java.util.Date date) { 312 return t; 313 } 314 315 public Throwable attachAnnotations (Throwable t, org.openide.ErrorManager.Annotation[] arr) { 316 return t; 317 } 318 319 public org.openide.ErrorManager.Annotation[] findAnnotations (Throwable t) { 320 return null; 321 } 322 323 public org.openide.ErrorManager getInstance (String name) { 324 return this; 325 } 326 327 public void log (int severity, String s) { 328 messages.append (s); 329 messages.append ('\n'); 330 } 331 332 public void notify (int severity, Throwable t) { 333 messages.append (t.getMessage ()); 334 } 335 336 } 337 } 338 | Popular Tags |