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
28
29import java.awt.BorderLayout;
30import java.awt.Color;
31import java.awt.Component;
32import java.awt.Dimension;
33import java.awt.event.ActionEvent;
34import java.awt.event.ActionListener;
35import java.io.IOException;
36
37import javax.management.IntrospectionException;
38import javax.management.NotificationListener;
39import javax.management.MBeanInfo;
40import javax.management.InstanceNotFoundException;
41import javax.management.ReflectionException;
42import javax.management.MBeanAttributeInfo;
43import javax.management.MBeanOperationInfo;
44import javax.management.MBeanNotificationInfo;
45import javax.management.Notification;
46import javax.swing.BorderFactory;
47import javax.swing.JButton;
48import javax.swing.JOptionPane;
49import javax.swing.JPanel;
50import javax.swing.JScrollPane;
51import javax.swing.JTextArea;
52import javax.swing.SwingWorker;
53import javax.swing.border.LineBorder;
54import javax.swing.tree.DefaultMutableTreeNode;
55import javax.swing.tree.DefaultTreeModel;
56
57import sun.tools.jconsole.*;
58import sun.tools.jconsole.inspector.XNodeInfo.Type;
59
60@SuppressWarnings("serial")
61public 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
85    public XSheet(MBeansTab mbeansTab) {
86        this.mbeansTab = mbeansTab;
87        setupScreen();
88    }
89
90    public void dispose() {
91        clear();
92        XDataViewer.dispose(mbeansTab);
93        mbeanNotifications.dispose();
94    }
95
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
138    private boolean isSelectedNode(DefaultMutableTreeNode n, DefaultMutableTreeNode cn) {
139        return (cn == n);
140    }
141
142    // Call on EDT
143    private void showErrorDialog(Object message, String title) {
144        new ThreadDialog(this, message, title, JOptionPane.ERROR_MESSAGE).run();
145    }
146
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
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
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
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
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
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
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
493    private void displayEmptyNode() {
494        invalidate();
495        mainPanel.removeAll();
496        southPanel.removeAll();
497        validate();
498        repaint();
499    }
500
501    /**
502     * Subscribe button action.
503     */
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     */
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     */
563    private void refreshAttributes() {
564        mbeanAttributes.refreshAttributes();
565    }
566
567    // Call on EDT
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
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
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
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
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
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
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
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
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