package org.rrd4j.inspector;
import org.rrd4j.ConsolFun;
import org.rrd4j.core.ArcDef;
import org.rrd4j.core.DsDef;
import org.rrd4j.core.RrdDb;
import org.rrd4j.core.RrdToolkit;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
/**
* Utility application (swing) to analyze, change and plot content of Rrd4j RRD files.
*/
public class RrdInspector extends JFrame {
static final boolean SHOULD_CREATE_BACKUPS = true;
static final String TITLE = "RRD File Inspector";
static final boolean SHOULD_FIX_ARCHIVED_VALUES = false;
static final Dimension MAIN_TREE_SIZE = new Dimension(250, 400);
static final Dimension INFO_PANE_SIZE = new Dimension(450, 400);
static final String ABOUT = "RRD4J\nRRD File Inspector\n" +
"Copyright (c) 2013 The RRD4J Authors. Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. Copyright (c) 2013 The OpenNMS Group, Inc. Licensed under the Apache License, Version 2.0.";
private static final String JSCROLL_BAR_FAST_WHEEL_SCROLLING = "JScrollBar.fastWheelScrolling";
private static final String OPEN_A_VALID_RRD_FILE_FIRST = "Open a valid RRD file first.";
private static final String SELECT_ARCHIVE_FIRST = "Select archive first";
JTabbedPane tabbedPane = new JTabbedPane();
private JTree mainTree = new JTree();
private JSplitPane splitPane = new JSplitPane();
private JTable generalTable = new JTable();
private JTable datasourceTable = new JTable();
private JTable archiveTable = new JTable();
private JTable dataTable = new JTable();
private InspectorModel inspectorModel = new InspectorModel();
private String lastDirectory = null;
private RrdInspector(String path) throws Exception {
super(TITLE);
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
constructUI();
pack();
}
});
Util.placeWindow(this);
setVisible(true);
if (path == null) {
selectFile();
} else {
loadFile(new File(path));
}
}
private void constructUI() {
JPanel content = (JPanel) getContentPane();
content.setLayout(new BorderLayout());
// NORTH
JToolBar toolBar = new JToolBar();
getContentPane().add(toolBar, BorderLayout.NORTH);
toolBar.setFloatable(true);
JButton openButton = new JButton(loadIcon("open-24.png"));
openButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectFile();
}
});
toolBar.add(openButton);
final JButton plotButton = new JButton(loadIcon("graph-24.gif"));
plotButton.setEnabled(false);
plotButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
plotArchive();
}
});
toolBar.add(plotButton);
// tree pane
JPanel leftPanel = new JPanel();
leftPanel.setLayout(new BorderLayout());
JScrollPane treePane = new JScrollPane(mainTree);
treePane.putClientProperty(JSCROLL_BAR_FAST_WHEEL_SCROLLING, Boolean.TRUE);
leftPanel.add(treePane);
leftPanel.setPreferredSize(MAIN_TREE_SIZE);
splitPane.setLeftComponent(leftPanel);
splitPane.setOneTouchExpandable(true);
mainTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
mainTree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
nodeChangedAction();
plotButton.setEnabled(isArchiveNode(getSelectedRrdNode()));
}
});
mainTree.setModel(inspectorModel.getMainTreeModel());
////////////////////////////////////////////
// EAST, tabbed pane
////////////////////////////////////////////
// GENERAL TAB
JScrollPane spGeneral = new JScrollPane(generalTable);
spGeneral.putClientProperty(JSCROLL_BAR_FAST_WHEEL_SCROLLING, Boolean.TRUE);
spGeneral.setPreferredSize(INFO_PANE_SIZE);
tabbedPane.add("General info", spGeneral);
generalTable.setModel(inspectorModel.getGeneralTableModel());
generalTable.getColumnModel().getColumn(0).setPreferredWidth(150);
generalTable.getColumnModel().getColumn(0).setMaxWidth(150);
// DATASOURCE TAB
JScrollPane spDatasource = new JScrollPane(datasourceTable);
spDatasource.putClientProperty(JSCROLL_BAR_FAST_WHEEL_SCROLLING, Boolean.TRUE);
spDatasource.setPreferredSize(INFO_PANE_SIZE);
tabbedPane.add("Datasource info", spDatasource);
datasourceTable.setModel(inspectorModel.getDatasourceTableModel());
datasourceTable.getColumnModel().getColumn(0).setPreferredWidth(150);
datasourceTable.getColumnModel().getColumn(0).setMaxWidth(150);
// ARCHIVE TAB
JScrollPane spArchive = new JScrollPane(archiveTable);
spArchive.putClientProperty(JSCROLL_BAR_FAST_WHEEL_SCROLLING, Boolean.TRUE);
archiveTable.setModel(inspectorModel.getArchiveTableModel());
archiveTable.getColumnModel().getColumn(0).setPreferredWidth(150);
archiveTable.getColumnModel().getColumn(0).setMaxWidth(150);
spArchive.setPreferredSize(INFO_PANE_SIZE);
tabbedPane.add("Archive info", spArchive);
// DATA TAB
JScrollPane spData = new JScrollPane(dataTable);
spData.putClientProperty(JSCROLL_BAR_FAST_WHEEL_SCROLLING, Boolean.TRUE);
dataTable.setModel(inspectorModel.getDataTableModel());
dataTable.getColumnModel().getColumn(0).setPreferredWidth(100);
dataTable.getColumnModel().getColumn(0).setMaxWidth(100);
dataTable.getColumnModel().getColumn(1).setPreferredWidth(150);
dataTable.getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
{
setBackground(Color.YELLOW);
}
});
spData.setPreferredSize(INFO_PANE_SIZE);
tabbedPane.add("Archive data", spData);
splitPane.setRightComponent(tabbedPane);
content.add(splitPane, BorderLayout.CENTER);
////////////////////////////////////////
// MENU
////////////////////////////////////////
JMenuBar menuBar = new JMenuBar();
// FILE MENU
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
// Open file
JMenuItem fileMenuItem = new JMenuItem("Open RRD file...", KeyEvent.VK_O);
fileMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectFile();
}
});
fileMenu.add(fileMenuItem);
// Open file in new window
JMenuItem fileMenuItem2 = new JMenuItem("Open RRD file in new window...");
fileMenuItem2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
new RrdInspector(null);
} catch (Exception e1) {
}
}
});
fileMenu.add(fileMenuItem2);
fileMenu.addSeparator();
// Add datasource
JMenuItem addDatasourceMenuItem = new JMenuItem("Add datasource...");
addDatasourceMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addDatasource();
}
});
fileMenu.add(addDatasourceMenuItem);
// Edit datasource
JMenuItem editDatasourceMenuItem = new JMenuItem("Edit datasource...");
editDatasourceMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editDatasource();
}
});
fileMenu.add(editDatasourceMenuItem);
// Remove datasource
JMenuItem removeDatasourceMenuItem = new JMenuItem("Remove datasource");
removeDatasourceMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
removeDatasource();
}
});
fileMenu.add(removeDatasourceMenuItem);
fileMenu.addSeparator();
// Add archive
JMenuItem addArchiveMenuItem = new JMenuItem("Add archive...");
addArchiveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addArchive();
}
});
fileMenu.add(addArchiveMenuItem);
// Edit archive
JMenuItem editArchiveMenuItem = new JMenuItem("Edit archive...");
editArchiveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editArchive();
}
});
fileMenu.add(editArchiveMenuItem);
// Remove archive
JMenuItem removeArchiveMenuItem = new JMenuItem("Remove archive");
removeArchiveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
removeArchive();
}
});
fileMenu.add(removeArchiveMenuItem);
// Plot archive values
JMenuItem plotArchiveMenuItem = new JMenuItem("Plot archive values...");
plotArchiveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
plotArchive();
}
});
fileMenu.add(plotArchiveMenuItem);
fileMenu.addSeparator();
// Exit
JMenuItem exitMenuItem = new JMenuItem("Exit", KeyEvent.VK_X);
exitMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
fileMenu.add(exitMenuItem);
// HELP MENU
JMenu helpMenu = new JMenu("Help");
fileMenu.setMnemonic(KeyEvent.VK_H);
// About
JMenuItem aboutMenuItem = new JMenuItem("About...", KeyEvent.VK_A);
aboutMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
about();
}
});
helpMenu.add(aboutMenuItem);
menuBar.add(fileMenu);
menuBar.add(helpMenu);
setJMenuBar(menuBar);
// finalize UI
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
closeWindow();
}
});
}
private void closeWindow() {
Util.dismissWindow(this);
}
private void about() {
JOptionPane.showMessageDialog(this, ABOUT, "About", JOptionPane.INFORMATION_MESSAGE);
}
/**
* <p>loadIcon.</p>
*
* @param fileName a {@link java.lang.String} object.
* @return a {@link javax.swing.Icon} object.
*/
public static Icon loadIcon(String fileName) {
return new ImageIcon(RrdInspector.class.getResource("/" + fileName));
}
private void nodeChangedAction() {
RrdNode rrdNode = getSelectedRrdNode();
if (rrdNode != null) {
inspectorModel.selectModel(rrdNode.getDsIndex(), rrdNode.getArcIndex());
if (rrdNode.getDsIndex() >= 0 && rrdNode.getArcIndex() >= 0) {
// archive node
if (tabbedPane.getSelectedIndex() < 2) {
tabbedPane.setSelectedIndex(2);
}
} else if (rrdNode.getDsIndex() >= 0) {
tabbedPane.setSelectedIndex(1);
} else {
tabbedPane.setSelectedIndex(0);
}
}
}
private RrdNode getSelectedRrdNode() {
TreePath path = mainTree.getSelectionPath();
if (path != null) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
Object obj = node.getUserObject();
if (obj instanceof RrdNode) {
return (RrdNode) obj;
}
}
return null;
}
private void selectFile() {
JFileChooser chooser = new JFileChooser(lastDirectory);
FileFilter filter = new FileFilter() {
public boolean accept(File file) {
String path = file.getAbsolutePath().toLowerCase();
return file.isDirectory() || path.endsWith(".rrd") ||
path.endsWith(".jrb") || path.endsWith(".rrd4j");
}
public String getDescription() {
return "Rrd4j RRD files (*.rrd;*.jrb;*.rrd4j)";
}
};
chooser.setFileFilter(filter);
int returnVal = chooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
if (file != null) {
lastDirectory = file.getParent();
//inspectorModel.setFile(file);
//tabbedPane.setSelectedIndex(0);
loadFile(file);
}
}
}
private void loadFile(File file) {
inspectorModel.setFile(file);
tabbedPane.setSelectedIndex(0);
}
private void addDatasource() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
DsDef newDsDef = new EditDatasourceDialog(this, null).getDsDef();
if (newDsDef != null) {
// action
try {
String sourcePath = inspectorModel.getFile().getCanonicalPath();
RrdToolkit.addDatasource(sourcePath, newDsDef, SHOULD_CREATE_BACKUPS);
inspectorModel.refresh();
tabbedPane.setSelectedIndex(0);
}
catch (Exception e) {
Util.error(this, e);
}
}
}
private void addArchive() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
ArcDef newArcDef = new EditArchiveDialog(this, null).getArcDef();
if (newArcDef != null) {
// action
try {
String sourcePath = inspectorModel.getFile().getCanonicalPath();
RrdToolkit.addArchive(sourcePath, newArcDef, SHOULD_CREATE_BACKUPS);
inspectorModel.refresh();
tabbedPane.setSelectedIndex(0);
}
catch (Exception e) {
Util.error(this, e);
}
}
}
private void editDatasource() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
RrdNode rrdNode = getSelectedRrdNode();
int dsIndex = -1;
if (rrdNode == null || (dsIndex = rrdNode.getDsIndex()) < 0) {
Util.error(this, "Select datasource first");
return;
}
try {
String sourcePath = inspectorModel.getFile().getCanonicalPath();
RrdDb rrd = new RrdDb(sourcePath, true);
try {
DsDef dsDef = rrd.getRrdDef().getDsDefs()[dsIndex];
rrd.close();
DsDef newDsDef = new EditDatasourceDialog(this, dsDef).getDsDef();
if (newDsDef != null) {
// action!
RrdToolkit.setDsHeartbeat(sourcePath, newDsDef.getDsName(),
newDsDef.getHeartbeat());
RrdToolkit.setDsMinMaxValue(sourcePath, newDsDef.getDsName(),
newDsDef.getMinValue(), newDsDef.getMaxValue(), SHOULD_FIX_ARCHIVED_VALUES);
inspectorModel.refresh();
tabbedPane.setSelectedIndex(0);
}
}
finally {
rrd.close();
}
}
catch (Exception e) {
Util.error(this, e);
}
}
private void editArchive() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
RrdNode rrdNode = getSelectedRrdNode();
int arcIndex = -1;
if (rrdNode == null || (arcIndex = rrdNode.getArcIndex()) < 0) {
Util.error(this, SELECT_ARCHIVE_FIRST);
return;
}
try {
String sourcePath = inspectorModel.getFile().getCanonicalPath();
RrdDb rrd = new RrdDb(sourcePath, true);
try {
ArcDef arcDef = rrd.getRrdDef().getArcDefs()[arcIndex];
rrd.close();
ArcDef newArcDef = new EditArchiveDialog(this, arcDef).getArcDef();
if (newArcDef != null) {
// action!
// fix X-files factor
RrdToolkit.setArcXff(sourcePath, newArcDef.getConsolFun(),
newArcDef.getSteps(), newArcDef.getXff());
// fix archive size
RrdToolkit.resizeArchive(sourcePath, newArcDef.getConsolFun(),
newArcDef.getSteps(), newArcDef.getRows(), SHOULD_CREATE_BACKUPS);
inspectorModel.refresh();
tabbedPane.setSelectedIndex(0);
}
}
finally {
rrd.close();
}
}
catch (Exception e) {
Util.error(this, e);
}
}
private void removeDatasource() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
RrdNode rrdNode = getSelectedRrdNode();
int dsIndex = -1;
if (rrdNode == null || (dsIndex = rrdNode.getDsIndex()) < 0) {
Util.error(this, "Select datasource first");
return;
}
try {
String sourcePath = inspectorModel.getFile().getCanonicalPath(), dsName;
RrdDb rrd = new RrdDb(sourcePath, true);
try {
dsName = rrd.getRrdDef().getDsDefs()[dsIndex].getDsName();
}
finally {
rrd.close();
}
RrdToolkit.removeDatasource(sourcePath, dsName, SHOULD_CREATE_BACKUPS);
inspectorModel.refresh();
tabbedPane.setSelectedIndex(0);
}
catch (Exception e) {
Util.error(this, e);
}
}
private void removeArchive() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
RrdNode rrdNode = getSelectedRrdNode();
int arcIndex = -1;
if (rrdNode == null || (arcIndex = rrdNode.getArcIndex()) < 0) {
Util.error(this, SELECT_ARCHIVE_FIRST);
return;
}
try {
String sourcePath = inspectorModel.getFile().getCanonicalPath();
ConsolFun consolFun;
int steps;
RrdDb rrd = new RrdDb(sourcePath, true);
try {
ArcDef arcDef = rrd.getRrdDef().getArcDefs()[arcIndex];
consolFun = arcDef.getConsolFun();
steps = arcDef.getSteps();
}
finally {
rrd.close();
}
RrdToolkit.removeArchive(sourcePath, consolFun, steps, SHOULD_CREATE_BACKUPS);
inspectorModel.refresh();
tabbedPane.setSelectedIndex(0);
}
catch (Exception e) {
Util.error(this, e);
}
}
private void plotArchive() {
if (!inspectorModel.isOk()) {
Util.error(this, OPEN_A_VALID_RRD_FILE_FIRST);
return;
}
RrdNode rrdNode = getSelectedRrdNode();
if (!isArchiveNode(rrdNode)) {
Util.error(this, SELECT_ARCHIVE_FIRST);
return;
}
String sourcePath = inspectorModel.getFile().getAbsolutePath();
new GraphFrame(sourcePath, rrdNode.getDsIndex(), rrdNode.getArcIndex());
}
private boolean isArchiveNode(RrdNode rrdNode) {
return !(rrdNode == null || rrdNode.getArcIndex() < 0);
}
private static void printUsageAndExit() {
System.err.println("usage: " + RrdInspector.class.getName() + " [<filename>]");
System.exit(1);
}
/**
* <p>To start the application use the following syntax:</p>
* <pre>
* java -cp rrd4j.jar org.rrd4j.inspector.RrdInspector
* java -cp rrd4j.jar org.rrd4j.inspector.RrdInspector [path to RRD file]
* </pre>
*
* @param args an array of {@link java.lang.String} objects.
* @throws java.lang.Exception if any.
*/
public static void main(String[] args) throws Exception {
if (args.length > 1) {
printUsageAndExit();
}
// Set look and feel
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e1) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e2) {
// ignore
}
}
}
});
String path = (args.length == 1) ? args[0] : null;
new RrdInspector(path);
}
}