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  package org.jrobin.core;
26  
27  import org.w3c.dom.Node;
28  import org.xml.sax.InputSource;
29  
30  import java.io.File;
31  import java.io.IOException;
32  import java.util.Calendar;
33  
34  /**
35   * Class used to create an arbitrary number of {@link RrdDef} (RRD definition) objects
36   * from a single XML template. XML template can be supplied as an XML InputSource,
37   * XML file or XML formatted string.<p>
38   * <p/>
39   * Here is an example of a properly formatted XML template with all available
40   * options in it (unwanted options can be removed):<p>
41   * <pre>
42   * &lt;rrd_def&gt;
43   *     &lt;path&gt;test.rrd&lt;/path&gt;
44   *     &lt;!-- not mandatory --&gt;
45   *     &lt;start&gt;1000123456&lt;/start&gt;
46   *     &lt;!-- not mandatory --&gt;
47   *     &lt;step&gt;300&lt;/step&gt;
48   *     &lt;!-- at least one datasource must be supplied --&gt;
49   *     &lt;datasource&gt;
50   *         &lt;name&gt;input&lt;/name&gt;
51   *         &lt;type&gt;COUNTER&lt;/type&gt;
52   *         &lt;heartbeat&gt;300&lt;/heartbeat&gt;
53   *         &lt;min&gt;0&lt;/min&gt;
54   *         &lt;max&gt;U&lt;/max&gt;
55   *     &lt;/datasource&gt;
56   *     &lt;datasource&gt;
57   *         &lt;name&gt;temperature&lt;/name&gt;
58   *         &lt;type&gt;GAUGE&lt;/type&gt;
59   *         &lt;heartbeat&gt;400&lt;/heartbeat&gt;
60   *         &lt;min&gt;U&lt;/min&gt;
61   *         &lt;max&gt;1000&lt;/max&gt;
62   *     &lt;/datasource&gt;
63   *     &lt;!-- at least one archive must be supplied --&gt;
64   *     &lt;archive&gt;
65   *         &lt;cf&gt;AVERAGE&lt;/cf&gt;
66   *         &lt;xff&gt;0.5&lt;/xff&gt;
67   *         &lt;steps&gt;1&lt;/steps&gt;
68   *         &lt;rows&gt;600&lt;/rows&gt;
69   *     &lt;/archive&gt;
70   *     &lt;archive&gt;
71   *         &lt;cf&gt;MAX&lt;/cf&gt;
72   *         &lt;xff&gt;0.6&lt;/xff&gt;
73   *         &lt;steps&gt;6&lt;/steps&gt;
74   *         &lt;rows&gt;7000&lt;/rows&gt;
75   *     &lt;/archive&gt;
76   * &lt;/rrd_def&gt;
77   * </pre>
78   * Notes on the template syntax:<p>
79   * <ul>
80   * <li>There is a strong relation between the XML template syntax and the syntax of
81   * {@link RrdDef} class methods. If you are not sure what some XML tag means, check javadoc
82   * for the corresponding class.
83   * <li>starting timestamp can be supplied either as a long integer
84   * (like: 1000243567) or as an ISO formatted string (like: 2004-02-21 12:25:45)
85   * <li>whitespaces are not harmful
86   * <li>floating point values: anything that cannot be parsed will be treated as Double.NaN
87   * (like: U, unknown, 12r.23)
88   * <li>comments are allowed.
89   * </ul>
90   * Any template value (text between <code>&lt;some_tag&gt;</code> and
91   * <code>&lt;/some_tag&gt;</code>) can be replaced with
92   * a variable of the following form: <code>${variable_name}</code>. Use
93   * {@link XmlTemplate#setVariable(String, String) setVariable()}
94   * methods from the base class to replace template variables with real values
95   * at runtime.<p>
96   * <p/>
97   * Typical usage scenario:<p>
98   * <ul>
99   * <li>Create your XML template and save it to a file (template.xml, for example)
100  * <li>Replace hardcoded template values with variables if you want to change them during runtime.
101  * For example, RRD path should not be hardcoded in the template - you probably want to create
102  * many different RRD files from the same XML template. For example, your XML
103  * template could start with:
104  * <pre>
105  * &lt;rrd_def&gt;
106  *     &lt;path&gt;${path}&lt;/path&gt;
107  *     &lt;step&gt;300&lt;/step&gt;
108  *     ...
109  * </pre>
110  * <li>In your Java code, create RrdDefTemplate object using your XML template file:
111  * <pre>
112  * RrdDefTemplate t = new RrdDefTemplate(new File(template.xml));
113  * </pre>
114  * <li>Then, specify real values for template variables:
115  * <pre>
116  * t.setVariable("path", "demo/test.rrd");
117  * </pre>
118  * <li>Once all template variables are set, just use the template object to create RrdDef
119  * object. This object is actually used to create JRobin RRD files:
120  * <pre>
121  * RrdDef def = t.getRrdDef();
122  * RrdDb rrd = new RrdDb(def);
123  * rrd.close();
124  * </pre>
125  * </ul>
126  * You should create new RrdDefTemplate object only once for each XML template. Single template
127  * object can be reused to create as many RrdDef objects as needed, with different values
128  * specified for template variables. XML synatax check is performed only once - the first
129  * definition object gets created relatively slowly, but it will be created much faster next time.
130  */
131 public class RrdDefTemplate extends XmlTemplate {
132 	/**
133 	 * Creates RrdDefTemplate object from any parsable XML input source. Read general information
134 	 * for this class to find an example of a properly formatted RrdDef XML source.
135 	 *
136 	 * @param xmlInputSource Xml input source
137 	 * @throws IOException  Thrown in case of I/O error
138 	 * @throws RrdException Thrown in case of XML related error (parsing error, for example)
139 	 */
140 	public RrdDefTemplate(InputSource xmlInputSource) throws IOException, RrdException {
141 		super(xmlInputSource);
142 	}
143 
144 	/**
145 	 * Creates RrdDefTemplate object from the string containing XML template.
146 	 * Read general information for this class to see an example of a properly formatted XML source.
147 	 *
148 	 * @param xmlString String containing XML template
149 	 * @throws IOException  Thrown in case of I/O error
150 	 * @throws RrdException Thrown in case of XML related error (parsing error, for example)
151 	 */
152 	public RrdDefTemplate(String xmlString) throws IOException, RrdException {
153 		super(xmlString);
154 	}
155 
156 	/**
157 	 * Creates RrdDefTemplate object from the file containing XML template.
158 	 * Read general information for this class to see an example of a properly formatted XML source.
159 	 *
160 	 * @param xmlFile File object representing file with XML template
161 	 * @throws IOException  Thrown in case of I/O error
162 	 * @throws RrdException Thrown in case of XML related error (parsing error, for example)
163 	 */
164 	public RrdDefTemplate(File xmlFile) throws IOException, RrdException {
165 		super(xmlFile);
166 	}
167 
168 	/**
169 	 * Returns RrdDef object constructed from the underlying XML template. Before this method
170 	 * is called, values for all non-optional placeholders must be supplied. To specify
171 	 * placeholder values at runtime, use some of the overloaded
172 	 * {@link XmlTemplate#setVariable(String, String) setVariable()} methods. Once this method
173 	 * returns, all placeholder values are preserved. To remove them all, call inhereted
174 	 * {@link XmlTemplate#clearValues() clearValues()} method explicitly.<p>
175 	 *
176 	 * @return RrdDef object constructed from the underlying XML template,
177 	 *         with all placeholders replaced with real values. This object can be passed to the constructor
178 	 *         of the new RrdDb object.
179 	 * @throws RrdException Thrown (in most cases) if the value for some placeholder
180 	 *                      was not supplied through {@link XmlTemplate#setVariable(String, String) setVariable()}
181 	 *                      method call
182 	 */
183 	public RrdDef getRrdDef() throws RrdException {
184 		if (!root.getTagName().equals("rrd_def")) {
185 			throw new RrdException("XML definition must start with <rrd_def>");
186 		}
187 		validateTagsOnlyOnce(root, new String[] {
188 				"path", "start", "step", "datasource*", "archive*"
189 		});
190 		// PATH must be supplied or exception is thrown
191 		String path = getChildValue(root, "path");
192 		RrdDef rrdDef = new RrdDef(path);
193 		try {
194 			String startStr = getChildValue(root, "start");
195 			Calendar startGc = Util.getCalendar(startStr);
196 			rrdDef.setStartTime(startGc);
197 		}
198 		catch (RrdException e) {
199 			// START is not mandatory
200 		}
201 		try {
202 			long step = getChildValueAsLong(root, "step");
203 			rrdDef.setStep(step);
204 		}
205 		catch (RrdException e) {
206 			// STEP is not mandatory
207 		}
208 		// datsources
209 		Node[] dsNodes = getChildNodes(root, "datasource");
210 		for (Node dsNode : dsNodes) {
211 			validateTagsOnlyOnce(dsNode, new String[] {
212 					"name", "type", "heartbeat", "min", "max"
213 			});
214 			String name = getChildValue(dsNode, "name");
215 			String type = getChildValue(dsNode, "type");
216 			long heartbeat = getChildValueAsLong(dsNode, "heartbeat");
217 			double min = getChildValueAsDouble(dsNode, "min");
218 			double max = getChildValueAsDouble(dsNode, "max");
219 			rrdDef.addDatasource(name, type, heartbeat, min, max);
220 		}
221 		// archives
222 		Node[] arcNodes = getChildNodes(root, "archive");
223 		for (Node arcNode : arcNodes) {
224 			validateTagsOnlyOnce(arcNode, new String[] {
225 					"cf", "xff", "steps", "rows"
226 			});
227 			String consolFun = getChildValue(arcNode, "cf");
228 			double xff = getChildValueAsDouble(arcNode, "xff");
229 			int steps = getChildValueAsInt(arcNode, "steps");
230 			int rows = getChildValueAsInt(arcNode, "rows");
231 			rrdDef.addArchive(consolFun, xff, steps, rows);
232 		}
233 		return rrdDef;
234 	}
235 }