1 19 20 package org.netbeans.modules.debugger.jpda.models; 21 22 import com.sun.jdi.ThreadGroupReference; 23 import com.sun.jdi.ThreadReference; 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 import java.lang.ref.WeakReference ; 27 import java.util.Collection ; 28 import java.util.HashSet ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Set ; 32 import java.util.WeakHashMap ; 33 import org.netbeans.api.debugger.jpda.JPDAThread; 34 import org.netbeans.api.debugger.jpda.JPDAThreadGroup; 35 36 import org.netbeans.spi.debugger.ContextProvider; 37 import org.netbeans.api.debugger.jpda.JPDADebugger; 38 import org.netbeans.spi.viewmodel.ModelEvent; 39 import org.netbeans.spi.viewmodel.ModelListener; 40 import org.netbeans.spi.viewmodel.TreeModel; 41 import org.netbeans.spi.viewmodel.UnknownTypeException; 42 43 import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; 44 import org.openide.util.RequestProcessor; 45 46 47 52 public class ThreadsTreeModel implements TreeModel { 53 54 private static boolean verbose = 55 (System.getProperty ("netbeans.debugger.viewrefresh") != null) && 56 (System.getProperty ("netbeans.debugger.viewrefresh").indexOf ('t') >= 0); 57 58 private JPDADebuggerImpl debugger; 59 private Map <Object , ChildrenTree> childrenCache = new WeakHashMap <Object , ChildrenTree>(); 60 private Listener listener; 61 private Collection <ModelListener> listeners = new HashSet <ModelListener>(); 62 63 64 public ThreadsTreeModel (ContextProvider lookupProvider) { 65 debugger = (JPDADebuggerImpl) lookupProvider. 66 lookupFirst (null, JPDADebugger.class); 67 } 68 69 public Object getRoot () { 70 return ROOT; 71 } 72 73 public Object [] getChildren (Object o, int from, int to) 74 throws UnknownTypeException { 75 108 109 Object [] ch; 110 synchronized (childrenCache) { 111 ChildrenTree cht = childrenCache.get(o); 113 if (cht != null) { 114 ch = cht.getChildren(); 115 } else { 116 ch = null; 117 } 118 } 119 if (ch == null) { 120 ch = computeChildren(o); 121 if (ch == null) { 122 throw new UnknownTypeException (o); 123 } else { 124 synchronized (childrenCache) { 125 ChildrenTree cht = new ChildrenTree(o); 126 cht.setChildren(ch); 127 childrenCache.put(o, cht); 128 } 129 } 130 } 131 int l = ch.length; 132 from = Math.min(l, from); 133 to = Math.min(l, to); 134 if (from == 0 && to == l) { 135 return ch; 136 } else { 137 Object [] ch1 = new Object [to - from]; 138 System.arraycopy(ch, from, ch1, 0, to - from); 139 ch = ch1; 140 } 141 return ch; 142 } 143 144 private Object [] computeChildren(Object node) { 145 166 if (node.equals (ROOT)) { 167 168 if (verbose) { 169 com.sun.jdi.VirtualMachine vm = debugger.getVirtualMachine(); 170 if (vm == null) { 171 System.err.println("\nThreadsTreeModel.computeChildren():\nVM is null!\n"); 172 } else { 173 List <ThreadReference> threads = vm.allThreads(); 174 System.err.println("\nThreadsTreeModel.computeChildren() ALL Threads:"); 175 for (ThreadReference t : threads) { 176 System.err.println(" "+t.name()+" is suspended: "+t.isSuspended()+", suspend count = "+t.suspendCount()); 177 } 178 System.err.println(""); 179 } 180 } 181 182 return debugger.getTopLevelThreadGroups(); 183 } else if (node instanceof JPDAThreadGroup) { 184 JPDAThreadGroup tg = (JPDAThreadGroup) node; 185 JPDAThreadGroup[] tgs = tg.getThreadGroups(); 186 JPDAThread[] ts = tg.getThreads(); 187 int n = tgs.length + ts.length; 188 Object [] ch = new Object [n]; 189 System.arraycopy(tgs, 0, ch, 0, tgs.length); 190 System.arraycopy(ts, 0, ch, tgs.length, ts.length); 191 return ch; 192 } else { 193 return new Object [0]; 194 } 195 } 196 197 private void recomputeChildren() { 198 synchronized (childrenCache) { 199 recomputeChildren(getRoot()); 200 } 201 } 202 203 private void recomputeChildren(Object node) { 204 ChildrenTree cht = childrenCache.get(node); 205 if (cht != null) { 206 Set keys = childrenCache.keySet(); 207 Object [] oldCh = cht.getChildren(); 208 Object [] newCh = computeChildren(node); 209 cht.setChildren(newCh); 210 for (int i = 0; i < newCh.length; i++) { 211 if (keys.contains(newCh[i])) { 212 recomputeChildren(newCh[i]); 213 } 214 } 215 } 216 225 } 226 227 236 public int getChildrenCount (Object node) throws UnknownTypeException { 237 return Integer.MAX_VALUE; 239 263 288 } 289 290 public boolean isLeaf (Object o) throws UnknownTypeException { 291 if (o instanceof JPDAThread) return true; 292 if (o instanceof JPDAThreadGroup) return false; 293 if (o == ROOT) return false; 294 throw new UnknownTypeException (o); 295 } 296 297 public void addModelListener (ModelListener l) { 298 synchronized (listeners) { 299 listeners.add (l); 300 if (listener == null) { 301 listener = new Listener (this, debugger); 302 } 303 } 304 } 305 306 public void removeModelListener (ModelListener l) { 307 synchronized (listeners) { 308 listeners.remove (l); 309 if (listeners.size () == 0) { 310 listener.destroy (); 311 listener = null; 312 } 313 } 314 } 315 316 public void fireTreeChanged () { 317 recomputeChildren(); 318 ModelListener[] ls; 319 synchronized (listeners) { 320 ls = listeners.toArray(new ModelListener[0]); 321 } 322 ModelEvent ev = new ModelEvent.TreeChanged(this); 323 for (int i = 0; i < ls.length; i++) { 324 ls[i].modelChanged (ev); 325 } 326 } 327 328 331 private static class Listener implements PropertyChangeListener { 332 333 private JPDADebugger debugger; 334 private WeakReference <ThreadsTreeModel> model; 335 private RequestProcessor.Task task; 338 339 public Listener ( 340 ThreadsTreeModel tm, 341 JPDADebugger debugger 342 ) { 343 this.debugger = debugger; 344 model = new WeakReference <ThreadsTreeModel>(tm); 345 debugger.addPropertyChangeListener (this); 346 if (debugger.getState() == debugger.STATE_RUNNING) { 347 task = createTask(); 348 task.schedule(500); 349 } 350 } 351 352 private ThreadsTreeModel getModel () { 353 ThreadsTreeModel tm = model.get (); 354 if (tm == null) { 355 destroy (); 356 } 357 return tm; 358 } 359 360 void destroy () { 361 debugger.removePropertyChangeListener (this); 362 synchronized (this) { 363 if (task != null) { 364 task.cancel (); 366 if (verbose) 367 System.out.println("TTM cancel old task " + task); 368 task = null; 369 } 370 } 371 } 372 373 private RequestProcessor.Task createTask() { 374 RequestProcessor.Task task = 375 new RequestProcessor("Threads Refresh", 1).create( 376 new RefreshTree()); 377 if (verbose) 378 System.out.println("TTM create task " + task); 379 return task; 380 } 381 382 public void propertyChange (PropertyChangeEvent e) { 383 if ( (e.getPropertyName () == debugger.PROP_STATE) && 384 (debugger.getState () == debugger.STATE_STOPPED) 385 ) { 386 final ThreadsTreeModel tm = getModel (); 387 if (tm == null) return; 388 synchronized (this) { 389 if (task == null) { 390 task = createTask(); 391 } 392 } 393 task.schedule(500); 394 } else 395 if ( (e.getPropertyName () == debugger.PROP_STATE) && 396 (debugger.getState () == debugger.STATE_RUNNING) 397 ) { 398 final ThreadsTreeModel tm = getModel (); 399 if (tm == null) return; 400 synchronized (this) { 401 if (task == null) { 402 task = createTask(); 403 } 404 } 405 task.schedule (2000); 406 } 407 } 408 409 private class RefreshTree implements Runnable { 410 public RefreshTree () {} 411 412 public void run() { 413 ThreadsTreeModel tm = getModel (); 414 if (tm == null) return; 415 if (verbose) 416 System.out.println("TTM do R task " + task); 417 tm.fireTreeChanged (); 418 if (debugger.getState () == debugger.STATE_RUNNING) { 419 task.schedule (2000); 420 } 421 } 422 } 423 } 424 425 private static class ChildrenTree { 426 427 private Object node; 428 private Object [] ch; 429 430 public ChildrenTree(Object node) { 431 this.node = node; 432 } 433 434 public void setChildren(Object [] ch) { 435 this.ch = ch; 436 } 437 438 public Object [] getChildren() { 439 return ch; 440 } 441 442 } 443 444 } 445 446 | Popular Tags |