View Javadoc

1   /* ============================================================
2    * JRobin : Pure java implementation of RRDTool's functionality
3    * ============================================================
4    *
5    * Project Info:  http://www.jrobin.org
6    * Project Lead:  Sasa Markovic (saxon@jrobin.org);
7    *
8    * (C) Copyright 2003, by Sasa Markovic.
9    *
10   * Developers:    Sasa Markovic (saxon@jrobin.org)
11   *
12   *
13   * This library is free software; you can redistribute it and/or modify it under the terms
14   * of the GNU Lesser General Public License as published by the Free Software Foundation;
15   * either version 2.1 of the License, or (at your option) any later version.
16   *
17   * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18   * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19   * See the GNU Lesser General Public License for more details.
20   *
21   * You should have received a copy of the GNU Lesser General Public License along with this
22   * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23   * Boston, MA 02111-1307, USA.
24   */
25  
26  package org.jrobin.inspector;
27  
28  import org.jrobin.core.*;
29  
30  import javax.swing.*;
31  import javax.swing.table.DefaultTableCellRenderer;
32  import javax.swing.filechooser.FileFilter;
33  import javax.swing.event.TreeSelectionListener;
34  import javax.swing.event.TreeSelectionEvent;
35  import javax.swing.tree.TreeSelectionModel;
36  import javax.swing.tree.DefaultMutableTreeNode;
37  import javax.swing.tree.TreePath;
38  import java.awt.*;
39  import java.awt.event.*;
40  import java.io.File;
41  import java.io.IOException;
42  
43  /**
44   * Utility application (swing) to analyze, change and plot content of JRobin RRD files.
45   */
46  public class RrdInspector extends JFrame {
47  	private static final long serialVersionUID = 1L;
48  	static final boolean SHOULD_CREATE_BACKUPS = true;
49  	static final String TITLE = "RRD File Inspector";
50  	static final boolean SHOULD_FIX_ARCHIVED_VALUES = false;
51  	static final Dimension MAIN_TREE_SIZE = new Dimension(250, 400);
52  	static final Dimension INFO_PANE_SIZE = new Dimension(450, 400);
53  	static final String ABOUT = "JRobinLite project\nRrdInspector utility\n" +
54  			"Copyright (C) 2003-2005 Sasa Markovic. All rights reserved.";
55  
56  	JTabbedPane tabbedPane = new JTabbedPane();
57  	private JTree mainTree = new JTree();
58  	private JTable generalTable = new JTable();
59  	private JTable datasourceTable = new JTable();
60  	private JTable archiveTable = new JTable();
61  	private JTable dataTable = new JTable();
62  
63  	private InspectorModel inspectorModel = new InspectorModel();
64  
65  	private String lastDirectory = null;
66  
67  	private RrdInspector(String path) {
68  		super(TITLE);
69  		constructUI();
70  		pack();
71  		Util.placeWindow(this);
72  		setVisible(true);
73  		if (path == null) {
74  			selectFile();
75  		}
76  		else {
77  			loadFile(new File(path));
78  		}
79  	}
80  
81  	private void constructUI() {
82  		JPanel content = (JPanel) getContentPane();
83  		content.setLayout(new BorderLayout());
84  
85  		// WEST, tree pane
86  		JPanel leftPanel = new JPanel();
87  		leftPanel.setLayout(new BorderLayout());
88  		JScrollPane treePane = new JScrollPane(mainTree);
89  		leftPanel.add(treePane);
90  		leftPanel.setPreferredSize(MAIN_TREE_SIZE);
91  		content.add(leftPanel, BorderLayout.WEST);
92  		mainTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
93  		mainTree.addTreeSelectionListener(new TreeSelectionListener() {
94  			public void valueChanged(TreeSelectionEvent e) {
95  				nodeChangedAction();
96  			}
97  		});
98  		mainTree.setModel(inspectorModel.getMainTreeModel());
99  
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 }