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.inspector;
27
28import java.awt.BorderLayout;
29import java.awt.Color;
30import java.awt.Component;
31import java.awt.GridLayout;
32import java.util.*;
33import javax.management.*;
34import javax.swing.*;
35import javax.swing.border.TitledBorder;
36import javax.swing.event.*;
37import javax.swing.table.*;
38
39import sun.tools.jconsole.Messages;
40
41import static sun.tools.jconsole.Utilities.*;
42
43@SuppressWarnings("serial")
44public class XMBeanInfo extends JPanel {
45
46    private static final Color lightYellow = new Color(255, 255, 128);
47     private final int NAME_COLUMN = 0;
48    private final int VALUE_COLUMN = 1;
49    private final String[] columnNames = {
50        Messages.NAME,
51        Messages.VALUE
52    };
53    private JTable infoTable = new JTable();
54    private JTable descTable = new JTable();
55    private JPanel infoBorderPanel = new JPanel(new BorderLayout());
56    private JPanel descBorderPanel = new JPanel(new BorderLayout());
57
58    private static class ReadOnlyDefaultTableModel extends DefaultTableModel {
59
60        @Override
61        public void setValueAt(Object value, int row, int col) {
62        }
63    }
64
65    private static class TableRowDivider {
66
67        private String tableRowDividerText;
68
69        public TableRowDivider(String tableRowDividerText) {
70            this.tableRowDividerText = tableRowDividerText;
71        }
72
73        @Override
74        public String toString() {
75            return tableRowDividerText;
76        }
77    }
78    private static MBeanInfoTableCellRenderer renderer =
79            new MBeanInfoTableCellRenderer();
80
81    private static class MBeanInfoTableCellRenderer
82            extends DefaultTableCellRenderer {
83
84        @Override
85        public Component getTableCellRendererComponent(
86                JTable table, Object value, boolean isSelected,
87                boolean hasFocus, int row, int column) {
88            Component comp = super.getTableCellRendererComponent(
89                    table, value, isSelected, hasFocus, row, column);
90            if (value instanceof TableRowDivider) {
91                JLabel label = new JLabel(value.toString());
92                label.setBackground(ensureContrast(lightYellow,
93                        label.getForeground()));
94                label.setOpaque(true);
95                return label;
96            }
97            return comp;
98        }
99    }
100    private static TableCellEditor editor =
101            new MBeanInfoTableCellEditor(new JTextField());
102
103    private static class MBeanInfoTableCellEditor
104            extends Utils.ReadOnlyTableCellEditor {
105
106        public MBeanInfoTableCellEditor(JTextField tf) {
107            super(tf);
108        }
109
110        @Override
111        public Component getTableCellEditorComponent(
112                JTable table, Object value, boolean isSelected,
113                int row, int column) {
114            Component comp = super.getTableCellEditorComponent(
115                    table, value, isSelected, row, column);
116            if (value instanceof TableRowDivider) {
117                JLabel label = new JLabel(value.toString());
118                label.setBackground(ensureContrast(lightYellow,
119                        label.getForeground()));
120                label.setOpaque(true);
121                return label;
122            }
123            return comp;
124        }
125    }
126
127    public XMBeanInfo() {
128        // Use the grid layout to display the two tables
129        //
130        super(new GridLayout(2, 1));
131        // MBean*Info table
132        //
133        infoTable.setModel(new ReadOnlyDefaultTableModel());
134        infoTable.setRowSelectionAllowed(false);
135        infoTable.setColumnSelectionAllowed(false);
136        infoTable.getTableHeader().setReorderingAllowed(false);
137        ((DefaultTableModel) infoTable.getModel()).setColumnIdentifiers(columnNames);
138        infoTable.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(140);
139        infoTable.getColumnModel().getColumn(NAME_COLUMN).setMaxWidth(140);
140        infoTable.getColumnModel().getColumn(NAME_COLUMN).setCellRenderer(renderer);
141        infoTable.getColumnModel().getColumn(VALUE_COLUMN).setCellRenderer(renderer);
142        infoTable.getColumnModel().getColumn(NAME_COLUMN).setCellEditor(editor);
143        infoTable.getColumnModel().getColumn(VALUE_COLUMN).setCellEditor(editor);
144        infoTable.addKeyListener(new Utils.CopyKeyAdapter());
145        infoTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
146        JScrollPane infoTableScrollPane = new JScrollPane(infoTable);
147        infoBorderPanel.setBorder(
148                BorderFactory.createTitledBorder("MBeanInfoPlaceHolder"));
149        infoBorderPanel.add(infoTableScrollPane);
150        // Descriptor table
151        //
152        descTable.setModel(new ReadOnlyDefaultTableModel());
153        descTable.setRowSelectionAllowed(false);
154        descTable.setColumnSelectionAllowed(false);
155        descTable.getTableHeader().setReorderingAllowed(false);
156        ((DefaultTableModel) descTable.getModel()).setColumnIdentifiers(columnNames);
157        descTable.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(140);
158        descTable.getColumnModel().getColumn(NAME_COLUMN).setMaxWidth(140);
159        descTable.getColumnModel().getColumn(NAME_COLUMN).setCellRenderer(renderer);
160        descTable.getColumnModel().getColumn(VALUE_COLUMN).setCellRenderer(renderer);
161        descTable.getColumnModel().getColumn(NAME_COLUMN).setCellEditor(editor);
162        descTable.getColumnModel().getColumn(VALUE_COLUMN).setCellEditor(editor);
163        descTable.addKeyListener(new Utils.CopyKeyAdapter());
164        descTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
165        JScrollPane descTableScrollPane = new JScrollPane(descTable);
166        descBorderPanel.setBorder(
167            BorderFactory.createTitledBorder(Messages.DESCRIPTOR));
168        descBorderPanel.add(descTableScrollPane);
169        // Add the two tables to the grid
170        //
171        add(infoBorderPanel);
172        add(descBorderPanel);
173    }
174
175    // Call on EDT
176    public void emptyInfoTable() {
177        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
178        while (tableModel.getRowCount() > 0) {
179            tableModel.removeRow(0);
180        }
181    }
182
183    // Call on EDT
184    public void emptyDescTable() {
185        DefaultTableModel tableModel = (DefaultTableModel) descTable.getModel();
186        while (tableModel.getRowCount() > 0) {
187            tableModel.removeRow(0);
188        }
189    }
190
191    // Call on EDT
192    private void addDescriptor(Descriptor desc, String text) {
193        if (desc != null && desc.getFieldNames().length > 0) {
194            DefaultTableModel tableModel = (DefaultTableModel) descTable.getModel();
195            Object rowData[] = new Object[2];
196            rowData[0] = new TableRowDivider(text);
197            rowData[1] = new TableRowDivider("");
198            tableModel.addRow(rowData);
199            for (String fieldName : desc.getFieldNames()) {
200                rowData[0] = fieldName;
201                Object fieldValue = desc.getFieldValue(fieldName);
202                if (fieldValue instanceof boolean[]) {
203                    rowData[1] = Arrays.toString((boolean[]) fieldValue);
204                } else if (fieldValue instanceof byte[]) {
205                    rowData[1] = Arrays.toString((byte[]) fieldValue);
206                } else if (fieldValue instanceof char[]) {
207                    rowData[1] = Arrays.toString((char[]) fieldValue);
208                } else if (fieldValue instanceof double[]) {
209                    rowData[1] = Arrays.toString((double[]) fieldValue);
210                } else if (fieldValue instanceof float[]) {
211                    rowData[1] = Arrays.toString((float[]) fieldValue);
212                } else if (fieldValue instanceof int[]) {
213                    rowData[1] = Arrays.toString((int[]) fieldValue);
214                } else if (fieldValue instanceof long[]) {
215                    rowData[1] = Arrays.toString((long[]) fieldValue);
216                } else if (fieldValue instanceof short[]) {
217                    rowData[1] = Arrays.toString((short[]) fieldValue);
218                } else if (fieldValue instanceof Object[]) {
219                    rowData[1] = Arrays.toString((Object[]) fieldValue);
220                } else {
221                    rowData[1] = fieldValue;
222                }
223                tableModel.addRow(rowData);
224            }
225            tableModel.newDataAvailable(new TableModelEvent(tableModel));
226        }
227    }
228
229    // Call on EDT
230    public void addMBeanInfo(XMBean mbean, MBeanInfo mbeanInfo) {
231        emptyInfoTable();
232        emptyDescTable();
233        ((TitledBorder) infoBorderPanel.getBorder()).setTitle(
234                Messages.MBEAN_INFO);
235        String text = Messages.INFO + ":";
236        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
237        Object rowData[] = new Object[2];
238        rowData[0] = new TableRowDivider(text);
239        rowData[1] = new TableRowDivider("");
240        tableModel.addRow(rowData);
241        rowData[0] = Messages.OBJECT_NAME;
242        rowData[1] = mbean.getObjectName();
243        tableModel.addRow(rowData);
244        rowData[0] = Messages.CLASS_NAME;
245        rowData[1] = mbeanInfo.getClassName();
246        tableModel.addRow(rowData);
247        rowData[0] = Messages.DESCRIPTION;
248        rowData[1] = mbeanInfo.getDescription();
249        tableModel.addRow(rowData);
250        addDescriptor(mbeanInfo.getDescriptor(), text);
251        // MBeanConstructorInfo
252        //
253        int i = 0;
254        for (MBeanConstructorInfo mbci : mbeanInfo.getConstructors()) {
255            addMBeanConstructorInfo(mbci,
256                    Messages.CONSTRUCTOR + "-" + i + ":");
257            // MBeanParameterInfo
258            //
259            int j = 0;
260            for (MBeanParameterInfo mbpi : mbci.getSignature()) {
261                addMBeanParameterInfo(mbpi,
262                        Messages.PARAMETER + "-" + i + "-" + j + ":");
263                j++;
264            }
265            i++;
266        }
267        tableModel.newDataAvailable(new TableModelEvent(tableModel));
268    }
269
270    // Call on EDT
271    public void addMBeanAttributeInfo(MBeanAttributeInfo mbai) {
272        emptyInfoTable();
273        emptyDescTable();
274        ((TitledBorder) infoBorderPanel.getBorder()).setTitle(
275                Messages.MBEAN_ATTRIBUTE_INFO);
276        String text = Messages.ATTRIBUTE + ":";
277        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
278        Object rowData[] = new Object[2];
279        rowData[0] = new TableRowDivider(text);
280        rowData[1] = new TableRowDivider("");
281        tableModel.addRow(rowData);
282        rowData[0] = Messages.NAME;
283        rowData[1] = mbai.getName();
284        tableModel.addRow(rowData);
285        rowData[0] = Messages.DESCRIPTION;
286        rowData[1] = mbai.getDescription();
287        tableModel.addRow(rowData);
288        rowData[0] = Messages.READABLE;
289        rowData[1] = mbai.isReadable();
290        tableModel.addRow(rowData);
291        rowData[0] = Messages.WRITABLE;
292        rowData[1] = mbai.isWritable();
293        tableModel.addRow(rowData);
294        rowData[0] = Messages.IS;
295        rowData[1] = mbai.isIs();
296        tableModel.addRow(rowData);
297        rowData[0] = Messages.TYPE;
298        rowData[1] = mbai.getType();
299        tableModel.addRow(rowData);
300        addDescriptor(mbai.getDescriptor(), text);
301        tableModel.newDataAvailable(new TableModelEvent(tableModel));
302    }
303
304    // Call on EDT
305    public void addMBeanOperationInfo(MBeanOperationInfo mboi) {
306        emptyInfoTable();
307        emptyDescTable();
308        ((TitledBorder) infoBorderPanel.getBorder()).setTitle(
309                Messages.MBEAN_OPERATION_INFO);
310        String text = Messages.OPERATION + ":";
311        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
312        Object rowData[] = new Object[2];
313        rowData[0] = new TableRowDivider(text);
314        rowData[1] = new TableRowDivider("");
315        tableModel.addRow(rowData);
316        rowData[0] = Messages.NAME;
317        rowData[1] = mboi.getName();
318        tableModel.addRow(rowData);
319        rowData[0] = Messages.DESCRIPTION;
320        rowData[1] = mboi.getDescription();
321        tableModel.addRow(rowData);
322        rowData[0] = Messages.IMPACT;
323        switch (mboi.getImpact()) {
324            case MBeanOperationInfo.INFO:
325                rowData[1] = Messages.INFO_CAPITALIZED;
326                break;
327            case MBeanOperationInfo.ACTION:
328                rowData[1] = Messages.ACTION_CAPITALIZED;
329                break;
330            case MBeanOperationInfo.ACTION_INFO:
331                rowData[1] = Messages.ACTION_INFO_CAPITALIZED;
332                break;
333            case MBeanOperationInfo.UNKNOWN:
334                rowData[1] = Messages.UNKNOWN_CAPITALIZED;
335                break;
336        }
337        tableModel.addRow(rowData);
338        rowData[0] = Messages.RETURN_TYPE;
339        rowData[1] = mboi.getReturnType();
340        tableModel.addRow(rowData);
341        addDescriptor(mboi.getDescriptor(), text);
342        // MBeanParameterInfo
343        //
344        int i = 0;
345        for (MBeanParameterInfo mbpi : mboi.getSignature()) {
346            addMBeanParameterInfo(mbpi,
347                    Messages.PARAMETER + "-" + i++ + ":");
348        }
349        tableModel.newDataAvailable(new TableModelEvent(tableModel));
350    }
351
352    // Call on EDT
353    public void addMBeanNotificationInfo(MBeanNotificationInfo mbni) {
354        emptyInfoTable();
355        emptyDescTable();
356        ((TitledBorder) infoBorderPanel.getBorder()).setTitle(
357                Messages.MBEAN_NOTIFICATION_INFO);
358        String text = Messages.NOTIFICATION + ":";
359        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
360        Object rowData[] = new Object[2];
361        rowData[0] = new TableRowDivider(text);
362        rowData[1] = new TableRowDivider("");
363        tableModel.addRow(rowData);
364        rowData[0] = Messages.NAME;
365        rowData[1] = mbni.getName();
366        tableModel.addRow(rowData);
367        rowData[0] = Messages.DESCRIPTION;
368        rowData[1] = mbni.getDescription();
369        tableModel.addRow(rowData);
370        rowData[0] = Messages.NOTIF_TYPES;
371        rowData[1] = Arrays.toString(mbni.getNotifTypes());
372        tableModel.addRow(rowData);
373        addDescriptor(mbni.getDescriptor(), text);
374        tableModel.newDataAvailable(new TableModelEvent(tableModel));
375    }
376
377    // Call on EDT
378    private void addMBeanConstructorInfo(MBeanConstructorInfo mbci, String text) {
379        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
380        Object rowData[] = new Object[2];
381        rowData[0] = new TableRowDivider(text);
382        rowData[1] = new TableRowDivider("");
383        tableModel.addRow(rowData);
384        rowData[0] = Messages.NAME;
385        rowData[1] = mbci.getName();
386        tableModel.addRow(rowData);
387        rowData[0] = Messages.DESCRIPTION;
388        rowData[1] = mbci.getDescription();
389        tableModel.addRow(rowData);
390        addDescriptor(mbci.getDescriptor(), text);
391        tableModel.newDataAvailable(new TableModelEvent(tableModel));
392    }
393
394    // Call on EDT
395    private void addMBeanParameterInfo(MBeanParameterInfo mbpi, String text) {
396        DefaultTableModel tableModel = (DefaultTableModel) infoTable.getModel();
397        Object rowData[] = new Object[2];
398        rowData[0] = new TableRowDivider(text);
399        rowData[1] = new TableRowDivider("");
400        tableModel.addRow(rowData);
401        rowData[0] = Messages.NAME;
402        rowData[1] = mbpi.getName();
403        tableModel.addRow(rowData);
404        rowData[0] = Messages.DESCRIPTION;
405        rowData[1] = mbpi.getDescription();
406        tableModel.addRow(rowData);
407        rowData[0] = Messages.TYPE;
408        rowData[1] = mbpi.getType();
409        tableModel.addRow(rowData);
410        addDescriptor(mbpi.getDescriptor(), text);
411        tableModel.newDataAvailable(new TableModelEvent(tableModel));
412    }
413}
414