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