blob: 3739f40c38fb3aff1dbdd4283d30b7a6aab6e0ff [file] [log] [blame]
/*
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.jconsole.inspector;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.management.IntrospectionException;
import javax.management.NotificationListener;
import javax.management.MBeanInfo;
import javax.management.InstanceNotFoundException;
import javax.management.ReflectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.border.LineBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import sun.tools.jconsole.*;
import sun.tools.jconsole.inspector.XNodeInfo.Type;
import static sun.tools.jconsole.Resources.*;
@SuppressWarnings("serial")
public class XSheet extends JPanel
implements ActionListener, NotificationListener {
private JPanel mainPanel;
private JPanel southPanel;
// Node being currently displayed
private volatile DefaultMutableTreeNode currentNode;
// MBean being currently displayed
private volatile XMBean mbean;
// XMBeanAttributes container
private XMBeanAttributes mbeanAttributes;
// XMBeanOperations container
private XMBeanOperations mbeanOperations;
// XMBeanNotifications container
private XMBeanNotifications mbeanNotifications;
// XMBeanInfo container
private XMBeanInfo mbeanInfo;
// Refresh JButton (mbean attributes case)
private JButton refreshButton;
// Subscribe/Unsubscribe/Clear JButton (mbean notifications case)
private JButton clearButton, subscribeButton, unsubscribeButton;
// Reference to MBeans tab
private MBeansTab mbeansTab;
public XSheet(MBeansTab mbeansTab) {
this.mbeansTab = mbeansTab;
setupScreen();
}
public void dispose() {
clear();
XDataViewer.dispose(mbeansTab);
mbeanNotifications.dispose();
}
private void setupScreen() {
setLayout(new BorderLayout());
setBorder(BorderFactory.createLineBorder(Color.GRAY));
// add main panel to XSheet
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
add(mainPanel, BorderLayout.CENTER);
// add south panel to XSheet
southPanel = new JPanel();
add(southPanel, BorderLayout.SOUTH);
// create the refresh button
String refreshButtonKey = "MBeansTab.refreshAttributesButton";
refreshButton = new JButton(getText(refreshButtonKey));
refreshButton.setMnemonic(getMnemonicInt(refreshButtonKey));
refreshButton.setToolTipText(getText(refreshButtonKey + ".toolTip"));
refreshButton.addActionListener(this);
// create the clear button
String clearButtonKey = "MBeansTab.clearNotificationsButton";
clearButton = new JButton(getText(clearButtonKey));
clearButton.setMnemonic(getMnemonicInt(clearButtonKey));
clearButton.setToolTipText(getText(clearButtonKey + ".toolTip"));
clearButton.addActionListener(this);
// create the subscribe button
String subscribeButtonKey = "MBeansTab.subscribeNotificationsButton";
subscribeButton = new JButton(getText(subscribeButtonKey));
subscribeButton.setMnemonic(getMnemonicInt(subscribeButtonKey));
subscribeButton.setToolTipText(getText(subscribeButtonKey + ".toolTip"));
subscribeButton.addActionListener(this);
// create the unsubscribe button
String unsubscribeButtonKey = "MBeansTab.unsubscribeNotificationsButton";
unsubscribeButton = new JButton(getText(unsubscribeButtonKey));
unsubscribeButton.setMnemonic(getMnemonicInt(unsubscribeButtonKey));
unsubscribeButton.setToolTipText(getText(unsubscribeButtonKey + ".toolTip"));
unsubscribeButton.addActionListener(this);
// create XMBeanAttributes container
mbeanAttributes = new XMBeanAttributes(mbeansTab);
// create XMBeanOperations container
mbeanOperations = new XMBeanOperations(mbeansTab);
mbeanOperations.addOperationsListener(this);
// create XMBeanNotifications container
mbeanNotifications = new XMBeanNotifications();
mbeanNotifications.addNotificationsListener(this);
// create XMBeanInfo container
mbeanInfo = new XMBeanInfo();
}
private boolean isSelectedNode(DefaultMutableTreeNode n, DefaultMutableTreeNode cn) {
return (cn == n);
}
// Call on EDT
private void showErrorDialog(Object message, String title) {
new ThreadDialog(this, message, title, JOptionPane.ERROR_MESSAGE).run();
}
public boolean isMBeanNode(DefaultMutableTreeNode node) {
Object userObject = node.getUserObject();
if (userObject instanceof XNodeInfo) {
XNodeInfo uo = (XNodeInfo) userObject;
return uo.getType().equals(Type.MBEAN);
}
return false;
}
// Call on EDT
public synchronized void displayNode(DefaultMutableTreeNode node) {
clear();
displayEmptyNode();
if (node == null) {
return;
}
currentNode = node;
Object userObject = node.getUserObject();
if (userObject instanceof XNodeInfo) {
XNodeInfo uo = (XNodeInfo) userObject;
switch (uo.getType()) {
case MBEAN:
displayMBeanNode(node);
break;
case NONMBEAN:
displayEmptyNode();
break;
case ATTRIBUTES:
displayMBeanAttributesNode(node);
break;
case OPERATIONS:
displayMBeanOperationsNode(node);
break;
case NOTIFICATIONS:
displayMBeanNotificationsNode(node);
break;
case ATTRIBUTE:
case OPERATION:
case NOTIFICATION:
displayMetadataNode(node);
break;
default:
displayEmptyNode();
break;
}
} else {
displayEmptyNode();
}
}
// Call on EDT
private void displayMBeanNode(final DefaultMutableTreeNode node) {
final XNodeInfo uo = (XNodeInfo) node.getUserObject();
if (!uo.getType().equals(Type.MBEAN)) {
return;
}
mbean = (XMBean) uo.getData();
SwingWorker<MBeanInfo, Void> sw = new SwingWorker<MBeanInfo, Void>() {
@Override
public MBeanInfo doInBackground() throws InstanceNotFoundException,
IntrospectionException, ReflectionException, IOException {
return mbean.getMBeanInfo();
}
@Override
protected void done() {
try {
MBeanInfo mbi = get();
if (mbi != null) {
if (!isSelectedNode(node, currentNode)) {
return;
}
mbeanInfo.addMBeanInfo(mbean, mbi);
invalidate();
mainPanel.removeAll();
mainPanel.add(mbeanInfo, BorderLayout.CENTER);
southPanel.setVisible(false);
southPanel.removeAll();
validate();
repaint();
}
} catch (Exception e) {
Throwable t = Utils.getActualException(e);
if (JConsole.isDebug()) {
System.err.println("Couldn't get MBeanInfo for MBean [" +
mbean.getObjectName() + "]");
t.printStackTrace();
}
showErrorDialog(t.toString(),
Resources.getText("Problem displaying MBean"));
}
}
};
sw.execute();
}
// Call on EDT
private void displayMetadataNode(final DefaultMutableTreeNode node) {
final XNodeInfo uo = (XNodeInfo) node.getUserObject();
final XMBeanInfo mbi = mbeanInfo;
switch (uo.getType()) {
case ATTRIBUTE:
SwingWorker<MBeanAttributeInfo, Void> sw =
new SwingWorker<MBeanAttributeInfo, Void>() {
@Override
public MBeanAttributeInfo doInBackground() {
Object attrData = uo.getData();
mbean = (XMBean) ((Object[]) attrData)[0];
MBeanAttributeInfo mbai =
(MBeanAttributeInfo) ((Object[]) attrData)[1];
mbeanAttributes.loadAttributes(mbean, new MBeanInfo(
null, null, new MBeanAttributeInfo[]{mbai},
null, null, null));
return mbai;
}
@Override
protected void done() {
try {
MBeanAttributeInfo mbai = get();
if (!isSelectedNode(node, currentNode)) {
return;
}
invalidate();
mainPanel.removeAll();
JPanel attributePanel =
new JPanel(new BorderLayout());
JPanel attributeBorderPanel =
new JPanel(new BorderLayout());
attributeBorderPanel.setBorder(
BorderFactory.createTitledBorder(
Resources.getText("Attribute value")));
JPanel attributeValuePanel =
new JPanel(new BorderLayout());
attributeValuePanel.setBorder(
LineBorder.createGrayLineBorder());
attributeValuePanel.add(mbeanAttributes.getTableHeader(),
BorderLayout.PAGE_START);
attributeValuePanel.add(mbeanAttributes,
BorderLayout.CENTER);
attributeBorderPanel.add(attributeValuePanel,
BorderLayout.CENTER);
JPanel refreshButtonPanel = new JPanel();
refreshButtonPanel.add(refreshButton);
attributeBorderPanel.add(refreshButtonPanel,
BorderLayout.SOUTH);
refreshButton.setEnabled(true);
attributePanel.add(attributeBorderPanel,
BorderLayout.NORTH);
mbi.addMBeanAttributeInfo(mbai);
attributePanel.add(mbi, BorderLayout.CENTER);
mainPanel.add(attributePanel,
BorderLayout.CENTER);
southPanel.setVisible(false);
southPanel.removeAll();
validate();
repaint();
} catch (Exception e) {
Throwable t = Utils.getActualException(e);
if (JConsole.isDebug()) {
System.err.println("Problem displaying MBean " +
"attribute for MBean [" +
mbean.getObjectName() + "]");
t.printStackTrace();
}
showErrorDialog(t.toString(),
Resources.getText("Problem displaying MBean"));
}
}
};
sw.execute();
break;
case OPERATION:
Object operData = uo.getData();
mbean = (XMBean) ((Object[]) operData)[0];
MBeanOperationInfo mboi =
(MBeanOperationInfo) ((Object[]) operData)[1];
mbeanOperations.loadOperations(mbean,
new MBeanInfo(null, null, null, null,
new MBeanOperationInfo[]{mboi}, null));
invalidate();
mainPanel.removeAll();
JPanel operationPanel = new JPanel(new BorderLayout());
JPanel operationBorderPanel = new JPanel(new BorderLayout());
operationBorderPanel.setBorder(BorderFactory.createTitledBorder(
Resources.getText("Operation invocation")));
operationBorderPanel.add(new JScrollPane(mbeanOperations));
operationPanel.add(operationBorderPanel, BorderLayout.NORTH);
mbi.addMBeanOperationInfo(mboi);
operationPanel.add(mbi, BorderLayout.CENTER);
mainPanel.add(operationPanel, BorderLayout.CENTER);
southPanel.setVisible(false);
southPanel.removeAll();
validate();
repaint();
break;
case NOTIFICATION:
Object notifData = uo.getData();
invalidate();
mainPanel.removeAll();
mbi.addMBeanNotificationInfo((MBeanNotificationInfo) notifData);
mainPanel.add(mbi, BorderLayout.CENTER);
southPanel.setVisible(false);
southPanel.removeAll();
validate();
repaint();
break;
}
}
// Call on EDT
private void displayMBeanAttributesNode(final DefaultMutableTreeNode node) {
final XNodeInfo uo = (XNodeInfo) node.getUserObject();
if (!uo.getType().equals(Type.ATTRIBUTES)) {
return;
}
mbean = (XMBean) uo.getData();
final XMBean xmb = mbean;
SwingWorker<MBeanInfo,Void> sw = new SwingWorker<MBeanInfo,Void>() {
@Override
public MBeanInfo doInBackground() throws InstanceNotFoundException,
IntrospectionException, ReflectionException, IOException {
MBeanInfo mbi = xmb.getMBeanInfo();
return mbi;
}
@Override
protected void done() {
try {
MBeanInfo mbi = get();
if (mbi != null && mbi.getAttributes() != null &&
mbi.getAttributes().length > 0) {
mbeanAttributes.loadAttributes(xmb, mbi);
if (!isSelectedNode(node, currentNode)) {
return;
}
invalidate();
mainPanel.removeAll();
JPanel borderPanel = new JPanel(new BorderLayout());
borderPanel.setBorder(BorderFactory.createTitledBorder(
Resources.getText("Attribute values")));
borderPanel.add(new JScrollPane(mbeanAttributes));
mainPanel.add(borderPanel, BorderLayout.CENTER);
// add the refresh button to the south panel
southPanel.removeAll();
southPanel.add(refreshButton, BorderLayout.SOUTH);
southPanel.setVisible(true);
refreshButton.setEnabled(true);
validate();
repaint();
}
} catch (Exception e) {
Throwable t = Utils.getActualException(e);
if (JConsole.isDebug()) {
System.err.println("Problem displaying MBean " +
"attributes for MBean [" +
mbean.getObjectName() + "]");
t.printStackTrace();
}
showErrorDialog(t.toString(),
Resources.getText("Problem displaying MBean"));
}
}
};
sw.execute();
}
// Call on EDT
private void displayMBeanOperationsNode(final DefaultMutableTreeNode node) {
final XNodeInfo uo = (XNodeInfo) node.getUserObject();
if (!uo.getType().equals(Type.OPERATIONS)) {
return;
}
mbean = (XMBean) uo.getData();
SwingWorker<MBeanInfo, Void> sw = new SwingWorker<MBeanInfo, Void>() {
@Override
public MBeanInfo doInBackground() throws InstanceNotFoundException,
IntrospectionException, ReflectionException, IOException {
return mbean.getMBeanInfo();
}
@Override
protected void done() {
try {
MBeanInfo mbi = get();
if (mbi != null) {
if (!isSelectedNode(node, currentNode)) {
return;
}
mbeanOperations.loadOperations(mbean, mbi);
invalidate();
mainPanel.removeAll();
JPanel borderPanel = new JPanel(new BorderLayout());
borderPanel.setBorder(BorderFactory.createTitledBorder(
Resources.getText("Operation invocation")));
borderPanel.add(new JScrollPane(mbeanOperations));
mainPanel.add(borderPanel, BorderLayout.CENTER);
southPanel.setVisible(false);
southPanel.removeAll();
validate();
repaint();
}
} catch (Exception e) {
Throwable t = Utils.getActualException(e);
if (JConsole.isDebug()) {
System.err.println("Problem displaying MBean " +
"operations for MBean [" +
mbean.getObjectName() + "]");
t.printStackTrace();
}
showErrorDialog(t.toString(),
Resources.getText("Problem displaying MBean"));
}
}
};
sw.execute();
}
// Call on EDT
private void displayMBeanNotificationsNode(DefaultMutableTreeNode node) {
final XNodeInfo uo = (XNodeInfo) node.getUserObject();
if (!uo.getType().equals(Type.NOTIFICATIONS)) {
return;
}
mbean = (XMBean) uo.getData();
mbeanNotifications.loadNotifications(mbean);
updateNotifications();
invalidate();
mainPanel.removeAll();
JPanel borderPanel = new JPanel(new BorderLayout());
borderPanel.setBorder(BorderFactory.createTitledBorder(
Resources.getText("Notification buffer")));
borderPanel.add(new JScrollPane(mbeanNotifications));
mainPanel.add(borderPanel, BorderLayout.CENTER);
// add the subscribe/unsubscribe/clear buttons to the south panel
southPanel.removeAll();
southPanel.add(subscribeButton, BorderLayout.WEST);
southPanel.add(unsubscribeButton, BorderLayout.CENTER);
southPanel.add(clearButton, BorderLayout.EAST);
southPanel.setVisible(true);
subscribeButton.setEnabled(true);
unsubscribeButton.setEnabled(true);
clearButton.setEnabled(true);
validate();
repaint();
}
// Call on EDT
private void displayEmptyNode() {
invalidate();
mainPanel.removeAll();
southPanel.removeAll();
validate();
repaint();
}
/**
* Subscribe button action.
*/
private void registerListener() {
new SwingWorker<Void, Void>() {
@Override
public Void doInBackground()
throws InstanceNotFoundException, IOException {
mbeanNotifications.registerListener(currentNode);
return null;
}
@Override
protected void done() {
try {
get();
updateNotifications();
validate();
} catch (Exception e) {
Throwable t = Utils.getActualException(e);
if (JConsole.isDebug()) {
System.err.println("Problem adding listener");
t.printStackTrace();
}
showErrorDialog(t.getMessage(),
Resources.getText("Problem adding listener"));
}
}
}.execute();
}
/**
* Unsubscribe button action.
*/
private void unregisterListener() {
new SwingWorker<Boolean, Void>() {
@Override
public Boolean doInBackground() {
return mbeanNotifications.unregisterListener(currentNode);
}
@Override
protected void done() {
try {
if (get()) {
updateNotifications();
validate();
}
} catch (Exception e) {
Throwable t = Utils.getActualException(e);
if (JConsole.isDebug()) {
System.err.println("Problem removing listener");
t.printStackTrace();
}
showErrorDialog(t.getMessage(),
Resources.getText("Problem removing listener"));
}
}
}.execute();
}
/**
* Refresh button action.
*/
private void refreshAttributes() {
mbeanAttributes.refreshAttributes();
}
// Call on EDT
private void updateNotifications() {
if (mbeanNotifications.isListenerRegistered(mbean)) {
long received = mbeanNotifications.getReceivedNotifications(mbean);
updateReceivedNotifications(currentNode, received, false);
} else {
clearNotifications();
}
}
/**
* Update notification node label in MBean tree: "Notifications[received]".
*/
// Call on EDT
private void updateReceivedNotifications(
DefaultMutableTreeNode emitter, long received, boolean bold) {
String text = Resources.getText("Notifications") + "[" + received + "]";
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) mbeansTab.getTree().getLastSelectedPathComponent();
if (bold && emitter != selectedNode) {
text = "<html><b>" + text + "</b></html>";
}
updateNotificationsNodeLabel(emitter, text);
}
/**
* Update notification node label in MBean tree: "Notifications".
*/
// Call on EDT
private void clearNotifications() {
updateNotificationsNodeLabel(currentNode,
Resources.getText("Notifications"));
}
/**
* Update notification node label in MBean tree: "Notifications[0]".
*/
// Call on EDT
private void clearNotifications0() {
updateNotificationsNodeLabel(currentNode,
Resources.getText("Notifications") + "[0]");
}
/**
* Update the label of the supplied MBean tree node.
*/
// Call on EDT
private void updateNotificationsNodeLabel(
DefaultMutableTreeNode node, String label) {
synchronized (mbeansTab.getTree()) {
invalidate();
XNodeInfo oldUserObject = (XNodeInfo) node.getUserObject();
XNodeInfo newUserObject = new XNodeInfo(
oldUserObject.getType(), oldUserObject.getData(),
label, oldUserObject.getToolTipText());
node.setUserObject(newUserObject);
DefaultTreeModel model =
(DefaultTreeModel) mbeansTab.getTree().getModel();
model.nodeChanged(node);
validate();
repaint();
}
}
/**
* Clear button action.
*/
// Call on EDT
private void clearCurrentNotifications() {
mbeanNotifications.clearCurrentNotifications();
if (mbeanNotifications.isListenerRegistered(mbean)) {
// Update notifs in MBean tree "Notifications[0]".
//
// Notification buffer has been cleared with a listener been
// registered so add "[0]" at the end of the node label.
//
clearNotifications0();
} else {
// Update notifs in MBean tree "Notifications".
//
// Notification buffer has been cleared without a listener been
// registered so don't add "[0]" at the end of the node label.
//
clearNotifications();
}
}
// Call on EDT
private void clear() {
mbeanAttributes.stopCellEditing();
mbeanAttributes.emptyTable();
mbeanAttributes.removeAttributes();
mbeanOperations.removeOperations();
mbeanNotifications.stopCellEditing();
mbeanNotifications.emptyTable();
mbeanNotifications.disableNotifications();
mbean = null;
currentNode = null;
}
/**
* Notification listener: handles asynchronous reception
* of MBean operation results and MBean notifications.
*/
// Call on EDT
public void handleNotification(Notification e, Object handback) {
// Operation result
if (e.getType().equals(XOperations.OPERATION_INVOCATION_EVENT)) {
final Object message;
if (handback == null) {
JTextArea textArea = new JTextArea("null");
textArea.setEditable(false);
textArea.setEnabled(true);
textArea.setRows(textArea.getLineCount());
message = textArea;
} else {
Component comp = mbeansTab.getDataViewer().
createOperationViewer(handback, mbean);
if (comp == null) {
JTextArea textArea = new JTextArea(handback.toString());
textArea.setEditable(false);
textArea.setEnabled(true);
textArea.setRows(textArea.getLineCount());
JScrollPane scrollPane = new JScrollPane(textArea);
Dimension d = scrollPane.getPreferredSize();
if (d.getWidth() > 400 || d.getHeight() > 250) {
scrollPane.setPreferredSize(new Dimension(400, 250));
}
message = scrollPane;
} else {
if (!(comp instanceof JScrollPane)) {
comp = new JScrollPane(comp);
}
Dimension d = comp.getPreferredSize();
if (d.getWidth() > 400 || d.getHeight() > 250) {
comp.setPreferredSize(new Dimension(400, 250));
}
message = comp;
}
}
new ThreadDialog(
(Component) e.getSource(),
message,
Resources.getText("Operation return value"),
JOptionPane.INFORMATION_MESSAGE).run();
} // Got notification
else if (e.getType().equals(
XMBeanNotifications.NOTIFICATION_RECEIVED_EVENT)) {
DefaultMutableTreeNode emitter = (DefaultMutableTreeNode) handback;
Long received = (Long) e.getUserData();
updateReceivedNotifications(emitter, received.longValue(), true);
}
}
/**
* Action listener: handles actions in panel buttons
*/
// Call on EDT
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
JButton button = (JButton) e.getSource();
// Refresh button
if (button == refreshButton) {
refreshAttributes();
return;
}
// Clear button
if (button == clearButton) {
clearCurrentNotifications();
return;
}
// Subscribe button
if (button == subscribeButton) {
registerListener();
return;
}
// Unsubscribe button
if (button == unsubscribeButton) {
unregisterListener();
return;
}
}
}
}