/******************************************************************************* * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. * Copyright (c) 2011 The OpenNMS Group, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *******************************************************************************/ package org.jrobin.graph; import org.jrobin.core.RrdException; import org.jrobin.core.Util; import org.jrobin.core.XmlTemplate; import org.w3c.dom.Node; import org.xml.sax.InputSource; import java.awt.*; import java.io.File; import java.io.IOException; /** * Class used to create an arbitrary number of RrdGraphDef (graph definition) objects * from a single XML template. XML template can be supplied as an XML InputSource, * XML file or XML formatted string. * <p> * Here is an example of a properly formatted XML template with all available options in it * (unwanted options can be removed/ignored): * <p> * <pre> * <rrd_graph_def> * <!-- use '-' to represent in-memory graph --> * <filename>test.png</filename> * <!-- * starting and ending timestamps can be specified by * using at-style time specification, or by specifying * exact timestamps since epoch (without milliseconds) * --> * <span> * <start>now - 1d</start> * <end>now</end> * </span> * <options> * <!-- * specify 'true' if you want to use RrdDbPool while * creating graph * --> * <use_pool>false</use_pool> * <anti_aliasing>true</anti_aliasing> * <time_grid> * <show_grid>true</show_grid> * <!-- allowed units: second, minute, hour, day, week, month, year --> * <minor_grid_unit>minute</minor_grid_unit> * <minor_grid_unit_count>60</minor_grid_unit_count> * <major_grid_unit>hour</major_grid_unit> * <major_grid_unit_count>2</major_grid_unit_count> * <label_unit>hour</label_unit> * <label_unit_count>2</label_unit_count> * <label_span>1200</label_span> * <!-- use SimpleDateFormat or strftime-like format to format labels --> * <label_format>dd-MMM-yy</label_format> * </time_grid> * <value_grid> * <show_grid>true</show_grid> * <grid_step>100.0</grid_step> * <label_factor>5</label_factor> * </value_grid> * <no_minor_grid>true</no_minor_grid> * <alt_y_grid>true</alt_y_grid> * <alt_y_mrtg>true</alt_y_mrtg> * <alt_autoscale>true</alt_autoscale> * <alt_autoscale_max>true</alt_autoscale_max> * <units_exponent>3</units_exponent> * <units_length>13</units_length> * <vertical_label>Speed (kbits/sec)</vertical_label> * <width>444</width> * <height>222</height> * <interlaced>true</interlaced> * <image_info>filename = %s, width=%d, height=%d</image_info> * <image_format>png</image_format> * <image_quality>0.8</image_quality> * <background_image>luka.png</background_image> * <overlay_image>luka.png</overlay_image> * <unit>kilos</unit> * <lazy>false</lazy> * <min_value>0</min_value> * <max_value>5000</max_value> * <rigid>true</rigid> * <base>1000</base> * <logarithmic>false</logarithmic> * <colors> * <canvas>#FFFFFF</canvas> * <back>#FFFFFF</back> * <shadea>#AABBCC</shadea> * <shadeb>#DDDDDD</shadeb> * <grid>#FF0000</grid> * <mgrid>#00FF00</mgrid> * <font>#FFFFFF</font> * <frame>#EE00FF</frame> * <arrow>#FF0000</arrow> * </colors> * <no_legend>false</no_legend> * <only_graph>false</only_graph> * <force_rules_legend>false</force_rules_legend> * <title>This is a title</title> * <step>300</step> * <fonts> * <small_font> * <name>Courier</name> * <style>bold italic</style> * <size>12</size> * </small_font> * <large_font> * <name>Courier</name> * <style>plain</style> * <size>11</size> * </large_font> * </fonts> * <first_day_of_week>SUNDAY</first_day_of_week> * </options> * <datasources> * <def> * <name>x</name> * <rrd>test.rrd</rrd> * <source>sun</source> * <cf>AVERAGE</cf> * <backend>FILE</backend> * </def> * <def> * <name>y</name> * <rrd>test.rrd</rrd> * <source>shade</source> * <cf>AVERAGE</cf> * </def> * <cdef> * <name>x_plus_y</name> * <rpn>x,y,+</rpn> * </cdef> * <cdef> * <name>x_minus_y</name> * <rpn>x,y,-</rpn> * </cdef> * <sdef> * <name>x_avg</name> * <source>x</source> * <cf>AVERAGE</cf> * </sdef> * <sdef> * <name>y_max</name> * <source>y</source> * <cf>MAX</cf> * </sdef> * </datasources> * <graph> * <area> * <datasource>x</datasource> * <color>#FF0000</color> * <legend>X value\r</legend> * </area> * <stack> * <datasource>y</datasource> * <color>#00FF00</color> * <legend>Y value\r</legend> * </stack> * <line> * <datasource>x</datasource> * <color>#FF0000</color> * <legend>X value\r</legend> * <width>2</width> * </line> * <print> * <datasource>x</datasource> * <cf>AVERAGE</cf> * <format>Average is %7.3f\c</format> * </print> * <gprint> * <datasource>y</datasource> * <cf>MAX</cf> * <format>Max is %7.3f\c</format> * </gprint> * <hrule> * <value>1250</value> * <color>#0000FF</color> * <legend>This is a horizontal rule</legend> * </hrule> * <vrule> * <time>now-6h</time> * <color>#0000FF</color> * <legend>This is a vertical rule</legend> * </vrule> * <comment>Simple comment</comment> * <comment>One more comment\c</comment> * </graph> * </rrd_graph_def> * </pre> * Notes on the template syntax: * <p> * <ul> * <li>There is a strong relation between the XML template syntax and the syntax of * {@link RrdGraphDef} class methods. If you are not sure what some XML tag means, check javadoc * for the corresponding class method. * <li>hard-coded timestamps in templates should be long integeres * (like: 1000243567) or at-style formatted strings * <li>whitespaces are not harmful * <li>use <code>true</code>, <code>on</code>, <code>yes</code>, <code>y</code>, * or <code>1</code> to specify boolean <code>true</code> value (anything else will * be treated as <code>false</code>). * <li>floating point values: anything that cannot be parsed will be treated as Double.NaN * (like: U, unknown, 12r.23) * <li>use #RRGGBB or #RRGGBBAA format to specify colors. * <li>valid font styles are: PLAIN, ITALIC, BOLD, BOLDITALIC * <li>comments are allowed. * </ul> * Any template value (text between <code><some_tag></code> and * <code></some_tag></code>) can be replaced with * a variable of the following form: <code>${variable_name}</code>. Use * {@link XmlTemplate#setVariable(String, String) setVariable()} * methods from the base class to replace * template variables with real values at runtime. * <p> * Typical usage scenario: * <p> * <ul> * <li>Create your XML template and save it to a file (template.xml, for example) * <li>Replace template values with variables if you want to change them during runtime. * For example, time span should not be hard-coded in the template - you probably want to create * many different graphs with different time spans from the same XML template. * For example, your XML template could start with: * <pre> * <rrd_graph_def> * ... * <span> * <start>${start}</start> * <end>${end}</end> * </span> * ... * </pre> * <li>In your Java code, create RrdGraphDefTemplate object using your XML template file: * <pre> * RrdGraphDefTemplate t = new RrdGraphDefTemplate(new File(template.xml)); * </pre> * <li>Then, specify real values for template variables: * <pre> * t.setVariable("start", new GregorianCalendar(2004, 2, 25)); * t.setVariable("end", new GregorianCalendar(2004, 2, 26)); * </pre> * <li>Once all template variables are set, just use the template object to create RrdGraphDef * object. This object is actually used to create JRobin grahps: * <pre> * RrdGraphDef gdef = t.getRrdGraphDef(); * RrdGraph g = new RrdGraph(gdef); * </pre> * </ul> * You should create new RrdGraphDefTemplate object only once for each XML template. Single template * object can be reused to create as many RrdGraphDef objects as needed, with different values * specified for template variables. XML synatax check is performed only once - the first graph * definition object gets created relatively slowly, but it will be created much faster next time. */ public class RrdGraphDefTemplate extends XmlTemplate implements RrdGraphConstants { static final Color BLIND_COLOR = new Color(0, 0, 0, 0); private RrdGraphDef rrdGraphDef; /** * Creates template object from any parsable XML source * * @param inputSource XML source * @throws IOException thrown in case of I/O error * @throws RrdException usually thrown in case of XML related error */ public RrdGraphDefTemplate(InputSource inputSource) throws IOException, RrdException { super(inputSource); } /** * Creates template object from the file containing XML template code * * @param xmlFile file containing XML template * @throws IOException thrown in case of I/O error * @throws RrdException usually thrown in case of XML related error */ public RrdGraphDefTemplate(File xmlFile) throws IOException, RrdException { super(xmlFile); } /** * Creates template object from the string containing XML template code * * @param xmlString string containing XML template * @throws IOException thrown in case of I/O error * @throws RrdException usually thrown in case of XML related error */ public RrdGraphDefTemplate(String xmlString) throws IOException, RrdException { super(xmlString); } /** * Creates RrdGraphDef object which can be used to create RrdGraph * object (actual JRobin graphs). Before this method is called, all template variables (if any) * must be resolved (replaced with real values). * See {@link XmlTemplate#setVariable(String, String) setVariable()} method information to * understand how to supply values for template variables. * * @return Graph definition which can be used to create RrdGraph object (actual JRobin graphs) * @throws RrdException Thrown if parsed XML template contains invalid (unrecognized) tags */ public RrdGraphDef getRrdGraphDef() throws RrdException { // basic check if (!root.getTagName().equals("rrd_graph_def")) { throw new RrdException("XML definition must start with <rrd_graph_def>"); } validateTagsOnlyOnce(root, new String[] {"filename", "span", "options", "datasources", "graph"}); rrdGraphDef = new RrdGraphDef(); // traverse all nodes Node[] childNodes = getChildNodes(root); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("filename")) { resolveFilename(childNode); } // SPAN else if (nodeName.equals("span")) { resolveSpan(childNode); } // OPTIONS else if (nodeName.equals("options")) { resolveOptions(childNode); } // DATASOURCES else if (nodeName.equals("datasources")) { resolveDatasources(childNode); } // GRAPH ELEMENTS else if (nodeName.equals("graph")) { resolveGraphElements(childNode); } } return rrdGraphDef; } private void resolveGraphElements(Node graphNode) throws RrdException { validateTagsOnlyOnce(graphNode, new String[] {"area*", "line*", "stack*", "print*", "gprint*", "hrule*", "vrule*", "comment*"}); Node[] childNodes = getChildNodes(graphNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("area")) { resolveArea(childNode); } else if (nodeName.equals("line")) { resolveLine(childNode); } else if (nodeName.equals("stack")) { resolveStack(childNode); } else if (nodeName.equals("print")) { resolvePrint(childNode, false); } else if (nodeName.equals("gprint")) { resolvePrint(childNode, true); } else if (nodeName.equals("hrule")) { resolveHRule(childNode); } else if (nodeName.equals("vrule")) { resolveVRule(childNode); } else if (nodeName.equals("comment")) { rrdGraphDef.comment(getValue(childNode)); } } } private void resolveVRule(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"time", "color", "legend"}); long timestamp = Long.MIN_VALUE; Paint color = null; String legend = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("time")) { timestamp = Util.getTimestamp(getValue(childNode)); } else if (nodeName.equals("color")) { color = getValueAsColor(childNode); } else if (nodeName.equals("legend")) { legend = getValue(childNode); } } if (timestamp != Long.MIN_VALUE && color != null) { rrdGraphDef.vrule(timestamp, color, legend); } else { throw new RrdException("Incomplete VRULE settings"); } } private void resolveHRule(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"value", "color", "legend"}); double value = Double.NaN; Paint color = null; String legend = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("value")) { value = getValueAsDouble(childNode); } else if (nodeName.equals("color")) { color = getValueAsColor(childNode); } else if (nodeName.equals("legend")) { legend = getValue(childNode); } } if (!Double.isNaN(value) && color != null) { rrdGraphDef.hrule(value, color, legend); } else { throw new RrdException("Incomplete HRULE settings"); } } private void resolvePrint(Node parentNode, boolean isInGraph) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"datasource", "cf", "format"}); String datasource = null, cf = null, format = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("datasource")) { datasource = getValue(childNode); } else if (nodeName.equals("cf")) { cf = getValue(childNode); } else if (nodeName.equals("format")) { format = getValue(childNode); } } if (datasource != null && cf != null && format != null) { if (isInGraph) { rrdGraphDef.gprint(datasource, cf, format); } else { rrdGraphDef.print(datasource, cf, format); } } else { throw new RrdException("Incomplete " + (isInGraph ? "GRPINT" : "PRINT") + " settings"); } } private void resolveStack(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"datasource", "color", "legend"}); String datasource = null, legend = null; Paint color = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("datasource")) { datasource = getValue(childNode); } else if (nodeName.equals("color")) { color = getValueAsColor(childNode); } else if (nodeName.equals("legend")) { legend = getValue(childNode); } } if (datasource != null) { if (color != null) { rrdGraphDef.stack(datasource, color, legend); } else { rrdGraphDef.stack(datasource, BLIND_COLOR, legend); } } else { throw new RrdException("Incomplete STACK settings"); } } private void resolveLine(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"datasource", "color", "legend", "width"}); String datasource = null, legend = null; Paint color = null; float width = 1.0F; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("datasource")) { datasource = getValue(childNode); } else if (nodeName.equals("color")) { color = getValueAsColor(childNode); } else if (nodeName.equals("legend")) { legend = getValue(childNode); } else if (nodeName.equals("width")) { width = (float) getValueAsDouble(childNode); } } if (datasource != null) { if (color != null) { rrdGraphDef.line(datasource, color, legend, width); } else { rrdGraphDef.line(datasource, BLIND_COLOR, legend, width); } } else { throw new RrdException("Incomplete LINE settings"); } } private void resolveArea(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"datasource", "color", "legend"}); String datasource = null, legend = null; Paint color = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("datasource")) { datasource = getValue(childNode); } else if (nodeName.equals("color")) { color = getValueAsColor(childNode); } else if (nodeName.equals("legend")) { legend = getValue(childNode); } } if (datasource != null) { if (color != null) { rrdGraphDef.area(datasource, color, legend); } else { rrdGraphDef.area(datasource, BLIND_COLOR, legend); } } else { throw new RrdException("Incomplete AREA settings"); } } private void resolveDatasources(Node datasourcesNode) throws RrdException { validateTagsOnlyOnce(datasourcesNode, new String[] {"def*", "cdef*", "sdef*"}); Node[] childNodes = getChildNodes(datasourcesNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("def")) { resolveDef(childNode); } else if (nodeName.equals("cdef")) { resolveCDef(childNode); } else if (nodeName.equals("sdef")) { resolveSDef(childNode); } } } private void resolveSDef(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"name", "source", "cf"}); String name = null, source = null, cf = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("name")) { name = getValue(childNode); } else if (nodeName.equals("source")) { source = getValue(childNode); } else if (nodeName.equals("cf")) { cf = getValue(childNode); } } if (name != null && source != null && cf != null) { rrdGraphDef.datasource(name, source, cf); } else { throw new RrdException("Incomplete SDEF settings"); } } private void resolveCDef(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"name", "rpn"}); String name = null, rpn = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("name")) { name = getValue(childNode); } else if (nodeName.equals("rpn")) { rpn = getValue(childNode); } } if (name != null && rpn != null) { rrdGraphDef.datasource(name, rpn); } else { throw new RrdException("Incomplete CDEF settings"); } } private void resolveDef(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"name", "rrd", "source", "cf", "backend"}); String name = null, rrd = null, source = null, cf = null, backend = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("name")) { name = getValue(childNode); } else if (nodeName.equals("rrd")) { rrd = getValue(childNode); } else if (nodeName.equals("source")) { source = getValue(childNode); } else if (nodeName.equals("cf")) { cf = getValue(childNode); } else if (nodeName.equals("backend")) { backend = getValue(childNode); } } if (name != null && rrd != null && source != null && cf != null) { rrdGraphDef.datasource(name, rrd, source, cf, backend); } else { throw new RrdException("Incomplete DEF settings"); } } private void resolveFilename(Node filenameNode) { String filename = getValue(filenameNode); rrdGraphDef.setFilename(filename); } private void resolveSpan(Node spanNode) throws RrdException { validateTagsOnlyOnce(spanNode, new String[] {"start", "end"}); String startStr = getChildValue(spanNode, "start"); String endStr = getChildValue(spanNode, "end"); long[] span = Util.getTimestamps(startStr, endStr); rrdGraphDef.setStartTime(span[0]); rrdGraphDef.setEndTime(span[1]); } private void resolveOptions(Node rootOptionNode) throws RrdException { validateTagsOnlyOnce(rootOptionNode, new String[] { "anti_aliasing", "use_pool", "time_grid", "value_grid", "alt_y_grid", "alt_y_mrtg", "no_minor_grid", "alt_autoscale", "alt_autoscale_max", "units_exponent", "units_length", "vertical_label", "width", "height", "interlaced", "image_info", "image_format", "image_quality", "background_image", "overlay_image", "unit", "lazy", "min_value", "max_value", "rigid", "base", "logarithmic", "colors", "no_legend", "only_graph", "force_rules_legend", "title", "step", "fonts", "first_day_of_week", "signature" }); Node[] optionNodes = getChildNodes(rootOptionNode); for (Node optionNode : optionNodes) { String option = optionNode.getNodeName(); if (option.equals("use_pool")) { rrdGraphDef.setPoolUsed(getValueAsBoolean(optionNode)); } else if (option.equals("anti_aliasing")) { rrdGraphDef.setAntiAliasing(getValueAsBoolean(optionNode)); } else if (option.equals("time_grid")) { resolveTimeGrid(optionNode); } else if (option.equals("value_grid")) { resolveValueGrid(optionNode); } else if (option.equals("no_minor_grid")) { rrdGraphDef.setNoMinorGrid(getValueAsBoolean(optionNode)); } else if (option.equals("alt_y_grid")) { rrdGraphDef.setAltYGrid(getValueAsBoolean(optionNode)); } else if (option.equals("alt_y_mrtg")) { rrdGraphDef.setAltYMrtg(getValueAsBoolean(optionNode)); } else if (option.equals("alt_autoscale")) { rrdGraphDef.setAltAutoscale(getValueAsBoolean(optionNode)); } else if (option.equals("alt_autoscale_max")) { rrdGraphDef.setAltAutoscaleMax(getValueAsBoolean(optionNode)); } else if (option.equals("units_exponent")) { rrdGraphDef.setUnitsExponent(getValueAsInt(optionNode)); } else if (option.equals("units_length")) { rrdGraphDef.setUnitsLength(getValueAsInt(optionNode)); } else if (option.equals("vertical_label")) { rrdGraphDef.setVerticalLabel(getValue(optionNode)); } else if (option.equals("width")) { rrdGraphDef.setWidth(getValueAsInt(optionNode)); } else if (option.equals("height")) { rrdGraphDef.setHeight(getValueAsInt(optionNode)); } else if (option.equals("interlaced")) { rrdGraphDef.setInterlaced(getValueAsBoolean(optionNode)); } else if (option.equals("image_info")) { rrdGraphDef.setImageInfo(getValue(optionNode)); } else if (option.equals("image_format")) { rrdGraphDef.setImageFormat(getValue(optionNode)); } else if (option.equals("image_quality")) { rrdGraphDef.setImageQuality((float) getValueAsDouble(optionNode)); } else if (option.equals("background_image")) { rrdGraphDef.setBackgroundImage(getValue(optionNode)); } else if (option.equals("overlay_image")) { rrdGraphDef.setOverlayImage(getValue(optionNode)); } else if (option.equals("unit")) { rrdGraphDef.setUnit(getValue(optionNode)); } else if (option.equals("lazy")) { rrdGraphDef.setLazy(getValueAsBoolean(optionNode)); } else if (option.equals("min_value")) { rrdGraphDef.setMinValue(getValueAsDouble(optionNode)); } else if (option.equals("max_value")) { rrdGraphDef.setMaxValue(getValueAsDouble(optionNode)); } else if (option.equals("rigid")) { rrdGraphDef.setRigid(getValueAsBoolean(optionNode)); } else if (option.equals("base")) { rrdGraphDef.setBase(getValueAsDouble(optionNode)); } else if (option.equals("logarithmic")) { rrdGraphDef.setLogarithmic(getValueAsBoolean(optionNode)); } else if (option.equals("colors")) { resolveColors(optionNode); } else if (option.equals("no_legend")) { rrdGraphDef.setNoLegend(getValueAsBoolean(optionNode)); } else if (option.equals("only_graph")) { rrdGraphDef.setOnlyGraph(getValueAsBoolean(optionNode)); } else if (option.equals("force_rules_legend")) { rrdGraphDef.setForceRulesLegend(getValueAsBoolean(optionNode)); } else if (option.equals("title")) { rrdGraphDef.setTitle(getValue(optionNode)); } else if (option.equals("step")) { rrdGraphDef.setStep(getValueAsLong(optionNode)); } else if (option.equals("fonts")) { resolveFonts(optionNode); } else if (option.equals("first_day_of_week")) { int dayIndex = resolveFirstDayOfWeek(getValue(optionNode)); rrdGraphDef.setFirstDayOfWeek(dayIndex); } else if (option.equals("signature")) { rrdGraphDef.setShowSignature(getValueAsBoolean(optionNode)); } } } private int resolveFirstDayOfWeek(String firstDayOfWeek) throws RrdException { if (firstDayOfWeek.equalsIgnoreCase("sunday")) { return SUNDAY; } else if (firstDayOfWeek.equalsIgnoreCase("monday")) { return MONDAY; } else if (firstDayOfWeek.equalsIgnoreCase("tuesday")) { return TUESDAY; } else if (firstDayOfWeek.equalsIgnoreCase("wednesday")) { return WEDNESDAY; } else if (firstDayOfWeek.equalsIgnoreCase("thursday")) { return THURSDAY; } else if (firstDayOfWeek.equalsIgnoreCase("friday")) { return FRIDAY; } else if (firstDayOfWeek.equalsIgnoreCase("saturday")) { return SATURDAY; } throw new RrdException("Never heard for this day of week: " + firstDayOfWeek); } private void resolveFonts(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"small_font", "large_font"}); Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("small_font")) { rrdGraphDef.setSmallFont(resolveFont(childNode)); } else if (nodeName.equals("large_font")) { rrdGraphDef.setLargeFont(resolveFont(childNode)); } } } private Font resolveFont(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"name", "style", "size"}); String name = null, style = null; int size = 0; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("name")) { name = getValue(childNode); } else if (nodeName.equals("style")) { style = getValue(childNode).toLowerCase(); } else if (nodeName.equals("size")) { size = getValueAsInt(childNode); } } if (name != null && style != null && size > 0) { boolean isItalic = style.contains("italic"), isBold = style.contains("bold"); int fstyle = Font.PLAIN; if (isItalic && isBold) { fstyle = Font.BOLD + Font.ITALIC; } else if (isItalic) { fstyle = Font.ITALIC; } else if (isBold) { fstyle = Font.BOLD; } return new Font(name, fstyle, size); } else { throw new RrdException("Incomplete font specification"); } } private void resolveColors(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, COLOR_NAMES); Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String colorName = childNode.getNodeName(); rrdGraphDef.setColor(colorName, getValueAsColor(childNode)); } } private void resolveValueGrid(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] {"show_grid", "grid_step", "label_factor"}); boolean showGrid = true; double gridStep = Double.NaN; int NOT_SET = Integer.MIN_VALUE, labelFactor = NOT_SET; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("show_grid")) { showGrid = getValueAsBoolean(childNode); } else if (nodeName.equals("grid_step")) { gridStep = getValueAsDouble(childNode); } else if (nodeName.equals("label_factor")) { labelFactor = getValueAsInt(childNode); } } rrdGraphDef.setDrawYGrid(showGrid); if (!Double.isNaN(gridStep) && labelFactor != NOT_SET) { rrdGraphDef.setValueAxis(gridStep, labelFactor); } else if (!Double.isNaN(gridStep) || labelFactor != NOT_SET) { throw new RrdException("Incomplete value axis settings"); } } private void resolveTimeGrid(Node parentNode) throws RrdException { validateTagsOnlyOnce(parentNode, new String[] { "show_grid", "minor_grid_unit", "minor_grid_unit_count", "major_grid_unit", "major_grid_unit_count", "label_unit", "label_unit_count", "label_span", "label_format" }); boolean showGrid = true; final int NOT_SET = Integer.MIN_VALUE; int minorGridUnit = NOT_SET, minorGridUnitCount = NOT_SET, majorGridUnit = NOT_SET, majorGridUnitCount = NOT_SET, labelUnit = NOT_SET, labelUnitCount = NOT_SET, labelSpan = NOT_SET; String labelFormat = null; Node[] childNodes = getChildNodes(parentNode); for (Node childNode : childNodes) { String nodeName = childNode.getNodeName(); if (nodeName.equals("show_grid")) { showGrid = getValueAsBoolean(childNode); } else if (nodeName.equals("minor_grid_unit")) { minorGridUnit = resolveTimeUnit(getValue(childNode)); } else if (nodeName.equals("minor_grid_unit_count")) { minorGridUnitCount = getValueAsInt(childNode); } else if (nodeName.equals("major_grid_unit")) { majorGridUnit = resolveTimeUnit(getValue(childNode)); } else if (nodeName.equals("major_grid_unit_count")) { majorGridUnitCount = getValueAsInt(childNode); } else if (nodeName.equals("label_unit")) { labelUnit = resolveTimeUnit(getValue(childNode)); } else if (nodeName.equals("label_unit_count")) { labelUnitCount = getValueAsInt(childNode); } else if (nodeName.equals("label_span")) { labelSpan = getValueAsInt(childNode); } else if (nodeName.equals("label_format")) { labelFormat = getValue(childNode); } } rrdGraphDef.setDrawXGrid(showGrid); if (minorGridUnit != NOT_SET && minorGridUnitCount != NOT_SET && majorGridUnit != NOT_SET && majorGridUnitCount != NOT_SET && labelUnit != NOT_SET && labelUnitCount != NOT_SET && labelSpan != NOT_SET && labelFormat != null) { rrdGraphDef.setTimeAxis(minorGridUnit, minorGridUnitCount, majorGridUnit, majorGridUnitCount, labelUnit, labelUnitCount, labelSpan, labelFormat); } else if (minorGridUnit != NOT_SET || minorGridUnitCount != NOT_SET || majorGridUnit != NOT_SET || majorGridUnitCount != NOT_SET || labelUnit != NOT_SET || labelUnitCount != NOT_SET || labelSpan != NOT_SET || labelFormat != null) { throw new RrdException("Incomplete time axis settings"); } } private int resolveTimeUnit(String unit) throws RrdException { if (unit.equalsIgnoreCase("second")) { return RrdGraphConstants.SECOND; } else if (unit.equalsIgnoreCase("minute")) { return RrdGraphConstants.MINUTE; } else if (unit.equalsIgnoreCase("hour")) { return RrdGraphConstants.HOUR; } else if (unit.equalsIgnoreCase("day")) { return RrdGraphConstants.DAY; } else if (unit.equalsIgnoreCase("week")) { return RrdGraphConstants.WEEK; } else if (unit.equalsIgnoreCase("month")) { return RrdGraphConstants.MONTH; } else if (unit.equalsIgnoreCase("year")) { return RrdGraphConstants.YEAR; } throw new RrdException("Unknown time unit specified: " + unit); } }