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
26package sun.tools.jconsole;
27
28import java.awt.*;
29import java.awt.event.*;
30import java.io.*;
31import java.lang.management.*;
32import java.lang.reflect.*;
33
34import javax.swing.*;
35import javax.swing.border.*;
36
37
38import java.util.concurrent.*;
39
40import static sun.tools.jconsole.Formatter.*;
41import static sun.tools.jconsole.Utilities.*;
42
43
44@SuppressWarnings("serial")
45class 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
80    public static String getTabName() {
81        return Messages.CLASSES;
82    }
83
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
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
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
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 {
238        ClassOverviewPanel() {
239            super(Messages.CLASSES, loadedPlotterKey, Messages.LOADED, null);
240        }
241
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