/*
*
* Copyright (c) void.fm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* Neither the name void.fm nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package etm.contrib.rrd.rrd4j;
import etm.core.monitor.EtmException;
import etm.core.monitor.EtmMonitor;
import etm.core.util.Log;
import etm.core.util.LogAdapter;
import org.rrd4j.core.RrdDb;
import org.rrd4j.core.RrdDef;
import org.rrd4j.core.RrdDefTemplate;
import org.rrd4j.core.XmlTemplate;
import org.rrd4j.graph.RrdGraph;
import org.rrd4j.graph.RrdGraphDef;
import org.rrd4j.graph.RrdGraphDefTemplate;
import org.rrd4j.graph.RrdGraphInfo;
import org.xml.sax.InputSource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Util class for various RRD4j tasks.
*
* @author void.fm
* @version $Revision$
* @since 1.2.0
*/
public class Rrd4jUtil {
public static final String IMAGE_DESTINATION_FILE_VARIABLE = "imagefile";
public static final String RRD_FILE_VARIABLE = "rrdfile";
public static final String INTERVALSTART_VARIABLE = "intervalstart";
public static final String INTERVALEND_VARIABLE = "intervalend";
private static final LogAdapter LOG = Log.getLog(Rrd4jUtil.class);
private static Map templates = new HashMap();
static {
templates.put("highres", "etm/contrib/rrd/rrd4j/template/db/highres-template.xml");
templates.put("mediumres", "etm/contrib/rrd/rrd4j/template/db/mediumres-template.xml");
templates.put("lowres", "etm/contrib/rrd/rrd4j/template/db/lowres-template.xml");
templates.put("average-tx", "etm/contrib/rrd/rrd4j/template/graph/average-and-tx-template.xml");
templates.put("min-average", "etm/contrib/rrd/rrd4j/template/graph/min-average-template.xml");
templates.put("max-average", "etm/contrib/rrd/rrd4j/template/graph/max-average-template.xml");
templates.put("average", "etm/contrib/rrd/rrd4j/template/graph/average-template.xml");
templates.put("min", "etm/contrib/rrd/rrd4j/template/graph/min-template.xml");
templates.put("max", "etm/contrib/rrd/rrd4j/template/graph/max-template.xml");
templates.put("tx", "etm/contrib/rrd/rrd4j/template/graph/tx-template.xml");
}
/**
* Creates a new image using the given template. Assumes
* <ul>
* <li>rrdfile</li>
* <li>imagefile</li>
* <li>intervalstart</li>
* <li>intervalend</li>
* </ul>
*
* @param templateUrl The templateUrl to use. See {@link RrdGraphDefTemplate} for further details.
* @param rrdFile The rrdfile to use
* @param destination The image to create.
* @param intervalStart Start of the rendering interval in seconds.
* @param intervalEnd End of the rendering interval in seconds.
* @param properties Optional properties providing variable values for the . May be null.
*/
public void createGraph(URL templateUrl, File rrdFile, File destination,
long intervalStart, long intervalEnd, Map properties) {
if (properties == null) {
properties = new HashMap();
}
properties.put(RRD_FILE_VARIABLE, rrdFile.getAbsolutePath());
createGraph(templateUrl, destination, intervalStart, intervalEnd, properties);
}
/**
* Creates a new image using the given template. Assumes
* <ul>
* <li>imagefile</li>
* <li>intervalstart</li>
* <li>intervalend</li>
* </ul>
*
* @param templateUrl The templateUrl to use. See {@link RrdGraphDefTemplate} for further details.
* @param destination The image to create.
* @param intervalStart Start of the rendering interval in seconds.
* @param intervalEnd End of the rendering interval in seconds.
* @param properties Optional properties providing variable values for the . May be null.
*/
public void createGraph(URL templateUrl, File destination,
long intervalStart, long intervalEnd, Map properties) {
if (properties == null) {
properties = new HashMap();
}
properties.put(IMAGE_DESTINATION_FILE_VARIABLE, destination.getAbsolutePath());
File parentDir = destination.getParentFile();
if (!parentDir.exists() && !parentDir.mkdirs()) {
LOG.warn("Unable to create directory " + parentDir.getAbsolutePath() + ". Aborting.");
return;
}
createGraph(templateUrl, intervalStart, intervalEnd, properties);
}
/**
* Creates a new image using the given template. Assumes
* <ul>
* <li>intervalstart</li>
* <li>intervalend</li>
* </ul>
*
* @param templateUrl The templateUrl to use. See {@link RrdGraphDefTemplate} for further details.
* @param intervalStart Start of the rendering interval in seconds.
* @param intervalEnd End of the rendering interval in seconds.
* @param properties Optional properties providing variable values for the . May be null.
*/
public void createGraph(URL templateUrl, long intervalStart, long intervalEnd, Map properties) {
if (properties == null) {
properties = new HashMap();
}
properties.put(INTERVALSTART_VARIABLE, new Long(intervalStart));
properties.put(INTERVALEND_VARIABLE, new Long(intervalEnd));
createGraph(templateUrl, properties);
}
/**
* Creates a image using the given template URL and properties.
*
* @param templateUrl The url to the template, may be a classpath to.
* @param properties The properties used to replace in the template.
*/
public void createGraph(URL templateUrl, Map properties) {
setImageDefaults(properties);
try {
URLConnection connection = templateUrl.openConnection();
InputStream in = connection.getInputStream();
try {
RrdGraphDefTemplate template = new RrdGraphDefTemplate(new InputSource(in));
setProperties(template, properties);
RrdGraphDef graphDef = template.getRrdGraphDef();
RrdGraphInfo info = new RrdGraph(graphDef).getRrdGraphInfo();
LOG.info("Created image " + info.getFilename() +
" [" +
info.getWidth() + "x" + info.getHeight() + ", " +
info.getBytes().length + " bytes" +
"]");
} finally {
try {
in.close();
} catch (IOException e) {
// ignore
}
}
} catch (IOException e) {
throw new EtmException(e);
}
}
/**
* Creates a new Rrd4j DB using the given template.
* Always assumes a variable <code>rrdfile</code> in the template that will be replaced
* with the given file path.
*
* @param templateUrl The template url.
* @param rrdFile The rrdfile to create.
* @param properties Optional properties providing variable values for the . May be null.
* @throws EtmException If the file already exists
*/
public void createRrdDb(URL templateUrl, File rrdFile, Map properties) {
if (rrdFile.exists()) {
throw new EtmException("Unable to create rrd file at " + rrdFile.getAbsolutePath() + ". File already available.");
}
File parentDir = rrdFile.getParentFile();
if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {
throw new EtmException("Unable to create rrd directory " + parentDir.getAbsolutePath());
}
if (properties == null) {
properties = new HashMap();
}
properties.put(RRD_FILE_VARIABLE, rrdFile.getAbsolutePath());
try {
URLConnection connection = templateUrl.openConnection();
InputStream in = connection.getInputStream();
try {
RrdDefTemplate template = new RrdDefTemplate(new InputSource(in));
setProperties(template, properties);
RrdDef rrdDef = template.getRrdDef();
RrdDb db = new RrdDb(rrdDef);
db.close();
LOG.info("Created rrd db at " + rrdFile.getAbsolutePath() + " using template " + templateUrl + ".");
} finally {
try {
in.close();
} catch (IOException e) {
// ignored
}
}
} catch (Exception e) {
throw new EtmException(e);
}
}
/**
* Locates a given template and returns a URL to the template. Translates pre defined
* templates to their url within the classpat.
*
* @param aTemplate A template name, might be predefined template, a classpath resource or file.
* @return The URL to the resource
* @throws EtmException Thrown to indicate that the given template could not be found.
*/
public URL locateTemplate(String aTemplate) {
if (templates.containsKey(aTemplate)) {
aTemplate = (String) templates.get(aTemplate);
LOG.debug("Using template " + aTemplate + " from classpath.");
}
ClassLoader loader = EtmMonitor.class.getClassLoader();
URL resource = loader.getResource(aTemplate);
if (resource != null) {
return resource;
}
File file = new File(aTemplate);
if (file.exists()) {
try {
return file.toURL();
} catch (MalformedURLException e) {
throw new EtmException(e);
}
}
throw new EtmException("Unable to locate template " + aTemplate + " in ClassPath or Filesystem.");
}
private void setProperties(XmlTemplate aTemplate, Map properties) {
Iterator it = properties.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
Object value = properties.get(key);
if (value instanceof String) {
aTemplate.setVariable(key, (String) value);
} else if (value instanceof Calendar) {
aTemplate.setVariable(key, (Calendar) value);
} else if (value instanceof Long) {
aTemplate.setVariable(key, ((Long) value).longValue());
} else if (value instanceof Date) {
aTemplate.setVariable(key, (Date) value);
} else {
aTemplate.setVariable(key, String.valueOf(value));
}
}
}
private void setImageDefaults(Map properties) {
if (properties.get("logarithmic") == null) {
properties.put("logarithmic", "false");
}
DateFormat format = SimpleDateFormat.getInstance();
if (properties.get("intervalstart") != null && properties.get("intervalend") != null) {
Long start = (Long) properties.get("intervalstart");
Long end = (Long) properties.get("intervalend");
Date startDate = new Date(start.longValue() * 1000);
Date endDate = new Date(end.longValue() * 1000);
properties.put("generatedstamp",
"Monitoring period: " + format.format(startDate) + " - " + format.format(endDate) +
" [Generated " + format.format(new Date()) + "]\\r");
} else {
properties.put("generatedstamp", "Generated " + format.format(new Date()) + "\\r");
}
if (properties.get("imagetitle") == null) {
properties.put("imagetitle", "Current performance results");
}
}
}