KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > scripting > php > dbginterface > models > WatchesModel


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.scripting.php.dbginterface.models;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.PropertyChangeSupport JavaDoc;
25 import java.lang.ref.WeakReference JavaDoc;
26 import java.util.*;
27 import javax.security.auth.RefreshFailedException JavaDoc;
28 import javax.security.auth.Refreshable JavaDoc;
29 import javax.swing.JToolTip JavaDoc;
30 import org.netbeans.api.debugger.Watch;
31 import org.netbeans.api.debugger.DebuggerManager;
32 import org.netbeans.api.debugger.DebuggerManagerAdapter;
33 import org.netbeans.modules.scripting.php.dbginterface.DbgDebuggerImpl;
34 import org.netbeans.modules.scripting.php.dbginterface.api.VariableNode;
35 import org.netbeans.spi.debugger.ContextProvider;
36 import org.netbeans.spi.debugger.ui.Constants;
37 import org.netbeans.spi.viewmodel.ModelEvent;
38 import org.netbeans.spi.viewmodel.TreeModel;
39 import org.netbeans.spi.viewmodel.ModelListener;
40 import org.netbeans.spi.viewmodel.NodeModel;
41 import org.netbeans.spi.viewmodel.TableModel;
42 import org.netbeans.spi.viewmodel.UnknownTypeException;
43 import org.openide.util.RequestProcessor;
44
45
46 /**
47  * @author Jan Jancura
48  * @author Peter Williams (originally taken from WatchesModel class in JPDA)
49  */

50 public class WatchesModel implements TreeModel, NodeModel, TableModel {
51     private DbgDebuggerImpl debugger;
52     private Listener JavaDoc listener;
53     private Vector<ModelListener> listeners = new Vector<ModelListener>();
54     private ContextProvider lookupProvider;
55     private DebugFrame currentFrame;
56
57     // Watch to Expression or Exception
58
private Map<Watch, ScriptWatchEvaluating> watchToValue =
59             new WeakHashMap<Watch, ScriptWatchEvaluating>();
60
61     public WatchesModel(ContextProvider lookupProvider) {
62         this.debugger = (DbgDebuggerImpl)lookupProvider.lookupFirst(null, DbgDebuggerImpl.class);
63         this.lookupProvider = lookupProvider;
64     }
65
66     // ------------------------------------------------------------------------
67
// TreeModel implementation
68
// ------------------------------------------------------------------------
69
/**
70      * Returns the root node of the tree or null, if the tree is empty.
71      *
72      * @return the root node of the tree or null
73      */

74     public Object JavaDoc getRoot() {
75         return ROOT;
76     }
77
78     /**
79      *
80      * @return watches contained in this group of watches
81      */

82     public Object JavaDoc [] getChildren(Object JavaDoc parent, int from, int to) throws UnknownTypeException {
83         if(parent == ROOT) {
84             // 1) get watches
85
Watch [] ws = DebuggerManager.getDebuggerManager().getWatches();
86             to = Math.min(ws.length, to);
87             from = Math.min(ws.length, from);
88             Watch [] fws = new Watch [to - from];
89             System.arraycopy(ws, from, fws, 0, to - from);
90
91             // 2) create ScriptWatchEvaluating for Watches
92
int i, k = fws.length;
93             ScriptWatchEvaluating[] jws = new ScriptWatchEvaluating[k];
94             for(i = 0; i < k; i++) {
95                 ScriptWatchEvaluating jw = watchToValue.get(fws[i]);
96                 if(jw == null) {
97                     jw = new ScriptWatchEvaluating(this, fws[i], debugger);
98                     watchToValue.put(fws[i], jw);
99                 }
100                 jws[i] = jw;
101
102                 // The actual expressions are computed on demand in ScriptWatchEvaluating
103
}
104
105             if(listener == null) {
106                 listener = new Listener JavaDoc(this, debugger);
107             }
108             return jws;
109         }
110         else if(parent instanceof VariableNode) {
111             return getLocalsTreeModel().getChildren(parent, from, to);
112         }
113         return getLocalsTreeModel().getChildren(parent, from, to);
114     }
115
116     /**
117      * Returns number of children for given node.
118      *
119      * @param node the parent node
120      * @throws UnknownTypeException if this TreeModel implementation is not
121      * able to resolve children for given node type
122      *
123      * @return true if node is leaf
124      */

125     public int getChildrenCount(Object JavaDoc node) throws UnknownTypeException {
126         if(node == ROOT) {
127             if(listener == null) {
128                 listener = new Listener JavaDoc(this, debugger);
129             }
130             // Performance, see issue #59058.
131
return Integer.MAX_VALUE; // DebuggerManager.getDebuggerManager().getWatches().length;
132
}
133         else if(node instanceof VariableNode) {
134             return getLocalsTreeModel().getChildrenCount(node);
135         }
136
137         return getLocalsTreeModel().getChildrenCount(node);
138     }
139
140     public boolean isLeaf(Object JavaDoc node) throws UnknownTypeException {
141         if(node == ROOT) {
142             return false;
143         }
144         else if(node instanceof VariableNode) {
145             return ((VariableNode) node).isLeaf();
146         }
147
148         return getLocalsTreeModel().isLeaf(node);
149     }
150
151     // ------------------------------------------------------------------------
152
// TableModel implementation
153
// ------------------------------------------------------------------------
154
public Object JavaDoc getValueAt(Object JavaDoc node, String JavaDoc columnID) throws UnknownTypeException {
155         if(Constants.WATCH_TYPE_COLUMN_ID.equals(columnID)) {
156             if(node instanceof VariableNode) {
157                 String JavaDoc className = ((VariableNode)node).getTypeName();
158                 return (className == null) ? "" : className;
159             }
160             else if(node instanceof JToolTip JavaDoc) {
161                 // This is how tooltips are implemented in the debugger views.
162
Object JavaDoc row = ((JToolTip JavaDoc)node).getClientProperty("getShortDescription");
163                 
164                 if(row instanceof VariableNode) {
165                     if(row instanceof Refreshable JavaDoc && !((Refreshable JavaDoc) row).isCurrent()) {
166                         return "";
167                     }
168                     return ((VariableNode)row).getTypeName();
169                 }
170             }
171         }
172         else if(Constants.WATCH_VALUE_COLUMN_ID.equals(columnID)) {
173             if(node instanceof VariableNode) {
174                 Object JavaDoc value = ((VariableNode)node).getValue();
175                 return value == null ? "null" : value;
176             }
177         }
178
179         throw new UnknownTypeException(node);
180     }
181
182     public boolean isReadOnly(Object JavaDoc node, String JavaDoc string) throws UnknownTypeException {
183         return true;
184     }
185
186     public void setValueAt(Object JavaDoc node, String JavaDoc string, Object JavaDoc value) throws UnknownTypeException {
187         throw new UnknownTypeException(node);
188     }
189
190     // ------------------------------------------------------------------------
191
// NodeModel implementation
192
// ------------------------------------------------------------------------
193
public String JavaDoc getDisplayName(Object JavaDoc node) throws UnknownTypeException {
194         if (node == null) {
195             return "null";
196         }
197         else if (node == ROOT) {
198             return ROOT;
199         }
200         else if (node instanceof VariableNode) {
201             return ((VariableNode)node).getDisplayName();
202         }
203         
204         throw new UnknownTypeException(node);
205     }
206
207     public String JavaDoc getIconBase(Object JavaDoc node) throws UnknownTypeException {
208         if (node == null || node == ROOT) {
209             return VariableNode.LOCAL_VARIABLE_ICON;
210         }
211         else if (node instanceof VariableNode) {
212             return ((VariableNode)node).getIconBase();
213         }
214         
215         throw new UnknownTypeException(node);
216     }
217
218     public String JavaDoc getShortDescription(Object JavaDoc node) throws UnknownTypeException {
219         if (node == null || node == ROOT) {
220             return null;
221         }
222         else if (node instanceof VariableNode) {
223             return ((VariableNode)node).getShortDescription();
224         }
225         
226         throw new UnknownTypeException(node);
227     }
228
229
230     public void addModelListener(ModelListener l) {
231         listeners.add(l);
232     }
233
234     public void removeModelListener(ModelListener l) {
235         listeners.remove(l);
236     }
237
238     private void fireTreeChanged() {
239         synchronized(watchToValue) {
240             for (ScriptWatchEvaluating swe : watchToValue.values()) {
241                 swe.setEvaluated(null);
242             }
243         }
244         
245         fireModelChanged(new ModelEvent.TreeChanged(this));
246     }
247
248     private void fireWatchesChanged() {
249         fireModelChanged(new ModelEvent.NodeChanged(this, ROOT, ModelEvent.NodeChanged.CHILDREN_MASK));
250     }
251
252     void fireTableValueChangedChanged(Object JavaDoc node, String JavaDoc propertyName) {
253         ((ScriptWatchEvaluating) node).setEvaluated(null);
254         fireTableValueChangedComputed(node, propertyName);
255     }
256
257     void fireTableValueChangedComputed(Object JavaDoc node, String JavaDoc propertyName) {
258         fireModelChanged(new ModelEvent.TableValueChanged(this, node, propertyName));
259         
260     }
261
262     private void fireModelChanged(ModelEvent event) {
263         Vector<ModelListener> v = new Vector<ModelListener>();
264         
265         synchronized (listeners) {
266             v = new Vector<ModelListener>(listeners);
267         }
268         
269         for (ModelListener ml : v) {
270             ml.modelChanged(event);
271         }
272     }
273
274     // other methods ...........................................................
275

276     DbgDebuggerImpl getDebugger() {
277         return debugger;
278     }
279
280     private volatile VariablesModel localsModel;
281
282     private VariablesModel getLocalsTreeModel() {
283         if(localsModel == null) {
284             localsModel = debugger != null ? debugger.getVariablesModel() : null;
285         }
286         return localsModel;
287     }
288
289     /** Current stack frame used to evaluate all non-fixed watches (fixed watches
290      * have a their own stack frame).
291      */

292     public DebugFrame getCurrentFrame() {
293         return currentFrame;
294     }
295
296     /** Changes the current stack frame and reevaluates the watch pane. Passing
297      * in null will leave all watches unevaluated (e.g. Debug | Continue) but
298      * watch expressions remain visible.
299      */

300     public void setStackFrame(DebugFrame frame) {
301         currentFrame = frame;
302         fireTreeChanged();
303     }
304
305
306     // innerclasses ............................................................
307

308     static class ScriptWatchEvaluating
309             implements VariableNode, Refreshable JavaDoc, PropertyChangeListener JavaDoc {
310
311         private WatchesModel model;
312         private Watch w;
313         private DbgDebuggerImpl debugger;
314         private VariableNode evaluatedWatch;
315
316         private boolean [] evaluating = new boolean [] { false };
317         private PropertyChangeSupport JavaDoc propSupp = new PropertyChangeSupport JavaDoc(this);
318
319         public ScriptWatchEvaluating(WatchesModel model, Watch w, DbgDebuggerImpl debugger) {
320             this.model = model;
321             this.w = w;
322             this.debugger = debugger;
323
324             parseExpression(w.getExpression());
325         }
326
327         private void parseExpression(String JavaDoc exprStr) {
328             setEvaluated(debugger.evaluateExpr(model.getCurrentFrame(), exprStr));
329         }
330
331         public void setEvaluated(VariableNode evaluatedWatch) {
332             synchronized(this) {
333                 this.evaluatedWatch = evaluatedWatch;
334             }
335         }
336
337         synchronized VariableNode getEvaluatedWatch() {
338             return evaluatedWatch;
339         }
340
341         public void expressionChanged() {
342             setEvaluated(null);
343             parseExpression(w.getExpression());
344         }
345
346         public synchronized String JavaDoc getExceptionDescription() {
347             return null;
348         }
349
350         public synchronized String JavaDoc getExpression() {
351             return w.getExpression();
352         }
353
354
355         public synchronized void remove() {
356             w.remove();
357         }
358
359         public void setExpression(String JavaDoc expression) {
360             w.setExpression(expression);
361             expressionChanged();
362         }
363
364         public synchronized void setValue(String JavaDoc value) { // throws InvalidExpressionException {
365
// if(evaluatedWatch != null) {
366
// evaluatedWatch.setValue(value);
367
// } else {
368
// throw new InvalidExpressionException("Can not set value while evaluating.");
369
// }
370
// !PW FIXME Cannot set values yet.
371
}
372
373         private VariableNode getUpdatedEvaluatedWatch() {
374             synchronized(this) {
375                 VariableNode evaluatedWatch = this.evaluatedWatch;
376             }
377             if(evaluatedWatch == null) {
378                 getValue(); // To init the evaluatedWatch
379
}
380             return evaluatedWatch;
381         }
382
383         // --------------------------------------------------------------------
384
// VariableNode
385
// --------------------------------------------------------------------
386
public String JavaDoc getName() {
387             return w.getExpression();
388         }
389
390         public String JavaDoc getDisplayName() {
391             return w.getExpression();
392         }
393
394         public String JavaDoc getShortDescription() {
395             return w.getExpression();
396         }
397
398         public String JavaDoc getIconBase() {
399             return WATCH_ICON;
400         }
401
402         public int getType() {
403             return TYPE_WATCH;
404         }
405
406         public String JavaDoc getTypeName() {
407             VariableNode evalWatch = getUpdatedEvaluatedWatch();
408             return evalWatch != null ? evalWatch.getTypeName() : "Evaluating...";
409         }
410
411         public String JavaDoc getValue() {
412             synchronized(evaluating) {
413                 if(evaluating[0]) {
414                     try {
415                         evaluating.wait();
416                     } catch(InterruptedException JavaDoc iex) {
417                         return null;
418                     }
419                 }
420                 synchronized(this) {
421                     if(evaluatedWatch != null) {
422                         Object JavaDoc value = evaluatedWatch.getValue();
423                         return(value != null) ? value.toString() : null;
424                     }
425                 }
426                 evaluating[0] = true;
427             }
428
429             VariableNode vn = null;
430             try {
431                 vn = debugger.evaluateExpr(model.getCurrentFrame(), w.getExpression());
432             } finally {
433                 setEvaluated(vn);
434                 synchronized(evaluating) {
435                     evaluating[0] = false;
436                     evaluating.notifyAll();
437                 }
438             }
439
440             Object JavaDoc value = (vn != null) ? vn.getValue() : "no value yet...";
441             return (value != null) ? value.toString() : null;
442         }
443
444         public String JavaDoc getTooltipValue() {
445             Object JavaDoc v = getValue();
446             return (v != null) ? v.toString() : null;
447         }
448
449         public VariableNode[] getChildren(int from, int to) {
450             VariableNode evalWatch = getUpdatedEvaluatedWatch();
451             return evalWatch != null ? evalWatch.getChildren(from, to) : new VariableNode[0];
452         }
453
454         public boolean isLeaf() {
455             VariableNode evalWatch = getUpdatedEvaluatedWatch();
456             return evalWatch != null ? evalWatch.isLeaf() : false;
457         }
458
459         public int getChildrenCount() {
460             VariableNode evalWatch = getUpdatedEvaluatedWatch();
461             return evalWatch != null ? evalWatch.getChildrenCount() : 0;
462         }
463
464         public boolean isReadOnly() {
465             return true;
466         }
467         
468         public void collectUpdates(Object JavaDoc source,
469                                Collection<ModelEvent> events,
470                                VariableNode newVar) {
471             throw new IllegalStateException JavaDoc("This API valid on VariableNodeImpl only");
472         }
473
474         // --------------------------------------------------------------------
475
// PropertyChange support
476
// --------------------------------------------------------------------
477
public void addPropertyChangeListener(PropertyChangeListener JavaDoc l) {
478             propSupp.addPropertyChangeListener(l);
479         }
480
481         public void removePropertyChangeListener(PropertyChangeListener JavaDoc l) {
482             propSupp.removePropertyChangeListener(l);
483         }
484
485
486         // --------------------------------------------------------------------
487
// PropertyChangeListener
488
// --------------------------------------------------------------------
489
public void propertyChange(PropertyChangeEvent JavaDoc evt) {
490             model.fireTableValueChangedChanged(this, null);
491         }
492
493
494         // --------------------------------------------------------------------
495
// Refreshable
496
// --------------------------------------------------------------------
497
/** Does wait for the value to be evaluated. */
498         public void refresh() throws RefreshFailedException JavaDoc {
499             synchronized(evaluating) {
500                 if(evaluating[0]) {
501                     try {
502                         evaluating.wait();
503                     } catch(InterruptedException JavaDoc iex) {
504                         throw new RefreshFailedException JavaDoc(iex.getLocalizedMessage());
505                     }
506                 }
507             }
508         }
509
510         /** Tells whether the variable is fully initialized and getValue()
511          * returns the value immediately. */

512         public synchronized boolean isCurrent() {
513             return evaluatedWatch != null;
514         }
515 }
516
517     private static class Listener extends DebuggerManagerAdapter
518             implements PropertyChangeListener JavaDoc {
519
520         private WeakReference JavaDoc<WatchesModel> model;
521         private WeakReference JavaDoc<DbgDebuggerImpl> debugger;
522
523         private Listener(
524             WatchesModel tm,
525             DbgDebuggerImpl debugger
526         ) {
527             model = new WeakReference JavaDoc<WatchesModel>(tm);
528             this.debugger = new WeakReference JavaDoc<DbgDebuggerImpl>(debugger);
529             DebuggerManager.getDebuggerManager().addDebuggerListener(
530                 DebuggerManager.PROP_WATCHES,
531                 this
532             );
533 // debugger.addPropertyChangeListener(this);
534
Watch[] ws = DebuggerManager.getDebuggerManager().getWatches();
535             int i, k = ws.length;
536             for(i = 0; i < k; i++) {
537                 ws [i].addPropertyChangeListener(this);
538             }
539         }
540
541         private WatchesModel getModel() {
542             WatchesModel m = model.get();
543             if(m == null) {
544                 destroy();
545             }
546             return m;
547         }
548
549         public void watchAdded(Watch watch) {
550             WatchesModel m = getModel();
551             if(m == null) {
552                 return;
553             }
554             watch.addPropertyChangeListener(this);
555             m.fireWatchesChanged();
556         }
557
558         public void watchRemoved(Watch watch) {
559             WatchesModel m = getModel();
560             if(m == null) {
561                 return;
562             }
563             watch.removePropertyChangeListener(this);
564             m.fireWatchesChanged();
565         }
566
567         // currently waiting / running refresh task
568
// there is at most one
569
private RequestProcessor.Task task;
570
571         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
572             String JavaDoc propName = evt.getPropertyName();
573             // We already have watchAdded & watchRemoved. Ignore PROP_WATCHES:
574
if(DebuggerManager.PROP_WATCHES.equals(propName)) {
575                 return;
576             }
577             final WatchesModel m = getModel();
578             if(m == null) {
579                 return;
580             }
581 // if(m.debugger.getState() == JPDADebugger.STATE_DISCONNECTED) {
582
// destroy();
583
// return;
584
// }
585
// if(m.debugger.getState() == JPDADebugger.STATE_RUNNING) {
586
// return ;
587
// }
588

589             if(evt.getSource() instanceof Watch) {
590                 Object JavaDoc node;
591                 synchronized(m.watchToValue) {
592                     node = m.watchToValue.get(evt.getSource());
593                 }
594                 if(node != null) {
595                     m.fireTableValueChangedChanged(node, null);
596                     return ;
597                 }
598             }
599
600             if(task == null) {
601                 task = RequestProcessor.getDefault().create(new Runnable JavaDoc() {
602                     public void run() {
603                         System.err.println("WM do task " + task);
604                         m.fireTreeChanged();
605                     }
606                 });
607                 System.err.println("WM create task " + task);
608             }
609             task.schedule(100);
610         }
611
612         private void destroy() {
613             DebuggerManager.getDebuggerManager().removeDebuggerListener(
614                 DebuggerManager.PROP_WATCHES,
615                 this
616             );
617             DbgDebuggerImpl d = debugger.get();
618             if(d != null) {
619 // d.removePropertyChangeListener(this);
620
}
621
622             Watch[] ws = DebuggerManager.getDebuggerManager().getWatches();
623             int i, k = ws.length;
624             for(i = 0; i < k; i++) {
625                 ws [i].removePropertyChangeListener(this);
626             }
627
628             if(task != null) {
629                 // cancel old task
630
task.cancel();
631                 System.err.println("WM cancel old task " + task);
632                 task = null;
633             }
634         }
635     }
636 }
637
Popular Tags