1 19 20 package org.netbeans.modules.debugger.jpda.models; 21 22 import com.sun.jdi.ObjectReference; 23 import com.sun.jdi.Value; 24 25 import java.beans.PropertyChangeEvent ; 26 import java.beans.PropertyChangeListener ; 27 import java.beans.PropertyChangeSupport ; 28 import java.lang.ref.WeakReference ; 29 import java.util.*; 30 import javax.security.auth.RefreshFailedException ; 31 import javax.security.auth.Refreshable ; 32 33 import org.netbeans.api.debugger.Watch; 34 import org.netbeans.api.debugger.DebuggerManager; 35 import org.netbeans.api.debugger.DebuggerManagerAdapter; 36 import org.netbeans.api.debugger.jpda.InvalidExpressionException; 37 import org.netbeans.api.debugger.jpda.Variable; 38 import org.netbeans.spi.debugger.ContextProvider; 39 import org.netbeans.api.debugger.jpda.JPDADebugger; 40 import org.netbeans.api.debugger.jpda.JPDAWatch; 41 import org.netbeans.spi.viewmodel.ModelEvent; 42 import org.netbeans.spi.viewmodel.TreeModel; 43 import org.netbeans.spi.viewmodel.ModelListener; 44 import org.netbeans.spi.viewmodel.UnknownTypeException; 45 46 import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; 47 import org.netbeans.modules.debugger.jpda.expr.Expression; 48 import org.netbeans.modules.debugger.jpda.expr.ParseException; 49 50 import org.openide.util.RequestProcessor; 51 52 55 public class WatchesModel implements TreeModel { 56 57 58 private static boolean verbose = 59 (System.getProperty ("netbeans.debugger.viewrefresh") != null) && 60 (System.getProperty ("netbeans.debugger.viewrefresh").indexOf ('w') >= 0); 61 62 private JPDADebuggerImpl debugger; 63 private Listener listener; 64 private Vector<ModelListener> listeners = new Vector<ModelListener>(); 65 private ContextProvider lookupProvider; 66 private Map<Watch, JPDAWatchEvaluating> watchToValue = new WeakHashMap<Watch, JPDAWatchEvaluating>(); 69 70 public WatchesModel (ContextProvider lookupProvider) { 71 debugger = (JPDADebuggerImpl) lookupProvider. 72 lookupFirst (null, JPDADebugger.class); 73 this.lookupProvider = lookupProvider; 74 } 75 76 80 public Object getRoot () { 81 return ROOT; 82 } 83 84 88 public Object [] getChildren (Object parent, int from, int to) 89 throws UnknownTypeException { 90 if (parent == ROOT) { 91 92 Watch[] ws = DebuggerManager.getDebuggerManager (). 94 getWatches (); 95 to = Math.min(ws.length, to); 96 from = Math.min(ws.length, from); 97 Watch[] fws = new Watch [to - from]; 98 System.arraycopy (ws, from, fws, 0, to - from); 99 100 int i, k = fws.length; 102 JPDAWatch[] jws = new JPDAWatch [k]; 103 for (i = 0; i < k; i++) { 104 105 106 JPDAWatchEvaluating jw = watchToValue.get(fws[i]); 107 if (jw == null) { 108 jw = new JPDAWatchEvaluating(this, fws[i], debugger); 109 watchToValue.put(fws[i], jw); 110 } 111 jws[i] = jw; 112 113 } 115 116 if (listener == null) 117 listener = new Listener (this, debugger); 118 return jws; 119 } 120 if (parent instanceof JPDAWatchImpl) { 121 return getLocalsTreeModel ().getChildren (parent, from, to); 122 } 123 return getLocalsTreeModel ().getChildren (parent, from, to); 124 } 125 126 135 public int getChildrenCount (Object node) throws UnknownTypeException { 136 if (node == ROOT) { 137 if (listener == null) 138 listener = new Listener (this, debugger); 139 return Integer.MAX_VALUE; 141 } 143 if (node instanceof JPDAWatchImpl) { 144 return getLocalsTreeModel ().getChildrenCount (node); 145 } 146 return getLocalsTreeModel ().getChildrenCount (node); 147 } 148 149 public boolean isLeaf (Object node) throws UnknownTypeException { 150 if (node == ROOT) return false; 151 if (node instanceof JPDAWatchEvaluating) { 152 JPDAWatchEvaluating jwe = (JPDAWatchEvaluating) node; 153 JPDAWatch jw = jwe.getEvaluatedWatch(); 154 if (jw instanceof JPDAWatchImpl) { 155 return ((JPDAWatchImpl) jw).isPrimitive (); 156 } 157 } 158 return getLocalsTreeModel ().isLeaf (node); 159 } 160 161 public void addModelListener (ModelListener l) { 162 listeners.add (l); 163 } 164 165 public void removeModelListener (ModelListener l) { 166 listeners.remove (l); 167 } 168 169 private void fireTreeChanged () { 170 synchronized (watchToValue) { 171 for (Iterator<JPDAWatchEvaluating> it = watchToValue.values().iterator(); it.hasNext(); ) { 172 it.next().setEvaluated(null); 173 } 174 } 175 Vector v = (Vector) listeners.clone (); 176 int i, k = v.size (); 177 ModelEvent event = new ModelEvent.TreeChanged(this); 178 for (i = 0; i < k; i++) 179 ((ModelListener) v.get (i)).modelChanged (event); 180 } 181 182 private void fireWatchesChanged () { 183 Vector v = (Vector) listeners.clone (); 184 int i, k = v.size (); 185 ModelEvent event = new ModelEvent.NodeChanged(this, ROOT, ModelEvent.NodeChanged.CHILDREN_MASK); 186 for (i = 0; i < k; i++) 187 ((ModelListener) v.get (i)).modelChanged (event); 188 } 189 190 void fireTableValueChangedChanged (Object node, String propertyName) { 191 ((JPDAWatchEvaluating) node).setEvaluated(null); 192 fireTableValueChangedComputed(node, propertyName); 193 } 194 195 void fireTableValueChangedComputed (Object node, String propertyName) { 196 Vector v = (Vector) listeners.clone (); 197 int i, k = v.size (); 198 for (i = 0; i < k; i++) 199 ((ModelListener) v.get (i)).modelChanged ( 200 new ModelEvent.TableValueChanged (this, node, propertyName) 201 ); 202 } 203 204 205 207 JPDADebuggerImpl getDebugger () { 208 return debugger; 209 } 210 211 private LocalsTreeModel localsTreeModel; 212 213 LocalsTreeModel getLocalsTreeModel () { 214 if (localsTreeModel == null) 215 localsTreeModel = (LocalsTreeModel) lookupProvider. 216 lookupFirst ("LocalsView", TreeModel.class); 217 return localsTreeModel; 218 } 219 220 221 223 private static class JPDAWatchEvaluating extends AbstractVariable 224 implements JPDAWatch, Variable, 225 Refreshable , PropertyChangeListener { 227 228 private WatchesModel model; 229 private Watch w; 230 private JPDADebuggerImpl debugger; 231 private JPDAWatch evaluatedWatch; 232 private Expression expression; 233 private ParseException parseException; 234 private boolean[] evaluating = new boolean[] { false }; 235 private PropertyChangeSupport propSupp = new PropertyChangeSupport (this); 236 237 public JPDAWatchEvaluating(WatchesModel model, Watch w, JPDADebuggerImpl debugger) { 238 super(debugger, null, "" + w); 239 this.model = model; 240 this.w = w; 241 this.debugger = debugger; 242 parseExpression(w.getExpression()); 243 } 244 245 private void parseExpression(String exprStr) { 246 try { 247 expression = Expression.parse ( 248 exprStr, 249 Expression.LANGUAGE_JAVA_1_5 250 ); 251 parseException = null; 252 } catch (ParseException e) { 253 setEvaluated(new JPDAWatchImpl(debugger, w, e, this)); 254 parseException = e; 255 } 256 } 257 258 Expression getParsedExpression() throws ParseException { 259 if (parseException != null) { 260 throw parseException; 261 } 262 return expression; 263 } 264 265 266 public void setEvaluated(JPDAWatch evaluatedWatch) { 267 synchronized (this) { 268 this.evaluatedWatch = evaluatedWatch; 269 } 270 if (evaluatedWatch != null) { 271 if (evaluatedWatch instanceof JPDAWatchImpl) { 272 setInnerValue(((JPDAWatchImpl) evaluatedWatch).getInnerValue()); 273 } else if (evaluatedWatch instanceof JPDAObjectWatchImpl) { 274 setInnerValue(((JPDAObjectWatchImpl) evaluatedWatch).getInnerValue()); 275 } 276 } else { 278 setInnerValue(null); 279 } 280 } 282 283 synchronized JPDAWatch getEvaluatedWatch() { 284 return evaluatedWatch; 285 } 286 287 public void expressionChanged() { 288 setEvaluated(null); 289 parseExpression(w.getExpression()); 290 } 291 292 public synchronized String getExceptionDescription() { 293 if (evaluatedWatch != null) { 294 return evaluatedWatch.getExceptionDescription(); 295 } else { 296 return null; 297 } 298 } 299 300 public synchronized String getExpression() { 301 if (evaluatedWatch != null) { 302 return evaluatedWatch.getExpression(); 303 } else { 304 return w.getExpression(); 305 } 306 } 307 308 public String getToStringValue() throws InvalidExpressionException { 309 synchronized (this) { 310 JPDAWatch evaluatedWatch = this.evaluatedWatch; 311 } 312 if (evaluatedWatch == null) { 313 getValue(); 314 } 315 return evaluatedWatch.getToStringValue(); 316 } 317 318 public String getType() { 319 synchronized (this) { 320 JPDAWatch evaluatedWatch = this.evaluatedWatch; 321 } 322 if (evaluatedWatch == null) { 323 getValue(); } 325 return evaluatedWatch.getType(); 326 } 327 328 public String getValue() { 329 synchronized (evaluating) { 330 if (evaluating[0]) { 331 try { 332 evaluating.wait(); 333 } catch (InterruptedException iex) { 334 return null; 335 } 336 } 337 synchronized (this) { 338 if (evaluatedWatch != null) { 339 return evaluatedWatch.getValue(); 340 } 341 } 342 evaluating[0] = true; 343 } 344 345 JPDAWatch jw = null; 346 try { 347 Expression expr = getParsedExpression(); 348 Value v = debugger.evaluateIn (expr); 349 JPDAWatchImpl jwi = new JPDAWatchImpl (debugger, w, v, this); 352 jwi.addPropertyChangeListener(this); 353 jw = jwi; 354 } catch (InvalidExpressionException e) { 355 JPDAWatchImpl jwi = new JPDAWatchImpl (debugger, w, e, this); 356 jwi.addPropertyChangeListener(this); 357 jw = jwi; 358 } catch (ParseException e) { 359 JPDAWatchImpl jwi = new JPDAWatchImpl (debugger, w, e, this); 360 jwi.addPropertyChangeListener(this); 361 jw = jwi; 362 } finally { 363 setEvaluated(jw); 364 synchronized (evaluating) { 365 evaluating[0] = false; 366 evaluating.notifyAll(); 367 } 368 } 369 return jw.getValue(); 371 } 372 373 public synchronized void remove() { 374 if (evaluatedWatch != null) { 375 evaluatedWatch.remove(); 376 } else { 377 w.remove (); 378 } 379 } 380 381 public void setExpression(String expression) { 382 w.setExpression (expression); 383 expressionChanged(); 384 } 385 386 public synchronized void setValue(String value) throws InvalidExpressionException { 387 if (evaluatedWatch != null) { 388 evaluatedWatch.setValue(value); 389 } else { 390 throw new InvalidExpressionException("Can not set value while evaluating."); 391 } 392 } 393 394 public void addPropertyChangeListener(PropertyChangeListener l) { 395 propSupp.addPropertyChangeListener(l); 396 } 397 398 public void removePropertyChangeListener(PropertyChangeListener l) { 399 propSupp.removePropertyChangeListener(l); 400 } 401 402 public void propertyChange(PropertyChangeEvent evt) { 403 model.fireTableValueChangedChanged (this, null); 404 } 405 406 407 public void refresh() throws RefreshFailedException { 408 synchronized (evaluating) { 409 if (evaluating[0]) { 410 try { 411 evaluating.wait(); 412 } catch (InterruptedException iex) { 413 throw new RefreshFailedException (iex.getLocalizedMessage()); 414 } 415 } 416 } 417 } 418 419 421 public synchronized boolean isCurrent() { 422 return evaluatedWatch != null; 423 } 424 425 public JPDAWatchEvaluating clone() { 426 return new JPDAWatchEvaluating(model, w, debugger); 427 } 428 429 } 430 431 private static class Listener extends DebuggerManagerAdapter implements 432 PropertyChangeListener { 433 434 private WeakReference <WatchesModel> model; 435 private WeakReference <JPDADebuggerImpl> debugger; 436 437 private Listener ( 438 WatchesModel tm, 439 JPDADebuggerImpl debugger 440 ) { 441 model = new WeakReference <WatchesModel>(tm); 442 this.debugger = new WeakReference <JPDADebuggerImpl>(debugger); 443 DebuggerManager.getDebuggerManager ().addDebuggerListener ( 444 DebuggerManager.PROP_WATCHES, 445 this 446 ); 447 debugger.addPropertyChangeListener (this); 448 Watch[] ws = DebuggerManager.getDebuggerManager (). 449 getWatches (); 450 int i, k = ws.length; 451 for (i = 0; i < k; i++) 452 ws [i].addPropertyChangeListener (this); 453 } 454 455 private WatchesModel getModel () { 456 WatchesModel m = model.get (); 457 if (m == null) destroy (); 458 return m; 459 } 460 461 public void watchAdded (Watch watch) { 462 WatchesModel m = getModel (); 463 if (m == null) return; 464 watch.addPropertyChangeListener (this); 465 m.fireWatchesChanged (); 466 } 467 468 public void watchRemoved (Watch watch) { 469 WatchesModel m = getModel (); 470 if (m == null) return; 471 watch.removePropertyChangeListener (this); 472 m.fireWatchesChanged (); 473 } 474 475 private RequestProcessor.Task task; 478 479 public void propertyChange (PropertyChangeEvent evt) { 480 String propName = evt.getPropertyName(); 481 if (DebuggerManager.PROP_WATCHES.equals(propName)) return ; 483 final WatchesModel m = getModel (); 484 if (m == null) return; 485 if (m.debugger.getState () == JPDADebugger.STATE_DISCONNECTED) { 486 destroy (); 487 return; 488 } 489 if (m.debugger.getState () == JPDADebugger.STATE_RUNNING) { 490 return ; 491 } 492 493 if (evt.getSource () instanceof Watch) { 494 Object node; 495 synchronized (m.watchToValue) { 496 node = m.watchToValue.get(evt.getSource()); 497 } 498 if (node != null) { 499 m.fireTableValueChangedChanged(node, null); 500 return ; 501 } 502 } 503 504 if (task == null) { 505 task = RequestProcessor.getDefault ().create (new Runnable () { 506 public void run () { 507 if (verbose) 508 System.out.println("WM do task " + task); 509 m.fireTreeChanged (); 510 } 511 }); 512 if (verbose) 513 System.out.println("WM create task " + task); 514 } 515 task.schedule(100); 516 } 517 518 private void destroy () { 519 DebuggerManager.getDebuggerManager ().removeDebuggerListener ( 520 DebuggerManager.PROP_WATCHES, 521 this 522 ); 523 JPDADebugger d = debugger.get (); 524 if (d != null) 525 d.removePropertyChangeListener (this); 526 527 Watch[] ws = DebuggerManager.getDebuggerManager (). 528 getWatches (); 529 int i, k = ws.length; 530 for (i = 0; i < k; i++) 531 ws [i].removePropertyChangeListener (this); 532 533 if (task != null) { 534 task.cancel (); 536 if (verbose) 537 System.out.println("WM cancel old task " + task); 538 task = null; 539 } 540 } 541 } 542 } 543 | Popular Tags |