001    /* ============================================================
002     * JRobin : Pure java implementation of RRDTool's functionality
003     * ============================================================
004     *
005     * Project Info:  http://www.jrobin.org
006     * Project Lead:  Sasa Markovic (saxon@jrobin.org);
007     *
008     * (C) Copyright 2003, by Sasa Markovic.
009     *
010     * Developers:    Sasa Markovic (saxon@jrobin.org)
011     *
012     *
013     * This library is free software; you can redistribute it and/or modify it under the terms
014     * of the GNU Lesser General Public License as published by the Free Software Foundation;
015     * either version 2.1 of the License, or (at your option) any later version.
016     *
017     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
018     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
019     * See the GNU Lesser General Public License for more details.
020     *
021     * You should have received a copy of the GNU Lesser General Public License along with this
022     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
023     * Boston, MA 02111-1307, USA.
024     */
025    
026    package org.jrobin.inspector;
027    
028    import org.jrobin.core.*;
029    
030    import javax.swing.*;
031    import javax.swing.table.DefaultTableCellRenderer;
032    import javax.swing.filechooser.FileFilter;
033    import javax.swing.event.TreeSelectionListener;
034    import javax.swing.event.TreeSelectionEvent;
035    import javax.swing.tree.TreeSelectionModel;
036    import javax.swing.tree.DefaultMutableTreeNode;
037    import javax.swing.tree.TreePath;
038    import java.awt.*;
039    import java.awt.event.*;
040    import java.io.File;
041    import java.io.IOException;
042    
043    /**
044     * Utility application (swing) to analyze, change and plot content of JRobin RRD files.
045     */
046    public class RrdInspector extends JFrame {
047            private static final long serialVersionUID = 1L;
048            static final boolean SHOULD_CREATE_BACKUPS = true;
049            static final String TITLE = "RRD File Inspector";
050            static final boolean SHOULD_FIX_ARCHIVED_VALUES = false;
051            static final Dimension MAIN_TREE_SIZE = new Dimension(250, 400);
052            static final Dimension INFO_PANE_SIZE = new Dimension(450, 400);
053            static final String ABOUT = "JRobinLite project\nRrdInspector utility\n" +
054                            "Copyright (C) 2003-2005 Sasa Markovic. All rights reserved.";
055    
056            JTabbedPane tabbedPane = new JTabbedPane();
057            private JTree mainTree = new JTree();
058            private JTable generalTable = new JTable();
059            private JTable datasourceTable = new JTable();
060            private JTable archiveTable = new JTable();
061            private JTable dataTable = new JTable();
062    
063            private InspectorModel inspectorModel = new InspectorModel();
064    
065            private String lastDirectory = null;
066    
067            private RrdInspector(String path) {
068                    super(TITLE);
069                    constructUI();
070                    pack();
071                    Util.placeWindow(this);
072                    setVisible(true);
073                    if (path == null) {
074                            selectFile();
075                    }
076                    else {
077                            loadFile(new File(path));
078                    }
079            }
080    
081            private void constructUI() {
082                    JPanel content = (JPanel) getContentPane();
083                    content.setLayout(new BorderLayout());
084    
085                    // WEST, tree pane
086                    JPanel leftPanel = new JPanel();
087                    leftPanel.setLayout(new BorderLayout());
088                    JScrollPane treePane = new JScrollPane(mainTree);
089                    leftPanel.add(treePane);
090                    leftPanel.setPreferredSize(MAIN_TREE_SIZE);
091                    content.add(leftPanel, BorderLayout.WEST);
092                    mainTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
093                    mainTree.addTreeSelectionListener(new TreeSelectionListener() {
094                            public void valueChanged(TreeSelectionEvent e) {
095                                    nodeChangedAction();
096                            }
097                    });
098                    mainTree.setModel(inspectorModel.getMainTreeModel());
099    
100                    ////////////////////////////////////////////
101                    // EAST, tabbed pane
102                    ////////////////////////////////////////////
103    
104                    // GENERAL TAB
105                    JScrollPane spGeneral = new JScrollPane(generalTable);
106                    spGeneral.setPreferredSize(INFO_PANE_SIZE);
107                    tabbedPane.add("General info", spGeneral);
108                    generalTable.setModel(inspectorModel.getGeneralTableModel());
109                    generalTable.getColumnModel().getColumn(0).setPreferredWidth(150);
110                    generalTable.getColumnModel().getColumn(0).setMaxWidth(150);
111    
112                    // DATASOURCE TAB
113                    JScrollPane spDatasource = new JScrollPane(datasourceTable);
114                    spDatasource.setPreferredSize(INFO_PANE_SIZE);
115                    tabbedPane.add("Datasource info", spDatasource);
116                    datasourceTable.setModel(inspectorModel.getDatasourceTableModel());
117                    datasourceTable.getColumnModel().getColumn(0).setPreferredWidth(150);
118                    datasourceTable.getColumnModel().getColumn(0).setMaxWidth(150);
119    
120                    // ARCHIVE TAB
121                    JScrollPane spArchive = new JScrollPane(archiveTable);
122                    archiveTable.setModel(inspectorModel.getArchiveTableModel());
123                    archiveTable.getColumnModel().getColumn(0).setPreferredWidth(150);
124                    archiveTable.getColumnModel().getColumn(0).setMaxWidth(150);
125                    spArchive.setPreferredSize(INFO_PANE_SIZE);
126                    tabbedPane.add("Archive info", spArchive);
127    
128                    // DATA TAB
129                    JScrollPane spData = new JScrollPane(dataTable);
130                    dataTable.setModel(inspectorModel.getDataTableModel());
131                    dataTable.getColumnModel().getColumn(0).setPreferredWidth(100);
132                    dataTable.getColumnModel().getColumn(0).setMaxWidth(100);
133                    dataTable.getColumnModel().getColumn(1).setPreferredWidth(150);
134                    dataTable.getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
135                            private static final long serialVersionUID = 1L;
136                            {
137                                    setBackground(Color.YELLOW);
138                            }
139                    });
140                    spData.setPreferredSize(INFO_PANE_SIZE);
141                    tabbedPane.add("Archive data", spData);
142    
143                    content.add(tabbedPane, BorderLayout.CENTER);
144    
145                    ////////////////////////////////////////
146                    // MENU
147                    ////////////////////////////////////////
148                    JMenuBar menuBar = new JMenuBar();
149    
150                    // FILE MENU
151                    JMenu fileMenu = new JMenu("File");
152                    fileMenu.setMnemonic(KeyEvent.VK_F);
153    
154                    // Open file
155                    JMenuItem fileMenuItem = new JMenuItem("Open RRD file...", KeyEvent.VK_O);
156                    fileMenuItem.addActionListener(new ActionListener() {
157                            public void actionPerformed(ActionEvent e) {
158                                    selectFile();
159                            }
160                    });
161                    fileMenu.add(fileMenuItem);
162    
163                    // Open file in new window
164                    JMenuItem fileMenuItem2 = new JMenuItem("Open RRD file in new window...");
165                    fileMenuItem2.addActionListener(new ActionListener() {
166                            public void actionPerformed(ActionEvent e) {
167                                    new RrdInspector(null);
168                            }
169                    });
170                    fileMenu.add(fileMenuItem2);
171                    fileMenu.addSeparator();
172    
173                    // Add datasource
174                    JMenuItem addDatasourceMenuItem = new JMenuItem("Add datasource...");
175                    addDatasourceMenuItem.addActionListener(new ActionListener() {
176                            public void actionPerformed(ActionEvent e) {
177                                    addDatasource();
178                            }
179                    });
180                    fileMenu.add(addDatasourceMenuItem);
181    
182                    // Edit datasource
183                    JMenuItem editDatasourceMenuItem = new JMenuItem("Edit datasource...");
184                    editDatasourceMenuItem.addActionListener(new ActionListener() {
185                            public void actionPerformed(ActionEvent e) {
186                                    editDatasource();
187                            }
188                    });
189                    fileMenu.add(editDatasourceMenuItem);
190    
191                    // Remove datasource
192                    JMenuItem removeDatasourceMenuItem = new JMenuItem("Remove datasource");
193                    removeDatasourceMenuItem.addActionListener(new ActionListener() {
194                            public void actionPerformed(ActionEvent e) {
195                                    removeDatasource();
196                            }
197                    });
198                    fileMenu.add(removeDatasourceMenuItem);
199                    fileMenu.addSeparator();
200    
201                    // Add archive
202                    JMenuItem addArchiveMenuItem = new JMenuItem("Add archive...");
203                    addArchiveMenuItem.addActionListener(new ActionListener() {
204                            public void actionPerformed(ActionEvent e) {
205                                    addArchive();
206                            }
207                    });
208                    fileMenu.add(addArchiveMenuItem);
209    
210                    // Edit archive
211                    JMenuItem editArchiveMenuItem = new JMenuItem("Edit archive...");
212                    editArchiveMenuItem.addActionListener(new ActionListener() {
213                            public void actionPerformed(ActionEvent e) {
214                                    editArchive();
215                            }
216                    });
217                    fileMenu.add(editArchiveMenuItem);
218    
219                    // Remove archive
220                    JMenuItem removeArchiveMenuItem = new JMenuItem("Remove archive...");
221                    removeArchiveMenuItem.addActionListener(new ActionListener() {
222                            public void actionPerformed(ActionEvent e) {
223                                    removeArchive();
224                            }
225                    });
226                    fileMenu.add(removeArchiveMenuItem);
227    
228                    // Plot archive values
229                    JMenuItem plotArchiveMenuItem = new JMenuItem("Plot archive values...");
230                    plotArchiveMenuItem.addActionListener(new ActionListener() {
231                            public void actionPerformed(ActionEvent e) {
232                                    plotArchive();
233                            }
234                    });
235                    fileMenu.add(plotArchiveMenuItem);
236                    fileMenu.addSeparator();
237    
238                    // Exit
239                    JMenuItem exitMenuItem = new JMenuItem("Exit", KeyEvent.VK_X);
240                    exitMenuItem.addActionListener(new ActionListener() {
241                            public void actionPerformed(ActionEvent e) {
242                                    System.exit(0);
243                            }
244                    });
245                    fileMenu.add(exitMenuItem);
246    
247                    // HELP MENU
248                    JMenu helpMenu = new JMenu("Help");
249                    fileMenu.setMnemonic(KeyEvent.VK_H);
250    
251                    // About
252                    JMenuItem aboutMenuItem = new JMenuItem("About...");
253                    aboutMenuItem.addActionListener(new ActionListener() {
254                            public void actionPerformed(ActionEvent e) {
255                                    about();
256                            }
257                    });
258                    helpMenu.add(aboutMenuItem);
259    
260                    menuBar.add(fileMenu);
261                    menuBar.add(helpMenu);
262                    setJMenuBar(menuBar);
263    
264                    // finalize UI
265                    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
266                    addWindowListener(new WindowAdapter() {
267                            public void windowClosing(WindowEvent e) {
268                                    closeWindow();
269                            }
270                    });
271            }
272    
273            private void closeWindow() {
274                    Util.dismissWindow(this);
275            }
276    
277            private void about() {
278                    JOptionPane.showMessageDialog(this, ABOUT, "About", JOptionPane.INFORMATION_MESSAGE);
279            }
280    
281            private void nodeChangedAction() {
282                    RrdNode rrdNode = getSelectedRrdNode();
283                    if (rrdNode != null) {
284                            inspectorModel.selectModel(rrdNode.getDsIndex(), rrdNode.getArcIndex());
285                            if (rrdNode.getDsIndex() >= 0 && rrdNode.getArcIndex() >= 0) {
286                                    // archive node
287                                    if (tabbedPane.getSelectedIndex() < 2) {
288                                            tabbedPane.setSelectedIndex(2);
289                                    }
290                            }
291                            else if (rrdNode.getDsIndex() >= 0) {
292                                    tabbedPane.setSelectedIndex(1);
293                            }
294                            else {
295                                    tabbedPane.setSelectedIndex(0);
296                            }
297                    }
298            }
299    
300            private RrdNode getSelectedRrdNode() {
301                    TreePath path = mainTree.getSelectionPath();
302                    if (path != null) {
303                            DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
304                            Object obj = node.getUserObject();
305                            if (obj instanceof RrdNode) {
306                                    return (RrdNode) obj;
307                            }
308                    }
309                    return null;
310            }
311    
312            private void selectFile() {
313                    JFileChooser chooser = new JFileChooser(lastDirectory);
314                    FileFilter filter = new FileFilter() {
315                            public boolean accept(File file) {
316                                    String path = file.getAbsolutePath().toLowerCase();
317                                    return file.isDirectory() || path.endsWith(".rrd") ||
318                                                    path.endsWith(".jrb") || path.endsWith(".jrobin");
319                            }
320    
321                            public String getDescription() {
322                                    return "JRobin RRD files (*.rrd;*.jrb;*.jrobin)";
323                            }
324                    };
325                    chooser.setFileFilter(filter);
326                    int returnVal = chooser.showOpenDialog(this);
327                    if (returnVal == JFileChooser.APPROVE_OPTION) {
328                            File file = chooser.getSelectedFile();
329                            if (file != null) {
330                                    lastDirectory = file.getParent();
331                                    //inspectorModel.setFile(file);
332                                    //tabbedPane.setSelectedIndex(0);
333                                    loadFile(file);
334                            }
335                    }
336            }
337    
338            private void loadFile(File file) {
339                    inspectorModel.setFile(file);
340                    tabbedPane.setSelectedIndex(0);
341            }
342    
343    
344            private void addDatasource() {
345                    if (!inspectorModel.isOk()) {
346                            Util.error(this, "Open a valid RRD file first.");
347                            return;
348                    }
349                    DsDef newDsDef = new EditDatasourceDialog(this, null).getDsDef();
350                    if (newDsDef != null) {
351                            // action
352                            try {
353                                    String sourcePath = inspectorModel.getFile().getCanonicalPath();
354                                    RrdToolkit .addDatasource(sourcePath, newDsDef, SHOULD_CREATE_BACKUPS);
355                                    inspectorModel.refresh();
356                                    tabbedPane.setSelectedIndex(0);
357                            }
358                            catch (IOException e) {
359                                    Util.error(this, e);
360                            }
361                            catch (RrdException e) {
362                                    Util.error(this, e);
363                            }
364                    }
365            }
366    
367            private void addArchive() {
368                    if (!inspectorModel.isOk()) {
369                            Util.error(this, "Open a valid RRD file first.");
370                            return;
371                    }
372                    ArcDef newArcDef = new EditArchiveDialog(this, null).getArcDef();
373                    if (newArcDef != null) {
374                            // action
375                            try {
376                                    String sourcePath = inspectorModel.getFile().getCanonicalPath();
377                                    RrdToolkit.addArchive(sourcePath, newArcDef, SHOULD_CREATE_BACKUPS);
378                                    inspectorModel.refresh();
379                                    tabbedPane.setSelectedIndex(0);
380                            }
381                            catch (IOException e) {
382                                    Util.error(this, e);
383                            }
384                            catch (RrdException e) {
385                                    Util.error(this, e);
386                            }
387                    }
388            }
389    
390            private void editDatasource() {
391                    if (!inspectorModel.isOk()) {
392                            Util.error(this, "Open a valid RRD file first.");
393                            return;
394                    }
395                    RrdNode rrdNode = getSelectedRrdNode();
396                    int dsIndex;
397                    if (rrdNode == null || (dsIndex = rrdNode.getDsIndex()) < 0) {
398                            Util.error(this, "Select datasource first");
399                            return;
400                    }
401                    try {
402                            String sourcePath = inspectorModel.getFile().getCanonicalPath();
403                            RrdDb rrd = new RrdDb(sourcePath, true);
404                            try {
405                                    DsDef dsDef = rrd.getRrdDef().getDsDefs()[dsIndex];
406                                    rrd.close();
407                                    DsDef newDsDef = new EditDatasourceDialog(this, dsDef).getDsDef();
408                                    if (newDsDef != null) {
409                                            // action!
410                                            RrdToolkit.setDsHeartbeat(sourcePath, newDsDef.getDsName(),
411                                                            newDsDef.getHeartbeat());
412                                            RrdToolkit.setDsMinMaxValue(sourcePath, newDsDef.getDsName(),
413                                                            newDsDef.getMinValue(), newDsDef.getMaxValue(), SHOULD_FIX_ARCHIVED_VALUES);
414                                            inspectorModel.refresh();
415                                            tabbedPane.setSelectedIndex(0);
416                                    }
417                            }
418                            finally {
419                                    rrd.close();
420                            }
421                    }
422                    catch (IOException e) {
423                            Util.error(this, e);
424                    }
425                    catch (RrdException e) {
426                            Util.error(this, e);
427                    }
428            }
429    
430            private void editArchive() {
431                    if (!inspectorModel.isOk()) {
432                            Util.error(this, "Open a valid RRD file first.");
433                            return;
434                    }
435                    RrdNode rrdNode = getSelectedRrdNode();
436                    int arcIndex;
437                    if (rrdNode == null || (arcIndex = rrdNode.getArcIndex()) < 0) {
438                            Util.error(this, "Select archive first");
439                            return;
440                    }
441                    try {
442                            String sourcePath = inspectorModel.getFile().getCanonicalPath();
443                            RrdDb rrd = new RrdDb(sourcePath, true);
444                            try {
445                                    ArcDef arcDef = rrd.getRrdDef().getArcDefs()[arcIndex];
446                                    rrd.close();
447                                    ArcDef newArcDef = new EditArchiveDialog(this, arcDef).getArcDef();
448                                    if (newArcDef != null) {
449                                            // action!
450                                            // fix X-files factor
451                                            RrdToolkit.setArcXff(sourcePath, newArcDef.getConsolFun(),
452                                                            newArcDef.getSteps(), newArcDef.getXff());
453                                            // fix archive size
454                                            RrdToolkit.resizeArchive(sourcePath, newArcDef.getConsolFun(),
455                                                            newArcDef.getSteps(), newArcDef.getRows(), SHOULD_CREATE_BACKUPS);
456                                            inspectorModel.refresh();
457                                            tabbedPane.setSelectedIndex(0);
458                                    }
459                            }
460                            finally {
461                                    rrd.close();
462                            }
463                    }
464                    catch (IOException e) {
465                            Util.error(this, e);
466                    }
467                    catch (RrdException e) {
468                            Util.error(this, e);
469                    }
470            }
471    
472            private void removeDatasource() {
473                    if (!inspectorModel.isOk()) {
474                            Util.error(this, "Open a valid RRD file first.");
475                            return;
476                    }
477                    RrdNode rrdNode = getSelectedRrdNode();
478                    int dsIndex;
479                    if (rrdNode == null || (dsIndex = rrdNode.getDsIndex()) < 0) {
480                            Util.error(this, "Select datasource first");
481                            return;
482                    }
483                    try {
484                            String sourcePath = inspectorModel.getFile().getCanonicalPath(), dsName;
485                            RrdDb rrd = new RrdDb(sourcePath, true);
486                            try {
487                                    dsName = rrd.getRrdDef().getDsDefs()[dsIndex].getDsName();
488                            }
489                            finally {
490                                    rrd.close();
491                            }
492                            RrdToolkit.removeDatasource(sourcePath, dsName, SHOULD_CREATE_BACKUPS);
493                            inspectorModel.refresh();
494                            tabbedPane.setSelectedIndex(0);
495                    }
496                    catch (IOException e) {
497                            Util.error(this, e);
498                    }
499                    catch (RrdException e) {
500                            Util.error(this, e);
501                    }
502            }
503    
504            private void removeArchive() {
505                    if (!inspectorModel.isOk()) {
506                            Util.error(this, "Open a valid RRD file first.");
507                            return;
508                    }
509                    RrdNode rrdNode = getSelectedRrdNode();
510                    int arcIndex;
511                    if (rrdNode == null || (arcIndex = rrdNode.getArcIndex()) < 0) {
512                            Util.error(this, "Select archive first");
513                            return;
514                    }
515                    try {
516                            String sourcePath = inspectorModel.getFile().getCanonicalPath(), consolFun;
517                            int steps;
518                            RrdDb rrd = new RrdDb(sourcePath, true);
519                            try {
520                                    ArcDef arcDef = rrd.getRrdDef().getArcDefs()[arcIndex];
521                                    consolFun = arcDef.getConsolFun();
522                                    steps = arcDef.getSteps();
523                            }
524                            finally {
525                                    rrd.close();
526                            }
527                            RrdToolkit.removeArchive(sourcePath, consolFun, steps, SHOULD_CREATE_BACKUPS);
528                            inspectorModel.refresh();
529                            tabbedPane.setSelectedIndex(0);
530                    }
531                    catch (IOException e) {
532                            Util.error(this, e);
533                    }
534                    catch (RrdException e) {
535                            Util.error(this, e);
536                    }
537            }
538    
539            private void plotArchive() {
540                    if (!inspectorModel.isOk()) {
541                            Util.error(this, "Open a valid RRD file first.");
542                            return;
543                    }
544                    RrdNode rrdNode = getSelectedRrdNode();
545                    int arcIndex;
546                    if (rrdNode == null || (arcIndex = rrdNode.getArcIndex()) < 0) {
547                            Util.error(this, "Select archive first");
548                            return;
549                    }
550                    String sourcePath = inspectorModel.getFile().getAbsolutePath();
551                    int dsIndex = rrdNode.getDsIndex();
552                    new GraphFrame(sourcePath, dsIndex, arcIndex);
553            }
554    
555            private static void printUsageAndExit() {
556                    System.err.println("usage: " + RrdInspector.class.getName() + " [<filename>]");
557                    System.exit(1);
558            }
559    
560            /**
561             * <p>To start the application use the following syntax:</p>
562             * <pre>
563             * java -cp JRobinLite.jar org.jrobin.inspector.RrdInspector
564             * java -cp JRobinLite.jar org.jrobin.inspector.RrdInspector [path to RRD file]
565             * </pre>
566             *
567             * @param args
568             */
569            public static void main(String[] args) {
570                    if (args.length > 1) {
571                            printUsageAndExit();
572                    }
573                    String path = (args.length == 1) ? args[0] : null;
574                    new RrdInspector(path);
575            }
576    }