1 /*
   2  * Copyright (c) 2004, 2008, 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 
  29 import java.awt.BorderLayout;
  30 import java.awt.Color;
  31 import java.awt.Component;
  32 import java.awt.Dimension;
  33 import java.awt.event.ActionEvent;
  34 import java.awt.event.ActionListener;
  35 import java.io.IOException;
  36 
  37 import javax.management.IntrospectionException;
  38 import javax.management.NotificationListener;
  39 import javax.management.MBeanInfo;
  40 import javax.management.InstanceNotFoundException;
  41 import javax.management.ReflectionException;
  42 import javax.management.MBeanAttributeInfo;
  43 import javax.management.MBeanOperationInfo;
  44 import javax.management.MBeanNotificationInfo;
  45 import javax.management.Notification;
  46 import javax.swing.BorderFactory;
  47 import javax.swing.JButton;
  48 import javax.swing.JOptionPane;
  49 import javax.swing.JPanel;
  50 import javax.swing.JScrollPane;
  51 import javax.swing.JTextArea;
  52 import javax.swing.SwingWorker;
  53 import javax.swing.border.LineBorder;
  54 import javax.swing.tree.DefaultMutableTreeNode;
  55 import javax.swing.tree.DefaultTreeModel;
  56 
  57 import sun.tools.jconsole.*;
  58 import sun.tools.jconsole.inspector.XNodeInfo.Type;
  59 import sun.tools.jconsole.resources.Messages;
  60 
  61 @SuppressWarnings("serial")
  62 public class XSheet extends JPanel
  63         implements ActionListener, NotificationListener {
  64 
  65     private JPanel mainPanel;
  66     private JPanel southPanel;
  67     // Node being currently displayed
  68     private volatile DefaultMutableTreeNode currentNode;
  69     // MBean being currently displayed
  70     private volatile XMBean mbean;
  71     // XMBeanAttributes container
  72     private XMBeanAttributes mbeanAttributes;
  73     // XMBeanOperations container
  74     private XMBeanOperations mbeanOperations;
  75     // XMBeanNotifications container
  76     private XMBeanNotifications mbeanNotifications;
  77     // XMBeanInfo container
  78     private XMBeanInfo mbeanInfo;
  79     // Refresh JButton (mbean attributes case)
  80     private JButton refreshButton;
  81     // Subscribe/Unsubscribe/Clear JButton (mbean notifications case)
  82     private JButton clearButton,  subscribeButton,  unsubscribeButton;
  83     // Reference to MBeans tab
  84     private MBeansTab mbeansTab;
  85 
  86     public XSheet(MBeansTab mbeansTab) {
  87         this.mbeansTab = mbeansTab;
  88         setupScreen();
  89     }
  90 
  91     public void dispose() {
  92         clear();
  93         XDataViewer.dispose(mbeansTab);
  94         mbeanNotifications.dispose();
  95     }
  96 
  97     private void setupScreen() {
  98         setLayout(new BorderLayout());
  99         setBorder(BorderFactory.createLineBorder(Color.GRAY));
 100         // add main panel to XSheet
 101         mainPanel = new JPanel();
 102         mainPanel.setLayout(new BorderLayout());
 103         add(mainPanel, BorderLayout.CENTER);
 104         // add south panel to XSheet
 105         southPanel = new JPanel();
 106         add(southPanel, BorderLayout.SOUTH);
 107         // create the refresh button
 108         refreshButton = new JButton(Messages.MBEANS_TAB_REFRESH_ATTRIBUTES_BUTTON);
 109         refreshButton.setMnemonic(Resources.getMnemonicInt(Messages.MBEANS_TAB_REFRESH_ATTRIBUTES_BUTTON));
 110         refreshButton.setToolTipText(Messages.MBEANS_TAB_REFRESH_ATTRIBUTES_BUTTON_TOOLTIP);
 111         refreshButton.addActionListener(this);
 112         // create the clear button
 113         clearButton = new JButton(Messages.MBEANS_TAB_CLEAR_NOTIFICATIONS_BUTTON);
 114         clearButton.setMnemonic(Resources.getMnemonicInt(Messages.MBEANS_TAB_CLEAR_NOTIFICATIONS_BUTTON));
 115         clearButton.setToolTipText(Messages.MBEANS_TAB_CLEAR_NOTIFICATIONS_BUTTON_TOOLTIP);
 116         clearButton.addActionListener(this);
 117         // create the subscribe button
 118         subscribeButton = new JButton(Messages.MBEANS_TAB_SUBSCRIBE_NOTIFICATIONS_BUTTON);
 119         subscribeButton.setMnemonic(Resources.getMnemonicInt(Messages.MBEANS_TAB_SUBSCRIBE_NOTIFICATIONS_BUTTON));
 120         subscribeButton.setToolTipText(Messages.MBEANS_TAB_SUBSCRIBE_NOTIFICATIONS_BUTTON_TOOLTIP);
 121         subscribeButton.addActionListener(this);
 122         // create the unsubscribe button
 123        unsubscribeButton = new JButton(Messages.MBEANS_TAB_UNSUBSCRIBE_NOTIFICATIONS_BUTTON);
 124         unsubscribeButton.setMnemonic(Resources.getMnemonicInt(Messages.MBEANS_TAB_UNSUBSCRIBE_NOTIFICATIONS_BUTTON));
 125         unsubscribeButton.setToolTipText(Messages.MBEANS_TAB_UNSUBSCRIBE_NOTIFICATIONS_BUTTON_TOOLTIP);
 126         unsubscribeButton.addActionListener(this);
 127         // create XMBeanAttributes container
 128         mbeanAttributes = new XMBeanAttributes(mbeansTab);
 129         // create XMBeanOperations container
 130         mbeanOperations = new XMBeanOperations(mbeansTab);
 131         mbeanOperations.addOperationsListener(this);
 132         // create XMBeanNotifications container
 133         mbeanNotifications = new XMBeanNotifications();
 134         mbeanNotifications.addNotificationsListener(this);
 135         // create XMBeanInfo container
 136         mbeanInfo = new XMBeanInfo();
 137     }
 138 
 139     private boolean isSelectedNode(DefaultMutableTreeNode n, DefaultMutableTreeNode cn) {
 140         return (cn == n);
 141     }
 142 
 143     // Call on EDT
 144     private void showErrorDialog(Object message, String title) {
 145         new ThreadDialog(this, message, title, JOptionPane.ERROR_MESSAGE).run();
 146     }
 147 
 148     public boolean isMBeanNode(DefaultMutableTreeNode node) {
 149         Object userObject = node.getUserObject();
 150         if (userObject instanceof XNodeInfo) {
 151             XNodeInfo uo = (XNodeInfo) userObject;
 152             return uo.getType().equals(Type.MBEAN);
 153         }
 154         return false;
 155     }
 156 
 157     // Call on EDT
 158     public synchronized void displayNode(DefaultMutableTreeNode node) {
 159         clear();
 160         displayEmptyNode();
 161         if (node == null) {
 162             return;
 163         }
 164         currentNode = node;
 165         Object userObject = node.getUserObject();
 166         if (userObject instanceof XNodeInfo) {
 167             XNodeInfo uo = (XNodeInfo) userObject;
 168             switch (uo.getType()) {
 169                 case MBEAN:
 170                     displayMBeanNode(node);
 171                     break;
 172                 case NONMBEAN:
 173                     displayEmptyNode();
 174                     break;
 175                 case ATTRIBUTES:
 176                     displayMBeanAttributesNode(node);
 177                     break;
 178                 case OPERATIONS:
 179                     displayMBeanOperationsNode(node);
 180                     break;
 181                 case NOTIFICATIONS:
 182                     displayMBeanNotificationsNode(node);
 183                     break;
 184                 case ATTRIBUTE:
 185                 case OPERATION:
 186                 case NOTIFICATION:
 187                     displayMetadataNode(node);
 188                     break;
 189                 default:
 190                     displayEmptyNode();
 191                     break;
 192             }
 193         } else {
 194             displayEmptyNode();
 195         }
 196     }
 197 
 198     // Call on EDT
 199     private void displayMBeanNode(final DefaultMutableTreeNode node) {
 200         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
 201         if (!uo.getType().equals(Type.MBEAN)) {
 202             return;
 203         }
 204         mbean = (XMBean) uo.getData();
 205         SwingWorker<MBeanInfo, Void> sw = new SwingWorker<MBeanInfo, Void>() {
 206             @Override
 207             public MBeanInfo doInBackground() throws InstanceNotFoundException,
 208                     IntrospectionException, ReflectionException, IOException {
 209                 return mbean.getMBeanInfo();
 210             }
 211             @Override
 212             protected void done() {
 213                 try {
 214                     MBeanInfo mbi = get();
 215                     if (mbi != null) {
 216                         if (!isSelectedNode(node, currentNode)) {
 217                             return;
 218                         }
 219                         mbeanInfo.addMBeanInfo(mbean, mbi);
 220                         invalidate();
 221                         mainPanel.removeAll();
 222                         mainPanel.add(mbeanInfo, BorderLayout.CENTER);
 223                         southPanel.setVisible(false);
 224                         southPanel.removeAll();
 225                         validate();
 226                         repaint();
 227                     }
 228                 } catch (Exception e) {
 229                     Throwable t = Utils.getActualException(e);
 230                     if (JConsole.isDebug()) {
 231                         System.err.println("Couldn't get MBeanInfo for MBean [" +
 232                                 mbean.getObjectName() + "]");
 233                         t.printStackTrace();
 234                     }
 235                     showErrorDialog(t.toString(),
 236                             Messages.PROBLEM_DISPLAYING_MBEAN);
 237                 }
 238             }
 239         };
 240         sw.execute();
 241     }
 242 
 243     // Call on EDT
 244     private void displayMetadataNode(final DefaultMutableTreeNode node) {
 245         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
 246         final XMBeanInfo mbi = mbeanInfo;
 247         switch (uo.getType()) {
 248             case ATTRIBUTE:
 249                 SwingWorker<MBeanAttributeInfo, Void> sw =
 250                         new SwingWorker<MBeanAttributeInfo, Void>() {
 251                             @Override
 252                             public MBeanAttributeInfo doInBackground() {
 253                                 Object attrData = uo.getData();
 254                                 mbean = (XMBean) ((Object[]) attrData)[0];
 255                                 MBeanAttributeInfo mbai =
 256                                         (MBeanAttributeInfo) ((Object[]) attrData)[1];
 257                                 mbeanAttributes.loadAttributes(mbean, new MBeanInfo(
 258                                         null, null, new MBeanAttributeInfo[]{mbai},
 259                                         null, null, null));
 260                                 return mbai;
 261                             }
 262                             @Override
 263                             protected void done() {
 264                                 try {
 265                                     MBeanAttributeInfo mbai = get();
 266                                     if (!isSelectedNode(node, currentNode)) {
 267                                         return;
 268                                     }
 269                                     invalidate();
 270                                     mainPanel.removeAll();
 271                                     JPanel attributePanel =
 272                                             new JPanel(new BorderLayout());
 273                                     JPanel attributeBorderPanel =
 274                                             new JPanel(new BorderLayout());
 275                                     attributeBorderPanel.setBorder(
 276                                             BorderFactory.createTitledBorder(
 277                                             Messages.ATTRIBUTE_VALUE));
 278                                     JPanel attributeValuePanel =
 279                                             new JPanel(new BorderLayout());
 280                                     attributeValuePanel.setBorder(
 281                                             LineBorder.createGrayLineBorder());
 282                                     attributeValuePanel.add(mbeanAttributes.getTableHeader(),
 283                                             BorderLayout.PAGE_START);
 284                                     attributeValuePanel.add(mbeanAttributes,
 285                                             BorderLayout.CENTER);
 286                                     attributeBorderPanel.add(attributeValuePanel,
 287                                             BorderLayout.CENTER);
 288                                     JPanel refreshButtonPanel = new JPanel();
 289                                     refreshButtonPanel.add(refreshButton);
 290                                     attributeBorderPanel.add(refreshButtonPanel,
 291                                             BorderLayout.SOUTH);
 292                                     refreshButton.setEnabled(true);
 293                                     attributePanel.add(attributeBorderPanel,
 294                                             BorderLayout.NORTH);
 295                                     mbi.addMBeanAttributeInfo(mbai);
 296                                     attributePanel.add(mbi, BorderLayout.CENTER);
 297                                     mainPanel.add(attributePanel,
 298                                             BorderLayout.CENTER);
 299                                     southPanel.setVisible(false);
 300                                     southPanel.removeAll();
 301                                     validate();
 302                                     repaint();
 303                                 } catch (Exception e) {
 304                                     Throwable t = Utils.getActualException(e);
 305                                     if (JConsole.isDebug()) {
 306                                         System.err.println("Problem displaying MBean " +
 307                                                 "attribute for MBean [" +
 308                                                 mbean.getObjectName() + "]");
 309                                         t.printStackTrace();
 310                                     }
 311                                     showErrorDialog(t.toString(),
 312                                             Messages.PROBLEM_DISPLAYING_MBEAN);
 313                                 }
 314                             }
 315                         };
 316                 sw.execute();
 317                 break;
 318             case OPERATION:
 319                 Object operData = uo.getData();
 320                 mbean = (XMBean) ((Object[]) operData)[0];
 321                 MBeanOperationInfo mboi =
 322                         (MBeanOperationInfo) ((Object[]) operData)[1];
 323                 mbeanOperations.loadOperations(mbean,
 324                         new MBeanInfo(null, null, null, null,
 325                         new MBeanOperationInfo[]{mboi}, null));
 326                 invalidate();
 327                 mainPanel.removeAll();
 328                 JPanel operationPanel = new JPanel(new BorderLayout());
 329                 JPanel operationBorderPanel = new JPanel(new BorderLayout());
 330                 operationBorderPanel.setBorder(BorderFactory.createTitledBorder(
 331                         Messages.OPERATION_INVOCATION));
 332                 operationBorderPanel.add(new JScrollPane(mbeanOperations));
 333                 operationPanel.add(operationBorderPanel, BorderLayout.NORTH);
 334                 mbi.addMBeanOperationInfo(mboi);
 335                 operationPanel.add(mbi, BorderLayout.CENTER);
 336                 mainPanel.add(operationPanel, BorderLayout.CENTER);
 337                 southPanel.setVisible(false);
 338                 southPanel.removeAll();
 339                 validate();
 340                 repaint();
 341                 break;
 342             case NOTIFICATION:
 343                 Object notifData = uo.getData();
 344                 invalidate();
 345                 mainPanel.removeAll();
 346                 mbi.addMBeanNotificationInfo((MBeanNotificationInfo) notifData);
 347                 mainPanel.add(mbi, BorderLayout.CENTER);
 348                 southPanel.setVisible(false);
 349                 southPanel.removeAll();
 350                 validate();
 351                 repaint();
 352                 break;
 353         }
 354     }
 355 
 356     // Call on EDT
 357     private void displayMBeanAttributesNode(final DefaultMutableTreeNode node) {
 358         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
 359         if (!uo.getType().equals(Type.ATTRIBUTES)) {
 360             return;
 361         }
 362         mbean = (XMBean) uo.getData();
 363         final XMBean xmb = mbean;
 364         SwingWorker<MBeanInfo,Void> sw = new SwingWorker<MBeanInfo,Void>() {
 365             @Override
 366             public MBeanInfo doInBackground() throws InstanceNotFoundException,
 367                     IntrospectionException, ReflectionException, IOException {
 368                 MBeanInfo mbi = xmb.getMBeanInfo();
 369                 return mbi;
 370             }
 371             @Override
 372             protected void done() {
 373                 try {
 374                     MBeanInfo mbi = get();
 375                     if (mbi != null && mbi.getAttributes() != null &&
 376                             mbi.getAttributes().length > 0) {
 377 
 378                         mbeanAttributes.loadAttributes(xmb, mbi);
 379 
 380                         if (!isSelectedNode(node, currentNode)) {
 381                             return;
 382                         }
 383                         invalidate();
 384                         mainPanel.removeAll();
 385                         JPanel borderPanel = new JPanel(new BorderLayout());
 386                         borderPanel.setBorder(BorderFactory.createTitledBorder(
 387                                 Messages.ATTRIBUTE_VALUES));
 388                         borderPanel.add(new JScrollPane(mbeanAttributes));
 389                         mainPanel.add(borderPanel, BorderLayout.CENTER);
 390                         // add the refresh button to the south panel
 391                         southPanel.removeAll();
 392                         southPanel.add(refreshButton, BorderLayout.SOUTH);
 393                         southPanel.setVisible(true);
 394                         refreshButton.setEnabled(true);
 395                         validate();
 396                         repaint();
 397                     }
 398                 } catch (Exception e) {
 399                     Throwable t = Utils.getActualException(e);
 400                     if (JConsole.isDebug()) {
 401                         System.err.println("Problem displaying MBean " +
 402                                 "attributes for MBean [" +
 403                                 mbean.getObjectName() + "]");
 404                         t.printStackTrace();
 405                     }
 406                     showErrorDialog(t.toString(),
 407                             Messages.PROBLEM_DISPLAYING_MBEAN);
 408                 }
 409             }
 410         };
 411         sw.execute();
 412     }
 413 
 414     // Call on EDT
 415     private void displayMBeanOperationsNode(final DefaultMutableTreeNode node) {
 416         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
 417         if (!uo.getType().equals(Type.OPERATIONS)) {
 418             return;
 419         }
 420         mbean = (XMBean) uo.getData();
 421         SwingWorker<MBeanInfo, Void> sw = new SwingWorker<MBeanInfo, Void>() {
 422             @Override
 423             public MBeanInfo doInBackground() throws InstanceNotFoundException,
 424                     IntrospectionException, ReflectionException, IOException {
 425                 return mbean.getMBeanInfo();
 426             }
 427             @Override
 428             protected void done() {
 429                 try {
 430                     MBeanInfo mbi = get();
 431                     if (mbi != null) {
 432                         if (!isSelectedNode(node, currentNode)) {
 433                             return;
 434                         }
 435                         mbeanOperations.loadOperations(mbean, mbi);
 436                         invalidate();
 437                         mainPanel.removeAll();
 438                         JPanel borderPanel = new JPanel(new BorderLayout());
 439                         borderPanel.setBorder(BorderFactory.createTitledBorder(
 440                                 Messages.OPERATION_INVOCATION));
 441                         borderPanel.add(new JScrollPane(mbeanOperations));
 442                         mainPanel.add(borderPanel, BorderLayout.CENTER);
 443                         southPanel.setVisible(false);
 444                         southPanel.removeAll();
 445                         validate();
 446                         repaint();
 447                     }
 448                 } catch (Exception e) {
 449                     Throwable t = Utils.getActualException(e);
 450                     if (JConsole.isDebug()) {
 451                         System.err.println("Problem displaying MBean " +
 452                                 "operations for MBean [" +
 453                                 mbean.getObjectName() + "]");
 454                         t.printStackTrace();
 455                     }
 456                     showErrorDialog(t.toString(),
 457                             Messages.PROBLEM_DISPLAYING_MBEAN);
 458                 }
 459             }
 460         };
 461         sw.execute();
 462     }
 463 
 464     // Call on EDT
 465     private void displayMBeanNotificationsNode(DefaultMutableTreeNode node) {
 466         final XNodeInfo uo = (XNodeInfo) node.getUserObject();
 467         if (!uo.getType().equals(Type.NOTIFICATIONS)) {
 468             return;
 469         }
 470         mbean = (XMBean) uo.getData();
 471         mbeanNotifications.loadNotifications(mbean);
 472         updateNotifications();
 473         invalidate();
 474         mainPanel.removeAll();
 475         JPanel borderPanel = new JPanel(new BorderLayout());
 476         borderPanel.setBorder(BorderFactory.createTitledBorder(
 477                 Messages.NOTIFICATION_BUFFER));
 478         borderPanel.add(new JScrollPane(mbeanNotifications));
 479         mainPanel.add(borderPanel, BorderLayout.CENTER);
 480         // add the subscribe/unsubscribe/clear buttons to the south panel
 481         southPanel.removeAll();
 482         southPanel.add(subscribeButton, BorderLayout.WEST);
 483         southPanel.add(unsubscribeButton, BorderLayout.CENTER);
 484         southPanel.add(clearButton, BorderLayout.EAST);
 485         southPanel.setVisible(true);
 486         subscribeButton.setEnabled(true);
 487         unsubscribeButton.setEnabled(true);
 488         clearButton.setEnabled(true);
 489         validate();
 490         repaint();
 491     }
 492 
 493     // Call on EDT
 494     private void displayEmptyNode() {
 495         invalidate();
 496         mainPanel.removeAll();
 497         southPanel.removeAll();
 498         validate();
 499         repaint();
 500     }
 501 
 502     /**
 503      * Subscribe button action.
 504      */
 505     private void registerListener() {
 506         new SwingWorker<Void, Void>() {
 507             @Override
 508             public Void doInBackground()
 509                     throws InstanceNotFoundException, IOException {
 510                 mbeanNotifications.registerListener(currentNode);
 511                 return null;
 512             }
 513             @Override
 514             protected void done() {
 515                 try {
 516                     get();
 517                     updateNotifications();
 518                     validate();
 519                 } catch (Exception e) {
 520                     Throwable t = Utils.getActualException(e);
 521                     if (JConsole.isDebug()) {
 522                         System.err.println("Problem adding listener");
 523                         t.printStackTrace();
 524                     }
 525                     showErrorDialog(t.getMessage(),
 526                             Messages.PROBLEM_ADDING_LISTENER);
 527                 }
 528             }
 529         }.execute();
 530     }
 531 
 532     /**
 533      * Unsubscribe button action.
 534      */
 535     private void unregisterListener() {
 536         new SwingWorker<Boolean, Void>() {
 537             @Override
 538             public Boolean doInBackground() {
 539                 return mbeanNotifications.unregisterListener(currentNode);
 540             }
 541             @Override
 542             protected void done() {
 543                 try {
 544                     if (get()) {
 545                         updateNotifications();
 546                         validate();
 547                     }
 548                 } catch (Exception e) {
 549                     Throwable t = Utils.getActualException(e);
 550                     if (JConsole.isDebug()) {
 551                         System.err.println("Problem removing listener");
 552                         t.printStackTrace();
 553                     }
 554                     showErrorDialog(t.getMessage(),
 555                             Messages.PROBLEM_REMOVING_LISTENER);
 556                 }
 557             }
 558         }.execute();
 559     }
 560 
 561     /**
 562      * Refresh button action.
 563      */
 564     private void refreshAttributes() {
 565         mbeanAttributes.refreshAttributes();
 566     }
 567 
 568     // Call on EDT
 569     private void updateNotifications() {
 570         if (mbeanNotifications.isListenerRegistered(mbean)) {
 571             long received = mbeanNotifications.getReceivedNotifications(mbean);
 572             updateReceivedNotifications(currentNode, received, false);
 573         } else {
 574             clearNotifications();
 575         }
 576     }
 577 
 578     /**
 579      * Update notification node label in MBean tree: "Notifications[received]".
 580      */
 581     // Call on EDT
 582     private void updateReceivedNotifications(
 583             DefaultMutableTreeNode emitter, long received, boolean bold) {
 584         String text = Messages.NOTIFICATIONS + "[" + received + "]";
 585         DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) mbeansTab.getTree().getLastSelectedPathComponent();
 586         if (bold && emitter != selectedNode) {
 587             text = "<html><b>" + text + "</b></html>";
 588         }
 589         updateNotificationsNodeLabel(emitter, text);
 590     }
 591 
 592     /**
 593      * Update notification node label in MBean tree: "Notifications".
 594      */
 595     // Call on EDT
 596     private void clearNotifications() {
 597         updateNotificationsNodeLabel(currentNode,
 598                 Messages.NOTIFICATIONS);
 599     }
 600 
 601     /**
 602      * Update notification node label in MBean tree: "Notifications[0]".
 603      */
 604     // Call on EDT
 605     private void clearNotifications0() {
 606         updateNotificationsNodeLabel(currentNode,
 607                 Messages.NOTIFICATIONS + "[0]");
 608     }
 609 
 610     /**
 611      * Update the label of the supplied MBean tree node.
 612      */
 613     // Call on EDT
 614     private void updateNotificationsNodeLabel(
 615             DefaultMutableTreeNode node, String label) {
 616         synchronized (mbeansTab.getTree()) {
 617             invalidate();
 618             XNodeInfo oldUserObject = (XNodeInfo) node.getUserObject();
 619             XNodeInfo newUserObject = new XNodeInfo(
 620                     oldUserObject.getType(), oldUserObject.getData(),
 621                     label, oldUserObject.getToolTipText());
 622             node.setUserObject(newUserObject);
 623             DefaultTreeModel model =
 624                     (DefaultTreeModel) mbeansTab.getTree().getModel();
 625             model.nodeChanged(node);
 626             validate();
 627             repaint();
 628         }
 629     }
 630 
 631     /**
 632      * Clear button action.
 633      */
 634     // Call on EDT
 635     private void clearCurrentNotifications() {
 636         mbeanNotifications.clearCurrentNotifications();
 637         if (mbeanNotifications.isListenerRegistered(mbean)) {
 638             // Update notifs in MBean tree "Notifications[0]".
 639             //
 640             // Notification buffer has been cleared with a listener been
 641             // registered so add "[0]" at the end of the node label.
 642             //
 643             clearNotifications0();
 644         } else {
 645             // Update notifs in MBean tree "Notifications".
 646             //
 647             // Notification buffer has been cleared without a listener been
 648             // registered so don't add "[0]" at the end of the node label.
 649             //
 650             clearNotifications();
 651         }
 652     }
 653 
 654     // Call on EDT
 655     private void clear() {
 656         mbeanAttributes.stopCellEditing();
 657         mbeanAttributes.emptyTable();
 658         mbeanAttributes.removeAttributes();
 659         mbeanOperations.removeOperations();
 660         mbeanNotifications.stopCellEditing();
 661         mbeanNotifications.emptyTable();
 662         mbeanNotifications.disableNotifications();
 663         mbean = null;
 664         currentNode = null;
 665     }
 666 
 667     /**
 668      * Notification listener: handles asynchronous reception
 669      * of MBean operation results and MBean notifications.
 670      */
 671     // Call on EDT
 672     public void handleNotification(Notification e, Object handback) {
 673         // Operation result
 674         if (e.getType().equals(XOperations.OPERATION_INVOCATION_EVENT)) {
 675             final Object message;
 676             if (handback == null) {
 677                 JTextArea textArea = new JTextArea("null");
 678                 textArea.setEditable(false);
 679                 textArea.setEnabled(true);
 680                 textArea.setRows(textArea.getLineCount());
 681                 message = textArea;
 682             } else {
 683                 Component comp = mbeansTab.getDataViewer().
 684                         createOperationViewer(handback, mbean);
 685                 if (comp == null) {
 686                     JTextArea textArea = new JTextArea(handback.toString());
 687                     textArea.setEditable(false);
 688                     textArea.setEnabled(true);
 689                     textArea.setRows(textArea.getLineCount());
 690                     JScrollPane scrollPane = new JScrollPane(textArea);
 691                     Dimension d = scrollPane.getPreferredSize();
 692                     if (d.getWidth() > 400 || d.getHeight() > 250) {
 693                         scrollPane.setPreferredSize(new Dimension(400, 250));
 694                     }
 695                     message = scrollPane;
 696                 } else {
 697                     if (!(comp instanceof JScrollPane)) {
 698                         comp = new JScrollPane(comp);
 699                     }
 700                     Dimension d = comp.getPreferredSize();
 701                     if (d.getWidth() > 400 || d.getHeight() > 250) {
 702                         comp.setPreferredSize(new Dimension(400, 250));
 703                     }
 704                     message = comp;
 705                 }
 706             }
 707             new ThreadDialog(
 708                     (Component) e.getSource(),
 709                     message,
 710                     Messages.OPERATION_RETURN_VALUE,
 711                     JOptionPane.INFORMATION_MESSAGE).run();
 712         } // Got notification
 713         else if (e.getType().equals(
 714                 XMBeanNotifications.NOTIFICATION_RECEIVED_EVENT)) {
 715             DefaultMutableTreeNode emitter = (DefaultMutableTreeNode) handback;
 716             Long received = (Long) e.getUserData();
 717             updateReceivedNotifications(emitter, received.longValue(), true);
 718         }
 719     }
 720 
 721     /**
 722      * Action listener: handles actions in panel buttons
 723      */
 724     // Call on EDT
 725     public void actionPerformed(ActionEvent e) {
 726         if (e.getSource() instanceof JButton) {
 727             JButton button = (JButton) e.getSource();
 728             // Refresh button
 729             if (button == refreshButton) {
 730                 refreshAttributes();
 731                 return;
 732             }
 733             // Clear button
 734             if (button == clearButton) {
 735                 clearCurrentNotifications();
 736                 return;
 737             }
 738             // Subscribe button
 739             if (button == subscribeButton) {
 740                 registerListener();
 741                 return;
 742             }
 743             // Unsubscribe button
 744             if (button == unsubscribeButton) {
 745                 unregisterListener();
 746                 return;
 747             }
 748         }
 749     }
 750 }