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;
27
28import java.awt.BorderLayout;
29import java.awt.EventQueue;
30import java.awt.event.MouseAdapter;
31import java.awt.event.MouseEvent;
32import java.awt.event.MouseListener;
33import java.beans.*;
34import java.io.*;
35import java.util.Set;
36import javax.management.*;
37import javax.swing.*;
38import javax.swing.event.*;
39import javax.swing.tree.*;
40import sun.tools.jconsole.ProxyClient.SnapshotMBeanServerConnection;
41import sun.tools.jconsole.inspector.*;
42
43import com.sun.tools.jconsole.JConsoleContext;
44
45@SuppressWarnings("serial")
46public class MBeansTab extends Tab implements
47        NotificationListener, PropertyChangeListener,
48        TreeSelectionListener, TreeWillExpandListener {
49
50    private XTree tree;
51    private XSheet sheet;
52    private XDataViewer viewer;
53
54    public static String getTabName() {
55        return Messages.MBEANS;
56    }
57
58    public MBeansTab(final VMPanel vmPanel) {
59        super(vmPanel, getTabName());
60        addPropertyChangeListener(this);
61        setupTab();
62    }
63
64    public XDataViewer getDataViewer() {
65        return viewer;
66    }
67
68    public XTree getTree() {
69        return tree;
70    }
71
72    public XSheet getSheet() {
73        return sheet;
74    }
75
76    @Override
77    public void dispose() {
78        super.dispose();
79        sheet.dispose();
80    }
81
82    public int getUpdateInterval() {
83        return vmPanel.getUpdateInterval();
84    }
85
86    private void buildMBeanServerView() {
87        new SwingWorker<Set<ObjectName>, Void>() {
88            @Override
89            public Set<ObjectName> doInBackground() {
90                // Register listener for MBean registration/unregistration
91                //
92                try {
93                    getMBeanServerConnection().addNotificationListener(
94                            MBeanServerDelegate.DELEGATE_NAME,
95                            MBeansTab.this,
96                            null,
97                            null);
98                } catch (InstanceNotFoundException e) {
99                    // Should never happen because the MBeanServerDelegate
100                    // is always present in any standard MBeanServer
101                    //
102                    if (JConsole.isDebug()) {
103                        e.printStackTrace();
104                    }
105                } catch (IOException e) {
106                    if (JConsole.isDebug()) {
107                        e.printStackTrace();
108                    }
109                    vmPanel.getProxyClient().markAsDead();
110                    return null;
111                }
112                // Retrieve MBeans from MBeanServer
113                //
114                Set<ObjectName> mbeans = null;
115                try {
116                    mbeans = getMBeanServerConnection().queryNames(null, null);
117                } catch (IOException e) {
118                    if (JConsole.isDebug()) {
119                        e.printStackTrace();
120                    }
121                    vmPanel.getProxyClient().markAsDead();
122                    return null;
123                }
124                return mbeans;
125            }
126            @Override
127            protected void done() {
128                try {
129                    // Wait for mbsc.queryNames() result
130                    Set<ObjectName> mbeans = get();
131                    // Do not display anything until the new tree has been built
132                    //
133                    tree.setVisible(false);
134                    // Cleanup current tree
135                    //
136                    tree.removeAll();
137                    // Add MBeans to tree
138                    //
139                    tree.addMBeansToView(mbeans);
140                    // Display the new tree
141                    //
142                    tree.setVisible(true);
143                } catch (Exception e) {
144                    Throwable t = Utils.getActualException(e);
145                    if (JConsole.isDebug()) {
146                        System.err.println("Problem at MBean tree construction");
147                        t.printStackTrace();
148                    }
149                }
150            }
151        }.execute();
152    }
153
154    public MBeanServerConnection getMBeanServerConnection() {
155        return vmPanel.getProxyClient().getMBeanServerConnection();
156    }
157
158    public SnapshotMBeanServerConnection getSnapshotMBeanServerConnection() {
159        return vmPanel.getProxyClient().getSnapshotMBeanServerConnection();
160    }
161
162    @Override
163    public void update() {
164        // Ping the connection to see if it is still alive. At
165        // some point the ProxyClient class should centralize
166        // the connection aliveness monitoring and no longer
167        // rely on the custom tabs to ping the connections.
168        //
169        try {
170            getMBeanServerConnection().getDefaultDomain();
171        } catch (IOException ex) {
172            vmPanel.getProxyClient().markAsDead();
173        }
174    }
175
176    private void setupTab() {
177        // set up the split pane with the MBean tree and MBean sheet panels
178        setLayout(new BorderLayout());
179        JSplitPane mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
180        mainSplit.setDividerLocation(160);
181        mainSplit.setBorder(BorderFactory.createEmptyBorder());
182
183        // set up the MBean tree panel (left pane)
184        tree = new XTree(this);
185        tree.setCellRenderer(new XTreeRenderer());
186        tree.getSelectionModel().setSelectionMode(
187                TreeSelectionModel.SINGLE_TREE_SELECTION);
188        tree.addTreeSelectionListener(this);
189        tree.addTreeWillExpandListener(this);
190        tree.addMouseListener(ml);
191        JScrollPane theScrollPane = new JScrollPane(
192                tree,
193                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
194                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
195        JPanel treePanel = new JPanel(new BorderLayout());
196        treePanel.add(theScrollPane, BorderLayout.CENTER);
197        mainSplit.add(treePanel, JSplitPane.LEFT, 0);
198
199        // set up the MBean sheet panel (right pane)
200        viewer = new XDataViewer(this);
201        sheet = new XSheet(this);
202        mainSplit.add(sheet, JSplitPane.RIGHT, 0);
203
204        add(mainSplit);
205    }
206
207    /* notification listener:  handleNotification */
208    public void handleNotification(
209            final Notification notification, Object handback) {
210        EventQueue.invokeLater(new Runnable() {
211            public void run() {
212                if (notification instanceof MBeanServerNotification) {
213                    ObjectName mbean =
214                            ((MBeanServerNotification) notification).getMBeanName();
215                    if (notification.getType().equals(
216                            MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
217                        tree.addMBeanToView(mbean);
218                    } else if (notification.getType().equals(
219                            MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
220                        tree.removeMBeanFromView(mbean);
221                    }
222                }
223            }
224        });
225    }
226
227    /* property change listener:  propertyChange */
228    public void propertyChange(PropertyChangeEvent evt) {
229        if (JConsoleContext.CONNECTION_STATE_PROPERTY.equals(evt.getPropertyName())) {
230            boolean connected = (Boolean) evt.getNewValue();
231            if (connected) {
232                buildMBeanServerView();
233            } else {
234                sheet.dispose();
235            }
236        }
237    }
238
239    /* tree selection listener: valueChanged */
240    public void valueChanged(TreeSelectionEvent e) {
241        DefaultMutableTreeNode node =
242                (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
243        sheet.displayNode(node);
244    }
245    /* tree mouse listener: mousePressed */
246    private MouseListener ml = new MouseAdapter() {
247        @Override
248        public void mousePressed(MouseEvent e) {
249            if (e.getClickCount() == 1) {
250                int selRow = tree.getRowForLocation(e.getX(), e.getY());
251                if (selRow != -1) {
252                    TreePath selPath =
253                            tree.getPathForLocation(e.getX(), e.getY());
254                    DefaultMutableTreeNode node =
255                            (DefaultMutableTreeNode) selPath.getLastPathComponent();
256                    if (sheet.isMBeanNode(node)) {
257                        tree.expandPath(selPath);
258                    }
259                }
260            }
261        }
262    };
263
264    /* tree will expand listener: treeWillExpand */
265    public void treeWillExpand(TreeExpansionEvent e)
266            throws ExpandVetoException {
267        TreePath path = e.getPath();
268        if (!tree.hasBeenExpanded(path)) {
269            DefaultMutableTreeNode node =
270                    (DefaultMutableTreeNode) path.getLastPathComponent();
271            if (sheet.isMBeanNode(node) && !tree.hasMetadataNodes(node)) {
272                tree.addMetadataNodes(node);
273            }
274        }
275    }
276
277    /* tree will expand listener: treeWillCollapse */
278    public void treeWillCollapse(TreeExpansionEvent e)
279            throws ExpandVetoException {
280    }
281}
282