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-2005, 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.cmd;
27  
28  import org.jrobin.core.RrdException;
29  import org.jrobin.core.Util;
30  import org.jrobin.graph.RrdGraph;
31  import org.jrobin.graph.RrdGraphConstants;
32  import org.jrobin.graph.RrdGraphDef;
33  import org.jrobin.graph.RrdGraphInfo;
34  
35  import java.awt.*;
36  import java.io.IOException;
37  
38  class RrdGraphCmd extends RrdToolCmd implements RrdGraphConstants {
39  	static final Color BLIND_COLOR = new Color(0, 0, 0, 0);
40  	private RrdGraphDef gdef;
41  
42  	String getCmdType() {
43  		return "graph";
44  	}
45  
46  	Object execute() throws RrdException, IOException {
47  		gdef = getGraphDef();
48  		
49  		// create diagram finally
50  		RrdGraphInfo info = new RrdGraph(gdef).getRrdGraphInfo();
51  		if (info.getFilename().equals(RrdGraphConstants.IN_MEMORY_IMAGE)) {
52  			println(new String(info.getBytes()));
53  		}
54  		else {
55  			println(info.getWidth() + "x" + info.getHeight());
56  			String[] plines = info.getPrintLines();
57  			for (String pline : plines) {
58  				println(pline);
59  			}
60  			if (info.getImgInfo() != null && info.getImgInfo().length() > 0) {
61  				println(info.getImgInfo());
62  			}
63  		}
64  		return info;
65  	}
66  
67      /**
68       * @throws RrdException
69       * @returns an RRD graph definition
70       */
71      public RrdGraphDef getGraphDef() throws RrdException {
72          RrdGraphDef gdef = new RrdGraphDef();
73  
74  		// OPTIONS
75  
76  		// START, END
77  		String t1 = getOptionValue("s", "start", DEFAULT_START), t2 = getOptionValue("e", "end", DEFAULT_END);
78  		gdef.setTimeSpan(Util.getTimestamps(t1, t2));
79  		// X-GRID
80  		parseXGrid(getOptionValue("x", "x-grid"));
81  		// Y-GRID
82  		parseYGrid(getOptionValue("y", "y-grid"));
83  		// ALT-Y-GRID
84  		gdef.setAltYGrid(getBooleanOption("Y", "alt-y-grid"));
85  		// NO_MINOR
86  		gdef.setNoMinorGrid(getBooleanOption(null, "no-minor"));
87  		// ALT-Y-MRTG
88  		gdef.setAltYMrtg(getBooleanOption("R", "alt-y-mrtg"));
89  		// ALT-AUTOSCALE
90  		gdef.setAltAutoscale(getBooleanOption("A", "alt-autoscale"));
91  		// ALT-AUTOSCALE-MAX
92  		gdef.setAltAutoscaleMax(getBooleanOption("M", "alt-autoscale-max"));
93  		// UNITS-EXPONENT
94  		String opt = getOptionValue("X", "units-exponent");
95  		if (opt != null) {
96  			gdef.setUnitsExponent(parseInt(opt));
97  		}
98  		// UNITS-LENGTH
99  		opt = getOptionValue("L", "units-length");
100 		if (opt != null) {
101 			gdef.setUnitsLength(parseInt(opt));
102 		}
103 		// VERTICAL LABEL
104 		opt = getOptionValue("v", "vertical-label");
105 		if (opt != null) {
106 			gdef.setVerticalLabel(opt);
107 		}
108 		// WIDTH
109 		opt = getOptionValue("w", "width");
110 		if (opt != null) {
111 			gdef.setWidth(parseInt(opt));
112 		}
113 		// HEIGHT
114 		opt = getOptionValue("h", "height");
115 		if (opt != null) {
116 			gdef.setHeight(parseInt(opt));
117 		}
118 		// INTERLACED
119 		gdef.setInterlaced(getBooleanOption("i", "interlaced"));
120 		// IMGINFO
121 		opt = getOptionValue("f", "imginfo");
122 		if (opt != null) {
123 			gdef.setImageInfo(opt);
124 		}
125 		// IMGFORMAT
126 		opt = getOptionValue("a", "imgformat");
127 		if (opt != null) {
128 			gdef.setImageFormat(opt);
129 		}
130 		// BACKGROUND
131 		opt = getOptionValue("B", "background");
132 		if (opt != null) {
133 			gdef.setBackgroundImage(opt);
134 		}
135 		// OVERLAY
136 		opt = getOptionValue("O", "overlay");
137 		if (opt != null) {
138 			gdef.setOverlayImage(opt);
139 		}
140 		// UNIT
141 		opt = getOptionValue("U", "unit");
142 		if (opt != null) {
143 			gdef.setUnit(opt);
144 		}
145 		// LAZY
146 		gdef.setLazy(getBooleanOption("z", "lazy"));
147 		// UPPER-LIMIT
148 		opt = getOptionValue("u", "upper-limit");
149 		if (opt != null) {
150 			gdef.setMaxValue(parseDouble(opt));
151 		}
152 		// LOWER-LIMIT
153 		opt = getOptionValue("l", "lower-limit");
154 		if (opt != null) {
155 			gdef.setMinValue(parseDouble(opt));
156 		}
157 		// RIGID
158 		gdef.setRigid(getBooleanOption("r", "rigid"));
159 		// BASE
160 		opt = getOptionValue("b", "base");
161 		if (opt != null) {
162 			gdef.setBase(parseDouble(opt));
163 		}
164 		// LOGARITHMIC
165 		gdef.setLogarithmic(getBooleanOption("o", "logarithmic"));
166 		// COLORS
167 		parseColors(getMultipleOptionValues("c", "color"));
168 		// NO-LEGEND
169 		gdef.setNoLegend(getBooleanOption("g", "no-legend"));
170 		// ONLY_GRAPH
171 		gdef.setOnlyGraph(getBooleanOption("j", "only-graph"));
172 		// FORCE-RULES-LEGEND
173 		gdef.setForceRulesLegend(getBooleanOption("F", "force-rules-legend"));
174 		// TITLE
175 		opt = getOptionValue("t", "title");
176 		if (opt != null) {
177 			gdef.setTitle(opt);
178 		}
179 		// STEP
180 		opt = getOptionValue("S", "step");
181 		if (opt != null) {
182 			gdef.setStep(parseLong(opt));
183 		}
184 
185 		// NON-OPTIONS
186 
187 		String[] words = getRemainingWords();
188 		// the first word must be a filename
189 		if (words.length < 2) {
190 			throw new RrdException("Image filename must be specified");
191 		}
192 		gdef.setFilename(words[1]);
193 		// parse remaining words, in no particular order
194 		for (int i = 2; i < words.length; i++) {
195 			if (words[i].startsWith("DEF:")) {
196 				parseDef(words[i]);
197 			}
198 			else if (words[i].startsWith("CDEF:")) {
199 				parseCDef(words[i]);
200 			}
201 			else if (words[i].startsWith("PRINT:")) {
202 				parsePrint(words[i]);
203 			}
204 			else if (words[i].startsWith("GPRINT:")) {
205 				parseGPrint(words[i]);
206 			}
207 			else if (words[i].startsWith("COMMENT:")) {
208 				parseComment(words[i]);
209 			}
210 			else if (words[i].startsWith("HRULE:")) {
211 				parseHRule(words[i]);
212 			}
213 			else if (words[i].startsWith("VRULE:")) {
214 				parseVRule(words[i]);
215 			}
216 			else if (words[i].startsWith("LINE1:") || words[i].startsWith("LINE2:") || words[i].startsWith("LINE3:")) {
217 				parseLine(words[i]);
218 			}
219 			else if (words[i].startsWith("AREA:")) {
220 				parseArea(words[i]);
221 			}
222 			else if (words[i].startsWith("STACK:")) {
223 				parseStack(words[i]);
224 			}
225 			else {
226 				throw new RrdException("Unexpected GRAPH token encountered: " + words[i]);
227 			}
228 		}
229 		
230 		return gdef;
231     }
232 
233 	private void parseLine(String word) throws RrdException {
234 		String[] tokens1 = new ColonSplitter(word).split();
235 		if (tokens1.length != 2 && tokens1.length != 3) {
236 			throw new RrdException("Invalid LINE statement: " + word);
237 		}
238 		String[] tokens2 = tokens1[1].split("#");
239 		if (tokens2.length != 1 && tokens2.length != 2) {
240 			throw new RrdException("Invalid LINE statement: " + word);
241 		}
242 		float width = Integer.parseInt(tokens1[0].substring(tokens1[0].length() - 1));
243 		String name = tokens2[0];
244 		Paint color = tokens2.length == 2 ? Util.parseColor(tokens2[1]) : BLIND_COLOR;
245 		String legend = tokens1.length == 3 ? tokens1[2] : null;
246 		gdef.line(name, color, legend, width);
247 	}
248 
249 	private void parseArea(String word) throws RrdException {
250 		String[] tokens1 = new ColonSplitter(word).split();
251 		if (tokens1.length != 2 && tokens1.length != 3) {
252 			throw new RrdException("Invalid AREA statement: " + word);
253 		}
254 		String[] tokens2 = tokens1[1].split("#");
255 		if (tokens2.length != 1 && tokens2.length != 2) {
256 			throw new RrdException("Invalid AREA statement: " + word);
257 		}
258 		String name = tokens2[0];
259 		Paint color = tokens2.length == 2 ? Util.parseColor(tokens2[1]) : BLIND_COLOR;
260 		String legend = tokens1.length == 3 ? tokens1[2] : null;
261 		gdef.area(name, color, legend);
262 	}
263 
264 	private void parseStack(String word) throws RrdException {
265 		String[] tokens1 = new ColonSplitter(word).split();
266 		if (tokens1.length != 2 && tokens1.length != 3) {
267 			throw new RrdException("Invalid STACK statement: " + word);
268 		}
269 		String[] tokens2 = tokens1[1].split("#");
270 		if (tokens2.length != 1 && tokens2.length != 2) {
271 			throw new RrdException("Invalid STACK statement: " + word);
272 		}
273 		String name = tokens2[0];
274 		Paint color = tokens2.length == 2 ? Util.parseColor(tokens2[1]) : BLIND_COLOR;
275 		String legend = tokens1.length == 3 ? tokens1[2] : null;
276 		gdef.stack(name, color, legend);
277 	}
278 
279 	private void parseHRule(String word) throws RrdException {
280 		String[] tokens1 = new ColonSplitter(word).split();
281 		if (tokens1.length < 2 || tokens1.length > 3) {
282 			throw new RrdException("Invalid HRULE statement: " + word);
283 		}
284 		String[] tokens2 = tokens1[1].split("#");
285 		if (tokens2.length != 2) {
286 			throw new RrdException("Invalid HRULE statement: " + word);
287 		}
288 		double value = parseDouble(tokens2[0]);
289 		Paint color = Util.parseColor(tokens2[1]);
290 		gdef.hrule(value, color, tokens1.length == 3 ? tokens1[2] : null);
291 	}
292 
293 	private void parseVRule(String word) throws RrdException {
294 		String[] tokens1 = new ColonSplitter(word).split();
295 		if (tokens1.length < 2 || tokens1.length > 3) {
296 			throw new RrdException("Invalid VRULE statement: " + word);
297 		}
298 		String[] tokens2 = tokens1[1].split("#");
299 		if (tokens2.length != 2) {
300 			throw new RrdException("Invalid VRULE statement: " + word);
301 		}
302 		long timestamp = Util.getTimestamp(tokens2[0]);
303 		Paint color = Util.parseColor(tokens2[1]);
304 		gdef.vrule(timestamp, color, tokens1.length == 3 ? tokens1[2] : null);
305 	}
306 
307 	private void parseComment(String word) throws RrdException {
308 		String[] tokens = new ColonSplitter(word).split();
309 		if (tokens.length != 2) {
310 			throw new RrdException("Invalid COMMENT specification: " + word);
311 		}
312 		gdef.comment(tokens[1]);
313 	}
314 
315 
316 	private void parseDef(String word) throws RrdException {
317 		String[] tokens1 = new ColonSplitter(word).split();
318 		if (tokens1.length != 4) {
319 			throw new RrdException("Invalid DEF specification: " + word);
320 		}
321 		String[] tokens2 = tokens1[1].split("=");
322 		if (tokens2.length != 2) {
323 			throw new RrdException("Invalid DEF specification: " + word);
324 		}
325 		gdef.datasource(tokens2[0], tokens2[1], tokens1[2], tokens1[3]);
326 	}
327 
328 	private void parseCDef(String word) throws RrdException {
329 		String[] tokens1 = new ColonSplitter(word).split();
330 		if (tokens1.length != 2) {
331 			throw new RrdException("Invalid CDEF specification: " + word);
332 		}
333 		String[] tokens2 = tokens1[1].split("=");
334 		if (tokens2.length != 2) {
335 			throw new RrdException("Invalid DEF specification: " + word);
336 		}
337 		gdef.datasource(tokens2[0], tokens2[1]);
338 	}
339 
340 	private void parsePrint(String word) throws RrdException {
341 		String[] tokens = new ColonSplitter(word).split();
342 		if (tokens.length != 4) {
343 			throw new RrdException("Invalid PRINT specification: " + word);
344 		}
345 		gdef.print(tokens[1], tokens[2], tokens[3]);
346 	}
347 
348 	private void parseGPrint(String word) throws RrdException {
349 		String[] tokens = new ColonSplitter(word).split();
350 		if (tokens.length != 4) {
351 			throw new RrdException("Invalid GPRINT specification: " + word);
352 		}
353 		gdef.gprint(tokens[1], tokens[2], tokens[3]);
354 	}
355 
356 	private void parseColors(String[] colorOptions) throws RrdException {
357 		if (colorOptions == null) {
358 			return;
359 		}
360 		for (String colorOption : colorOptions) {
361 			String[] tokens = colorOption.split("#");
362 			if (tokens.length != 2) {
363 				throw new RrdException("Invalid COLOR specification: " + colorOption);
364 			}
365 			String colorName = tokens[0];
366 			Paint paint = Util.parseColor(tokens[1]);
367 			gdef.setColor(colorName, paint);
368 		}
369 	}
370 
371 	private void parseYGrid(String ygrid) throws RrdException {
372 		if (ygrid == null) {
373 			return;
374 		}
375 		if (ygrid.equalsIgnoreCase("none")) {
376 			gdef.setDrawYGrid(false);
377 			return;
378 		}
379 		String[] tokens = new ColonSplitter(ygrid).split();
380 		if (tokens.length != 2) {
381 			throw new RrdException("Invalid YGRID settings: " + ygrid);
382 		}
383 		double gridStep = parseDouble(tokens[0]);
384 		int labelFactor = parseInt(tokens[1]);
385 		gdef.setValueAxis(gridStep, labelFactor);
386 	}
387 
388 	private void parseXGrid(String xgrid) throws RrdException {
389 		if (xgrid == null) {
390 			return;
391 		}
392 		if (xgrid.equalsIgnoreCase("none")) {
393 			gdef.setDrawXGrid(false);
394 			return;
395 		}
396 		String[] tokens = new ColonSplitter(xgrid).split();
397 		if (tokens.length != 8) {
398 			throw new RrdException("Invalid XGRID settings: " + xgrid);
399 		}
400 		int minorUnit = resolveUnit(tokens[0]), majorUnit = resolveUnit(tokens[2]),
401 				labelUnit = resolveUnit(tokens[4]);
402 		int minorUnitCount = parseInt(tokens[1]), majorUnitCount = parseInt(tokens[3]),
403 				labelUnitCount = parseInt(tokens[5]);
404 		int labelSpan = parseInt(tokens[6]);
405 		String fmt = tokens[7];
406 		gdef.setTimeAxis(minorUnit, minorUnitCount, majorUnit, majorUnitCount,
407 				labelUnit, labelUnitCount, labelSpan, fmt);
408 	}
409 
410 	private int resolveUnit(String unitName) throws RrdException {
411 		final String[] unitNames = {"SECOND", "MINUTE", "HOUR", "DAY", "WEEK", "MONTH", "YEAR"};
412 		final int[] units = {SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR};
413 		for (int i = 0; i < unitNames.length; i++) {
414 			if (unitName.equalsIgnoreCase(unitNames[i])) {
415 				return units[i];
416 			}
417 		}
418 		throw new RrdException("Unknown time unit specified: " + unitName);
419 	}
420 }