KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > JTop


1 /*
2  * @(#)JTop.java 1.5 06/05/08
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 /*
38  * @(#)JTop.java 1.5 06/05/08
39  *
40  * Example of using the java.lang.management API to sort threads
41  * by CPU usage.
42  *
43  * JTop class can be run as a standalone application.
44  * It first establishs a connection to a target VM specified
45  * by the given hostname and port number where the JMX agent
46  * to be connected. It then polls for the thread information
47  * and the CPU consumption of each thread to display every 2
48  * seconds.
49  *
50  * It is also used by JTopPlugin which is a JConsolePlugin
51  * that can be used with JConsole (see README.txt). The JTop
52  * GUI will be added as a JConsole tab by the JTop plugin.
53  *
54  * @see com.sun.tools.jconsole.JConsolePlugin
55  *
56  * @author Mandy Chung
57  */

58 import java.lang.management.*;
59 import javax.management.*;
60 import javax.management.remote.*;
61 import java.io.IOException JavaDoc;
62 import java.util.ArrayList JavaDoc;
63 import java.util.Collections JavaDoc;
64 import java.util.List JavaDoc;
65 import java.util.Map JavaDoc;
66 import java.util.Map.Entry;
67 import java.util.Set JavaDoc;
68 import java.util.SortedMap JavaDoc;
69 import java.util.Timer JavaDoc;
70 import java.util.TimerTask JavaDoc;
71 import java.util.TreeMap JavaDoc;
72 import java.util.concurrent.ExecutionException JavaDoc;
73 import java.text.NumberFormat JavaDoc;
74 import java.net.MalformedURLException JavaDoc;
75 import static java.lang.management.ManagementFactory JavaDoc.*;
76
77 import java.awt.*;
78 import java.awt.event.*;
79 import javax.swing.*;
80 import javax.swing.border.*;
81 import javax.swing.event.*;
82 import javax.swing.table.*;
83
84 /**
85  * JTop is a JPanel to display thread's name, CPU time, and its state
86  * in a table.
87  */

88 public class JTop extends JPanel {
89     private MBeanServerConnection server;
90     private ThreadMXBean tmbean;
91     private MyTableModel tmodel;
92     public JTop() {
93         super(new GridLayout(1,0));
94
95         tmodel = new MyTableModel();
96         JTable table = new JTable(tmodel);
97         table.setPreferredScrollableViewportSize(new Dimension(500, 300));
98
99         // Set the renderer to format Double
100
table.setDefaultRenderer(Double JavaDoc.class, new DoubleRenderer());
101         // Add some space
102
table.setIntercellSpacing(new Dimension(6,3));
103         table.setRowHeight(table.getRowHeight() + 4);
104
105         // Create the scroll pane and add the table to it.
106
JScrollPane scrollPane = new JScrollPane(table);
107
108         // Add the scroll pane to this panel.
109
add(scrollPane);
110     }
111
112     // Set the MBeanServerConnection object for communicating
113
// with the target VM
114
public void setMBeanServerConnection(MBeanServerConnection mbs) {
115         this.server = mbs;
116         try {
117             this.tmbean = newPlatformMXBeanProxy(server,
118                                                  THREAD_MXBEAN_NAME,
119                                                  ThreadMXBean.class);
120         } catch (IOException JavaDoc e) {
121             e.printStackTrace();
122         }
123         if (!tmbean.isThreadCpuTimeSupported()) {
124             System.err.println("This VM does not support thread CPU time monitoring");
125         } else {
126             tmbean.setThreadCpuTimeEnabled(true);
127         }
128     }
129
130     class MyTableModel extends AbstractTableModel {
131         private String JavaDoc[] columnNames = {"ThreadName",
132                                         "CPU(sec)",
133                                         "State"};
134         // List of all threads. The key of each entry is the CPU time
135
// and its value is the ThreadInfo object with no stack trace.
136
private List JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>> threadList =
137             Collections.EMPTY_LIST;
138
139         public MyTableModel() {
140         }
141
142         public int getColumnCount() {
143             return columnNames.length;
144         }
145
146         public int getRowCount() {
147             return threadList.size();
148         }
149
150         public String JavaDoc getColumnName(int col) {
151             return columnNames[col];
152         }
153
154         public Object JavaDoc getValueAt(int row, int col) {
155             Map.Entry JavaDoc<Long JavaDoc, ThreadInfo> me = threadList.get(row);
156             switch (col) {
157                 case 0 :
158                     // Column 0 shows the thread name
159
return me.getValue().getThreadName();
160                 case 1 :
161                     // Column 1 shows the CPU usage
162
long ns = me.getKey().longValue();
163                     double sec = ns / 1000000000;
164                     return new Double JavaDoc(sec);
165                 case 2 :
166                     // Column 2 shows the thread state
167
return me.getValue().getThreadState();
168                 default:
169                     return null;
170             }
171         }
172
173         public Class JavaDoc getColumnClass(int c) {
174             return getValueAt(0, c).getClass();
175         }
176
177         void setThreadList(List JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>> list) {
178             threadList = list;
179         }
180     }
181
182     /**
183      * Get the thread list with CPU consumption and the ThreadInfo
184      * for each thread sorted by the CPU time.
185      */

186     private List JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>> getThreadList() {
187         // Get all threads and their ThreadInfo objects
188
// with no stack trace
189
long[] tids = tmbean.getAllThreadIds();
190         ThreadInfo[] tinfos = tmbean.getThreadInfo(tids);
191
192         // build a map with key = CPU time and value = ThreadInfo
193
SortedMap JavaDoc<Long JavaDoc, ThreadInfo> map = new TreeMap JavaDoc<Long JavaDoc, ThreadInfo>();
194         for (int i = 0; i < tids.length; i++) {
195             long cpuTime = tmbean.getThreadCpuTime(tids[i]);
196             // filter out threads that have been terminated
197
if (cpuTime != -1 && tinfos[i] != null) {
198                 map.put(new Long JavaDoc(cpuTime), tinfos[i]);
199             }
200         }
201
202         // build the thread list and sort it with CPU time
203
// in decreasing order
204
Set JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>> set = map.entrySet();
205         List JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>> list =
206             new ArrayList JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>>(set);
207         Collections.reverse(list);
208         return list;
209     }
210
211
212     /**
213      * Format Double with 4 fraction digits
214      */

215     class DoubleRenderer extends DefaultTableCellRenderer {
216         NumberFormat JavaDoc formatter;
217         public DoubleRenderer() {
218             super();
219             setHorizontalAlignment(JLabel.RIGHT);
220         }
221     
222         public void setValue(Object JavaDoc value) {
223             if (formatter==null) {
224                 formatter = NumberFormat.getInstance();
225                 formatter.setMinimumFractionDigits(4);
226             }
227             setText((value == null) ? "" : formatter.format(value));
228         }
229     }
230
231     // SwingWorker responsible for updating the GUI
232
//
233
// It first gets the thread and CPU usage information as a
234
// background task done by a worker thread so that
235
// it will not block the event dispatcher thread.
236
//
237
// When the worker thread finishes, the event dispatcher
238
// thread will invoke the done() method which will update
239
// the UI.
240
class Worker extends SwingWorker<List JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>>,Object JavaDoc> {
241         private MyTableModel tmodel;
242         Worker(MyTableModel tmodel) {
243             this.tmodel = tmodel;
244         }
245
246         // Get the current thread info and CPU time
247
public List JavaDoc<Map.Entry JavaDoc<Long JavaDoc, ThreadInfo>> doInBackground() {
248             return getThreadList();
249         }
250                                                                                 
251         // fire table data changed to trigger GUI update
252
// when doInBackground() is finished
253
protected void done() {
254             try {
255                 // Set table model with the new thread list
256
tmodel.setThreadList(get());
257                 // refresh the table model
258
tmodel.fireTableDataChanged();
259             } catch (InterruptedException JavaDoc e) {
260             } catch (ExecutionException JavaDoc e) {
261             }
262         }
263     }
264
265     // Return a new SwingWorker for UI update
266
public SwingWorker<?,?> newSwingWorker() {
267         return new Worker(tmodel);
268     }
269
270     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
271         // Validate the input arguments
272
if (args.length != 1) {
273             usage();
274         }
275
276         String JavaDoc[] arg2 = args[0].split(":");
277         if (arg2.length != 2) {
278             usage();
279         }
280         String JavaDoc hostname = arg2[0];
281         int port = -1;
282         try {
283             port = Integer.parseInt(arg2[1]);
284         } catch (NumberFormatException JavaDoc x) {
285             usage();
286         }
287         if (port < 0) {
288             usage();
289         }
290
291         // Create the JTop Panel
292
final JTop jtop = new JTop();
293         // Set up the MBeanServerConnection to the target VM
294
MBeanServerConnection server = connect(hostname, port);
295         jtop.setMBeanServerConnection(server);
296
297         // A timer task to update GUI per each interval
298
TimerTask JavaDoc timerTask = new TimerTask JavaDoc() {
299             public void run() {
300                 // Schedule the SwingWorker to update the GUI
301
jtop.newSwingWorker().execute();
302             }
303     };
304
305         // Create the standalone window with JTop panel
306
// by the event dispatcher thread
307
SwingUtilities.invokeAndWait(new Runnable JavaDoc() {
308             public void run() {
309                 createAndShowGUI(jtop);
310             }
311         });
312
313         // refresh every 2 seconds
314
Timer JavaDoc timer = new Timer JavaDoc("JTop Sampling thread");
315     timer.schedule(timerTask, 0, 2000);
316
317     }
318
319     // Establish a connection with the remote application
320
//
321
// You can modify the urlPath to the address of the JMX agent
322
// of your application if it has a different URL.
323
//
324
// You can also modify the following code to take
325
// username and password for client authentication.
326
private static MBeanServerConnection connect(String JavaDoc hostname, int port) {
327         // Create an RMI connector client and connect it to
328
// the RMI connector server
329
String JavaDoc urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
330         MBeanServerConnection server = null;
331         try {
332             JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
333             JMXConnector jmxc = JMXConnectorFactory.connect(url);
334             server = jmxc.getMBeanServerConnection();
335         } catch (MalformedURLException JavaDoc e) {
336             // should not reach here
337
} catch (IOException JavaDoc e) {
338             System.err.println("\nCommunication error: " + e.getMessage());
339             System.exit(1);
340         }
341         return server;
342     }
343
344     private static void usage() {
345         System.out.println("Usage: java JTop <hostname>:<port>");
346         System.exit(1);
347     }
348     /**
349      * Create the GUI and show it. For thread safety,
350      * this method should be invoked from the
351      * event-dispatching thread.
352      */

353     private static void createAndShowGUI(JPanel jtop) {
354         // Create and set up the window.
355
JFrame frame = new JFrame("JTop");
356         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
357
358         // Create and set up the content pane.
359
JComponent contentPane = (JComponent) frame.getContentPane();
360         contentPane.add(jtop, BorderLayout.CENTER);
361         contentPane.setOpaque(true); //content panes must be opaque
362
contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
363         frame.setContentPane(contentPane);
364
365         // Display the window.
366
frame.pack();
367         frame.setVisible(true);
368     }
369
370 }
371
Popular Tags