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;
  27 
  28 import java.awt.BorderLayout;
  29 import java.awt.EventQueue;
  30 import java.awt.event.MouseAdapter;
  31 import java.awt.event.MouseEvent;
  32 import java.awt.event.MouseListener;
  33 import java.beans.*;
  34 import java.io.*;
  35 import java.util.Set;
  36 import javax.management.*;
  37 import javax.swing.*;
  38 import javax.swing.event.*;
  39 import javax.swing.tree.*;
  40 import sun.tools.jconsole.ProxyClient.SnapshotMBeanServerConnection;
  41 import sun.tools.jconsole.inspector.*;
  42 
  43 import com.sun.tools.jconsole.JConsoleContext;
  44 
  45 @SuppressWarnings("serial")
  46 public 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 Resources.getText("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 }