1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.ui.swing;
20
21 import java.awt.BorderLayout;
22 import java.awt.Dimension;
23 import java.awt.Insets;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.awt.event.MouseEvent;
27 import java.awt.event.MouseListener;
28 import java.lang.ref.ReferenceQueue;
29 import java.lang.ref.WeakReference;
30
31 import javax.swing.JFrame;
32 import javax.swing.JLabel;
33 import javax.swing.JPanel;
34 import javax.swing.JScrollPane;
35 import javax.swing.JTable;
36 import javax.swing.border.EmptyBorder;
37 import javax.swing.table.TableColumn;
38
39 import net.wotonomy.foundation.NSArray;
40 import net.wotonomy.ui.EOAssociation;
41 import net.wotonomy.ui.EODisplayGroup;
42 import net.wotonomy.ui.swing.components.ButtonPanel;
43 import net.wotonomy.ui.swing.util.WindowUtilities;
44
45 /***
46 * ReferenceInspector tracks objects until they are garbage collected.
47 * Use it to track objects that you suspect are not being GCed.
48 * ReferenceInspector retains only weak references to the objects that
49 * it tracks, so when those weak references cannot be resolved, the
50 * object has been garbage collected. Note that under some GC
51 * implementations, adding a weak reference to an object will delay
52 * garbage collection for that object.
53 *
54 * @author michael@mpowers.net
55 * @version $Revision: 904 $
56 */
57
58 public class ReferenceInspector
59 implements MouseListener, ActionListener
60 {
61 protected JTable table;
62 protected JLabel memoryLabel;
63
64 static protected EODisplayGroup displayGroup;
65 static protected JFrame window;
66
67
68 private static ReferenceQueue queue = new ReferenceQueue();
69
70
71 static public final String COPY = "COPY";
72
73 /***
74 * Launches a new ReferenceInspector if one does not already exist.
75 */
76 public ReferenceInspector()
77 {
78 if ( window == null )
79 {
80 table = new JTable();
81 memoryLabel = new JLabel();
82
83 displayGroup = new EODisplayGroup();
84
85 TableColumn column;
86 TableColumnAssociation assoc;
87
88 column = new TableColumn();
89 column.setHeaderValue( "Object" );
90
91 assoc = new TableColumnAssociation( column );
92 assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "" );
93 assoc.setTable( table );
94 assoc.establishConnection();
95
96 column = new TableColumn();
97 column.setHeaderValue( "Address" );
98 column.setMaxWidth( 100 );
99
100 assoc = new TableColumnAssociation( column );
101 assoc.bindAspect( EOAssociation.ValueAspect, displayGroup, "identityHashCode" );
102 assoc.setTable( table );
103 assoc.establishConnection();
104
105 initLayout();
106 }
107 window.show();
108 }
109
110 /***
111 * Adds the specified object to the ReferenceInspector, launching
112 * a new ReferenceInspector if one does not already exist.
113 */
114 public ReferenceInspector( Object anObject )
115 {
116 this();
117 displayGroup.insertObjectAtIndex( new ExtendedWeakReference( anObject, queue ), 0 );
118 window.show();
119 }
120
121 protected void initLayout()
122 {
123 table.addMouseListener( this );
124
125 JPanel panel = new JPanel();
126 panel.setBorder( new EmptyBorder( new Insets( 10, 10, 10, 10 ) ) );
127 panel.setLayout( new BorderLayout( 10, 10 ) );
128
129 JScrollPane scrollPane = new JScrollPane( table );
130 scrollPane.setPreferredSize( new Dimension( 500, 250 ) );
131 panel.add( scrollPane, BorderLayout.CENTER );
132
133 ButtonPanel buttonPanel = new ButtonPanel( new String[] { "Update" } );
134 buttonPanel.addActionListener( this );
135
136 JPanel bottomPanel = new JPanel();
137 bottomPanel.setLayout( new BorderLayout() );
138 bottomPanel.add( buttonPanel, BorderLayout.EAST );
139 bottomPanel.add( memoryLabel, BorderLayout.CENTER );
140 panel.add( bottomPanel, BorderLayout.SOUTH );
141
142 window = new JFrame();
143 window.setTitle( "Reference Inspector" );
144 window.getContentPane().add( panel );
145
146
147
148
149 window.pack();
150 WindowUtilities.cascade( window );
151 window.show();
152 }
153
154
155
156
157
158
159 private static void processQueue()
160 {
161
162 synchronized ( displayGroup )
163 {
164 int idx;
165 WeakReference rk;
166 while ((rk = (WeakReference)queue.poll()) != null)
167 {
168
169 if ( rk != null )
170 {
171 idx = displayGroup.displayedObjects().indexOfIdenticalObject( rk );
172 if ( idx != NSArray.NotFound )
173 {
174 displayGroup.deleteObjectAtIndex( idx );
175 }
176 }
177 }
178 displayGroup.updateDisplayedObjects();
179 }
180 }
181
182
183
184 public void actionPerformed( ActionEvent evt )
185 {
186 Runtime runtime = Runtime.getRuntime();
187 runtime.gc();
188 processQueue();
189
190 long totalMemory = runtime.totalMemory() / 1024;
191 long freeMemory = runtime.freeMemory() / 1024;
192 memoryLabel.setText(
193 Long.toString( totalMemory - freeMemory ) + "K / " +
194 Long.toString( totalMemory ) + "K" );
195 }
196
197
198
199 /***
200 * Double click to launch object inspector.
201 */
202
203 public void mouseClicked(MouseEvent e)
204 {
205 if ( e.getSource() == table )
206 {
207 if ( e.getClickCount() > 1 )
208 {
209 int row = table.rowAtPoint( e.getPoint() );
210 int col = table.columnAtPoint( e.getPoint() );
211 col = table.convertColumnIndexToModel( col );
212
213 if ( row == -1 ) return;
214
215 if ( col == 0 )
216 {
217 }
218 else
219 {
220 }
221 }
222 }
223 }
224
225 public void mouseReleased(MouseEvent e) {}
226 public void mousePressed(MouseEvent e) {}
227 public void mouseEntered(MouseEvent e) {}
228 public void mouseExited(MouseEvent e) {}
229
230 public class ExtendedWeakReference extends WeakReference
231 {
232 public ExtendedWeakReference(Object referent, ReferenceQueue q)
233 {
234 super( referent, q );
235 }
236
237 public String toString()
238 {
239 if ( get() != null )
240 {
241 return get().toString();
242 }
243 return null;
244 }
245
246 public String identityHashCode()
247 {
248 if ( get() != null )
249 {
250 return Integer.toHexString( System.identityHashCode( get() ) );
251 }
252 return null;
253 }
254
255 }
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283