/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.tools.ui.cybernodeutilization;
import net.jini.core.lookup.ServiceItem;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.AbstractMutableTreeTableNode;
import org.jdesktop.swingx.treetable.TreeTableNode;
import org.rioproject.cybernode.Cybernode;
import org.rioproject.cybernode.CybernodeAdmin;
import org.rioproject.impl.jmx.JMXUtil;
import org.rioproject.tools.ui.Constants;
import org.rioproject.tools.ui.GraphViewAdapter;
import org.rioproject.tools.ui.UtilizationColumnManager;
import org.rioproject.tools.ui.servicenotification.DeploymentNode;
import org.rioproject.ui.Util;
import org.rioproject.system.ComputeResourceUtilization;
import org.rioproject.tools.ui.serviceui.ServiceAdminManager;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* The CybernodeUtilizationPanel displays graphed and tabular information about
* Cybernode Utilization
*
* @author Dennis Reedy
*/
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
public class CybernodeUtilizationPanel extends JPanel {
/**
* The model for the Cybernode utilization table
*/
private UtilizationTreeModel utilizationModel;
private final JXTreeTable treeTable;
/**
* For showing cybernode stats
*/
private JPanel statusPanel;
private final ServiceAdminManager adminManager = ServiceAdminManager.getInstance();
/* a reference to 'self' */
private JPanel component;
private boolean expandAll = false;
private final GraphViewAdapter graphViewAdapter;
public CybernodeUtilizationPanel(final GraphViewAdapter graphViewAdapter,
final String[] selectedColumns,
final Properties props) {
super(new BorderLayout(8, 8));
this.graphViewAdapter = graphViewAdapter;
String s = props.getProperty(Constants.TREE_TABLE_AUTO_EXPAND);
expandAll = (s != null && Boolean.parseBoolean(s));
List<String> columns = getColumns(selectedColumns);
treeTable = /*new JXTreeTable();*/
new JXTreeTable() {
@Override public TableCellRenderer getCellRenderer(int row, int column) {
Object value;
try {
value = super.getValueAt(row, column);
} catch (IllegalArgumentException e) {
value = null;
}
if(value != null) {
if(value instanceof JLabel) {
return new JLabelCellRenderer(((JLabel)value));
}
return super.getCellRenderer(row, column);
}
return super.getCellRenderer(row, column);
}
};
treeTable.setAutoCreateColumnsFromModel(true);
utilizationModel = createModel(columns);
treeTable.setTreeTableModel(utilizationModel);
treeTable.setRootVisible(false);
treeTable.setShowsRootHandles(true);
treeTable.setAutoCreateColumnsFromModel(false);
treeTable.getTableHeader().setReorderingAllowed(false);
//no icons
treeTable.setLeafIcon(null);
treeTable.setOpenIcon(null);
treeTable.setClosedIcon(null);
component = this;
treeTable.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int row = treeTable.getSelectedRow();
if(row==-1) {
return;
}
if(e.isPopupTrigger()) {
showPopup(e, row);
}
}
public void mouseReleased(MouseEvent e) {
int row = treeTable.getSelectedRow();
if(!e.isPopupTrigger() || row==-1) {
return;
}
showPopup(e, row);
}
private void showPopup(MouseEvent e, int row) {
CybernodeNode cNode = utilizationModel.getCybernodeNode(row);
ServiceNode sNode = null;
final String label;
boolean showJConsoleOption = true;
if(cNode == null) {
sNode = utilizationModel.getServiceNode(row);
if(sNode==null)
return;
label = sNode.getName();
if(!sNode.isForked())
showJConsoleOption=false;
} else {
label = "Cybernode Admin";
}
final ServiceItemAccessor serviceItemAccessor = new ServiceItemAccessor(cNode==null?sNode:cNode);
JPopupMenu popup = new JPopupMenu();
JMenuItem serviceUI = new JMenuItem("Show "+label+" UI");
serviceUI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
adminManager.doShowAdminUI(serviceItemAccessor.getServiceItem(), graphViewAdapter.getMain());
}
});
JMenuItem jconsole = null;
if(showJConsoleOption) {
jconsole = new JMenuItem("Launch JConsole");
final ServiceItem serviceItem = serviceItemAccessor.getServiceItem();
if(serviceItem!=null) {
jconsole.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String jmxConn = JMXUtil.getJMXConnection(serviceItem.attributeSets);
if(jmxConn==null) {
JOptionPane.showMessageDialog(null,
"There is no JMX connectivity information for ["+label+"], " +
"unable to start a JConsole",
"Missing JMX Entries",
JOptionPane.WARNING_MESSAGE);
return;
}
try {
Runtime.getRuntime().exec("jconsole "+jmxConn);
} catch (IOException e1) {
Util.showError(e1, component, "Creating jconsole");
}
}
});
} else {
JOptionPane.showMessageDialog(null,
"There is no ServiceItem for ["+label+"]",
"Missing ServiceItem",
JOptionPane.WARNING_MESSAGE);
}
}
popup.add(serviceUI);
if(jconsole!=null) {
popup.addSeparator();
popup.add(jconsole);
}
popup.pack();
popup.show(e.getComponent(), e.getX(), e.getY());
}
public void mouseClicked(MouseEvent e) {
int row = treeTable.getSelectedRow();
if (row == -1)
return;
if (e.getClickCount() == 2) {
AbstractMutableTreeTableNode node = utilizationModel.getNode(row);
if(node instanceof ServiceNode) {
ServiceItem item = graphViewAdapter.getServiceItem(((ServiceNode)node).getServiceElement(),
((ServiceNode)node).getUuid());
if(item!=null)
adminManager.doShowAdminUI(item, graphViewAdapter.getMain());
} else if(node instanceof CybernodeNode) {
ServiceItem item = ((CybernodeNode)node).getServiceItem();
if(item!=null)
adminManager.doShowAdminUI(item, graphViewAdapter.getMain());
}
} else if(e.getClickCount()==1) {
AbstractMutableTreeTableNode node = utilizationModel.getNode(row);
if(node instanceof DeploymentNode) {
if(treeTable.isExpanded(row)) {
treeTable.collapseRow(row);
} else {
treeTable.expandRow(row);
}
}
}
}
});
//treeTable.setColumnSelectionAllowed(false);
//treeTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
JToolBar toolBar = new JToolBar(JToolBar.HORIZONTAL);
toolBar.setFloatable(false);
toolBar.setRollover(true);
toolBar.setBorderPainted(false);
ImageIcon collapseIcon = Util.getImageIcon("org/rioproject/tools/ui/images/collapseall.gif");
ImageIcon expandIcon = Util.getImageIcon("org/rioproject/tools/ui/images/expandall.gif");
ImageIcon refreshIcon = null;
if(expandIcon!=null) {
refreshIcon = Util.getScaledImageIcon("org/rioproject/tools/ui/images/view-refresh.png",
expandIcon.getIconWidth(),
expandIcon.getIconHeight());
}
JButton collapse = new JButton();
collapse.setIcon(collapseIcon);
collapse.setPreferredSize(new Dimension(22, 22));
collapse.setMaximumSize(new Dimension(22, 22));
collapse.setToolTipText("Collapse all Cybernodes");
collapse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int row = treeTable.getRowCount() - 1;
while (row >= 0) {
treeTable.collapseRow(row);
row--;
}
expandAll = false;
}
});
JButton expand = new JButton();
expand.setIcon(expandIcon);
expand.setPreferredSize(new Dimension(22, 22));
expand.setMaximumSize(new Dimension(22, 22));
expand.setToolTipText("Expand all Cybernodes");
expand.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int row = 0;
while (row < treeTable.getRowCount()) {
treeTable.expandRow(row);
row++;
}
expandAll = true;
}
});
final JButton refresh = new JButton(refreshIcon);
refresh.setPreferredSize(new Dimension(22, 22));
refresh.setMaximumSize(new Dimension(22, 22));
refresh.getAccessibleContext().setAccessibleName("refresh utilization values");
refresh.setToolTipText("Refresh the utilization values");
toolBar.add(collapse);
toolBar.add(expand);
toolBar.add(refresh);
refresh.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
graphViewAdapter.refreshCybernodeTable();
}
});
JScrollPane sp2 = new JScrollPane(treeTable);
sp2.getViewport().setBackground(Color.WHITE);
statusPanel = new StatusPanel(utilizationModel);
statusPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 8));
String bannerIcon = props.getProperty("bannerIcon");
if(bannerIcon!=null) {
ImageIcon icon = Util.getImageIcon(bannerIcon);
JLabel l = new JLabel(icon);
//l.setBorder(BorderFactory.createEtchedBorder());
statusPanel.add(l, BorderLayout.NORTH);
}
statusPanel.add(toolBar, BorderLayout.NORTH);
//statusPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, 70));
statusPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, 40));
statusPanel.setBorder(BorderFactory.createEtchedBorder());
add(statusPanel, BorderLayout.NORTH);
add(sp2, BorderLayout.CENTER);
}
private List<String> getColumns(String... column) {
List<String> columns = new ArrayList<String>();
columns.add(ColumnValueHelper.FIXED_COLUMN);
Collections.addAll(columns, column);
return columns;
}
private UtilizationTreeModel createModel(List<String> columns) {
if(utilizationModel==null) {
utilizationModel = new UtilizationTreeModel(new RootNode(), columns, treeTable);
utilizationModel.setExpandAll(expandAll);
} else {
utilizationModel.setColumnIdentifiers(columns);
}
return utilizationModel;
}
public boolean getExpandAll() {
return expandAll;
}
public int getCount() {
return treeTable.getRowCount();
}
public void addCybernode(final ServiceItem item,
final CybernodeAdmin admin,
final ComputeResourceUtilization cru,
final UtilizationColumnManager utilizationColumnManager) {
CybernodeNode node = new CybernodeNode(item,
admin,
cru,
new ColumnValueHelper(utilizationColumnManager, treeTable));
utilizationModel.addCybernodeNode(node);
statusPanel.repaint();
}
public void removeCybernode(Cybernode item) {
utilizationModel.removeCybernode(item);
statusPanel.repaint();
}
public void update(final ServiceItem item,
final CybernodeAdmin admin,
final ComputeResourceUtilization cru,
final UtilizationColumnManager utilizationColumnManager) {
CybernodeNode node = new CybernodeNode(item,
admin,
cru,
new ColumnValueHelper(utilizationColumnManager, treeTable));
utilizationModel.updateCybernode(node);
}
public void updateCybernodesAt(final String hostAddress) {
utilizationModel.updateCybernodesAt(hostAddress);
}
/**
* Renderer for nodes that use a JLabel
*/
class JLabelCellRenderer extends DefaultTableCellRenderer {
final JLabel label;
public JLabelCellRenderer(JLabel label) {
super();
this.label = label;
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
setValue(value);
return label;
}
}
class ServiceItemAccessor {
TreeTableNode node;
ServiceItemAccessor(TreeTableNode node) {
this.node = node;
}
ServiceItem getServiceItem() {
ServiceItem item;
if(node instanceof CybernodeNode) {
item = ((CybernodeNode)node).getServiceItem();
} else {
item = graphViewAdapter.getServiceItem(((ServiceNode)node).getServiceElement(),
((ServiceNode)node).getUuid());
}
return item;
}
}
class RootNode extends AbstractMutableTreeTableNode {
@Override
public Object getValueAt(int i) {
return null;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public boolean getAllowsChildren() {
return true;
}
}
}