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