1 /*
2  * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.tools.jconsole;
27 
28 import java.awt.*;
29 import java.awt.event.*;
30 import java.io.*;
31 import java.lang.management.*;
32 import java.lang.reflect.*;
33 
34 import javax.swing.*;
35 import javax.swing.border.*;
36 
37 
38 import java.util.concurrent.*;
39 
40 import static sun.tools.jconsole.Formatter.*;
41 import static sun.tools.jconsole.Utilities.*;
42 
43 
44 @SuppressWarnings("serial")
45 class ClassTab extends Tab implements ActionListener {
46     PlotterPanel loadedClassesMeter;
47     TimeComboBox timeComboBox;
48     private JCheckBox verboseCheckBox;
49     private HTMLPane details;
50     private ClassOverviewPanel overviewPanel;
51     private boolean plotterListening = false;
52 
53     private static final String loadedPlotterKey        = "loaded";
54     private static final String totalLoadedPlotterKey   = "totalLoaded";
55     private static final Color  loadedPlotterColor      = Plotter.defaultColor;
56     private static final Color  totalLoadedPlotterColor = Color.red;
57 
58     /*
59       Hierarchy of panels and layouts for this tab:
60 
61         ClassTab (BorderLayout)
62 
63             North:  topPanel (BorderLayout)
64 
65                         Center: controlPanel (FlowLayout)
66                                     timeComboBox
67 
68                         East:   topRightPanel (FlowLayout)
69                                     verboseCheckBox
70 
71             Center: plotterPanel (BorderLayout)
72 
73                         Center: plotter
74 
75             South:  bottomPanel (BorderLayout)
76 
77                         Center: details
78     */
79 
getTabName()80     public static String getTabName() {
81         return Messages.CLASSES;
82     }
83 
ClassTab(VMPanel vmPanel)84     public ClassTab(VMPanel vmPanel) {
85         super(vmPanel, getTabName());
86 
87         setLayout(new BorderLayout(0, 0));
88         setBorder(new EmptyBorder(4, 4, 3, 4));
89 
90         JPanel topPanel     = new JPanel(new BorderLayout());
91         JPanel plotterPanel = new JPanel(new BorderLayout());
92         JPanel bottomPanel  = new JPanel(new BorderLayout());
93 
94         add(topPanel,     BorderLayout.NORTH);
95         add(plotterPanel, BorderLayout.CENTER);
96         add(bottomPanel,  BorderLayout.SOUTH);
97 
98         JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 5));
99         topPanel.add(controlPanel, BorderLayout.CENTER);
100 
101         verboseCheckBox = new JCheckBox(Messages.VERBOSE_OUTPUT);
102         verboseCheckBox.addActionListener(this);
103         verboseCheckBox.setToolTipText(Messages.VERBOSE_OUTPUT_TOOLTIP);
104         JPanel topRightPanel = new JPanel();
105         topRightPanel.setBorder(new EmptyBorder(0, 65-8, 0, 70));
106         topRightPanel.add(verboseCheckBox);
107         topPanel.add(topRightPanel, BorderLayout.AFTER_LINE_ENDS);
108 
109         loadedClassesMeter = new PlotterPanel(Messages.NUMBER_OF_LOADED_CLASSES,
110                                               Plotter.Unit.NONE, false);
111         loadedClassesMeter.plotter.createSequence(loadedPlotterKey,
112                                                   Messages.LOADED,
113                                                   loadedPlotterColor,
114                                                   true);
115         loadedClassesMeter.plotter.createSequence(totalLoadedPlotterKey,
116                                                   Messages.TOTAL_LOADED,
117                                                   totalLoadedPlotterColor,
118                                                   true);
119         setAccessibleName(loadedClassesMeter.plotter,
120                           Messages.CLASS_TAB_LOADED_CLASSES_PLOTTER_ACCESSIBLE_NAME);
121         plotterPanel.add(loadedClassesMeter);
122 
123         timeComboBox = new TimeComboBox(loadedClassesMeter.plotter);
124         controlPanel.add(new LabeledComponent(Messages.TIME_RANGE_COLON,
125                                               Resources.getMnemonicInt(Messages.TIME_RANGE_COLON),
126                                               timeComboBox));
127 
128         LabeledComponent.layout(plotterPanel);
129 
130         bottomPanel.setBorder(new CompoundBorder(new TitledBorder(Messages.DETAILS),
131                                                  new EmptyBorder(10, 10, 10, 10)));
132 
133         details = new HTMLPane();
134         setAccessibleName(details, Messages.DETAILS);
135         JScrollPane scrollPane = new JScrollPane(details);
136         scrollPane.setPreferredSize(new Dimension(0, 150));
137         bottomPanel.add(scrollPane, BorderLayout.SOUTH);
138 
139     }
140 
actionPerformed(ActionEvent ev)141     public void actionPerformed(ActionEvent ev) {
142         final boolean b = verboseCheckBox.isSelected();
143         workerAdd(new Runnable() {
144             public void run() {
145                 ProxyClient proxyClient = vmPanel.getProxyClient();
146                 try {
147                     proxyClient.getClassLoadingMXBean().setVerbose(b);
148                 } catch (UndeclaredThrowableException e) {
149                     proxyClient.markAsDead();
150                 } catch (IOException ex) {
151                     // Ignore
152                 }
153             }
154         });
155     }
156 
157 
newSwingWorker()158     public SwingWorker<?, ?> newSwingWorker() {
159         final ProxyClient proxyClient = vmPanel.getProxyClient();
160 
161         if (!plotterListening) {
162             proxyClient.addWeakPropertyChangeListener(loadedClassesMeter.plotter);
163             plotterListening = true;
164         }
165 
166         return new SwingWorker<Boolean, Object>() {
167             private long clCount, cuCount, ctCount;
168             private boolean isVerbose;
169             private String detailsStr;
170             private long timeStamp;
171 
172             public Boolean doInBackground() {
173                 try {
174                     ClassLoadingMXBean classLoadingMBean = proxyClient.getClassLoadingMXBean();
175 
176                     clCount = classLoadingMBean.getLoadedClassCount();
177                     cuCount = classLoadingMBean.getUnloadedClassCount();
178                     ctCount = classLoadingMBean.getTotalLoadedClassCount();
179                     isVerbose = classLoadingMBean.isVerbose();
180                     detailsStr = formatDetails();
181                     timeStamp = System.currentTimeMillis();
182 
183                     return true;
184                 } catch (UndeclaredThrowableException e) {
185                     proxyClient.markAsDead();
186                     return false;
187                 } catch (IOException e) {
188                     return false;
189                 }
190             }
191 
192             protected void done() {
193                 try {
194                     if (get()) {
195                         loadedClassesMeter.plotter.addValues(timeStamp, clCount, ctCount);
196 
197                         if (overviewPanel != null) {
198                             overviewPanel.updateClassInfo(ctCount, clCount);
199                             overviewPanel.getPlotter().addValues(timeStamp, clCount);
200                         }
201 
202                         loadedClassesMeter.setValueLabel(clCount + "");
203                         verboseCheckBox.setSelected(isVerbose);
204                         details.setText(detailsStr);
205                     }
206                 } catch (InterruptedException ex) {
207                 } catch (ExecutionException ex) {
208                     if (JConsole.isDebug()) {
209                         ex.printStackTrace();
210                     }
211                 }
212             }
213 
214             private String formatDetails() {
215                 String text = "<table cellspacing=0 cellpadding=0>";
216 
217                 long time = System.currentTimeMillis();
218                 String timeStamp = formatDateTime(time);
219                 text += newRow(Messages.TIME, timeStamp);
220                 text += newRow(Messages.CURRENT_CLASSES_LOADED, justify(clCount, 5));
221                 text += newRow(Messages.TOTAL_CLASSES_LOADED,   justify(ctCount, 5));
222                 text += newRow(Messages.TOTAL_CLASSES_UNLOADED, justify(cuCount, 5));
223 
224                 return text;
225             }
226         };
227     }
228 
229 
getOverviewPanels()230     OverviewPanel[] getOverviewPanels() {
231         if (overviewPanel == null) {
232             overviewPanel = new ClassOverviewPanel();
233         }
234         return new OverviewPanel[] { overviewPanel };
235     }
236 
237     private static class ClassOverviewPanel extends OverviewPanel {
ClassOverviewPanel()238         ClassOverviewPanel() {
239             super(Messages.CLASSES, loadedPlotterKey, Messages.LOADED, null);
240         }
241 
updateClassInfo(long total, long loaded)242         private void updateClassInfo(long total, long loaded) {
243             long unloaded = (total - loaded);
244             getInfoLabel().setText(Resources.format(Messages.CLASS_TAB_INFO_LABEL_FORMAT,
245                                    loaded, unloaded, total));
246         }
247     }
248 }
249