Java tutorial
/* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server * Copyright (C) 2007, 2008, 2009, 2010, 2013, 2014, 2016 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, * version 2 of the License. * * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <https://www.gnu.org/licenses/>. * ***** END LICENSE BLOCK ***** */ package com.zimbra.perf.chart; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import com.zimbra.common.soap.W3cDomUtil; import com.zimbra.common.soap.XmlParseException; public class XMLChartConfig { // elements public static final String E_CHARTS = "charts"; public static final String E_CHART = "chart"; public static final String E_PLOT = "plot"; public final static String E_GROUP_PLOT = "groupplot"; // <chart> attributes public static final String A_CHART_TITLE = "title"; public static final String A_CHART_CATEGORY = "category"; public static final String A_CHART_OUTFILE = "outfile"; public static final String A_CHART_XAXIS = "xAxis"; public static final String A_CHART_YAXIS = "yAxis"; public static final String A_CHART_ALLOW_LOG_SCALE = "allowLogScale"; public static final String A_CHART_PLOT_ZERO = "plotZero"; public static final String A_CHART_WIDTH = "width"; public static final String A_CHART_HEIGHT = "height"; public final static String A_CHART_DOCUMENT = "outDocument"; public final static String A_CHART_TOP_PLOTS = "topPlots"; public final static String A_CHART_TOP_PLOTS_TYPE = "topPlotsType"; // <plot> attributes public static final String A_PLOT_LEGEND = "legend"; public static final String A_PLOT_INFILE = "infile"; public static final String A_PLOT_DATA_COLUMN = "data"; public static final String A_PLOT_SHOW_RAW = "showRaw"; public static final String A_PLOT_SHOW_MOVING_AVG = "showMovingAvg"; public static final String A_PLOT_MOVING_AVG_POINTS = "movingAvgPoints"; public static final String A_PLOT_MULTIPLIER = "multiplier"; public static final String A_PLOT_DIVISOR = "divisor"; public static final String A_PLOT_NON_NEGATIVE = "nonNegative"; public static final String A_PLOT_PERCENT_TIME = "percentTime"; public static final String A_PLOT_DATA_FUNCTION = "dataFunction"; public static final String A_PLOT_AGGREGATE_FUNCTION = "aggregateFunction"; public static final String A_PLOT_OPTIONAL = "optional"; public static final String A_PLOT_RATIO_TOP = "ratioTop"; public static final String A_PLOT_RATIO_BOTTOM = "ratioBottom"; public static final String A_PLOT_GROUP_BY = "groupBy"; public static final String A_PLOT_IGNORE = "ignore"; private static String getAttr(Element elem, String name) throws DocumentException { String val = elem.attributeValue(name, null); if (val != null) return val; else throw new DocumentException("Missing required attribute " + name + " in element " + elem.getName()); } private static String getAttr(Element elem, String name, String defaultValue) { String val = elem.attributeValue(name, null); if (val != null) return val; else return defaultValue; } private static String getInheritedAttr(Element elem, String name, String defaultValue) { String val = null; for (Element e = elem; val == null && e != null; e = e.getParent()) { val = e.attributeValue(name, null); } return val != null ? val : defaultValue; } private static Boolean getInheritedAttrBoolean(Element elem, String name, boolean defaultValue) { String val = getInheritedAttr(elem, name, null); if (val != null) { val = val.toLowerCase(); return val.equalsIgnoreCase("true") || val.equals("1"); } else return defaultValue; } private static int getInheritedAttrInt(Element elem, String name, int defaultValue) throws DocumentException { String val = getInheritedAttr(elem, name, null); if (val != null) { try { int i = Integer.parseInt(val); return i; } catch (NumberFormatException ex) { throw new DocumentException("Invalid integer value " + val + " for attribute " + name + " in element " + elem.getName()); } } else return defaultValue; } // allows 'k', 'm', 'g' suffix for kilo, mega and giga private static double getInheritedAttrDouble(Element elem, String name, double defaultValue) throws DocumentException { String val = getInheritedAttr(elem, name, null); if (val != null) { int len = val.length(); if (len == 0) return defaultValue; char unit = val.toLowerCase().charAt(len - 1); int multiplier = 1; if (unit == 'k') multiplier = 1024; else if (unit == 'm') multiplier = 1024 * 1024; else if (unit == 'g') multiplier = 1024 * 1024 * 1024; String digits; if (multiplier == 1) digits = val; else digits = val.substring(0, len - 1); try { double d = Double.parseDouble(digits); return d * multiplier; } catch (NumberFormatException ex) { throw new DocumentException( "Invalid double value " + val + " for attribute " + name + " in element " + elem.getName()); } } else return defaultValue; } /** * Loads chart settings from the specified XML file. * * @throws IOException * if there was an error reading the file * @throws DocumentException * if there was an error parsing the file * @throws XmlParseException * @throws IllegalArgumentException * if any attribute has invalid value */ public static List<ChartSettings> load(File xmlFile) throws IOException, DocumentException, XmlParseException { List<ChartSettings> charts = new ArrayList<ChartSettings>(); Document document; try (FileInputStream fis = new FileInputStream(xmlFile)) { document = W3cDomUtil.parseXMLToDom4jDocUsingSecureProcessing(fis); } Element chartsElem = document.getRootElement(); if (!chartsElem.getName().equals(E_CHARTS)) { throw new DocumentException("Missing <" + E_CHARTS + "> root element"); } for (Iterator iter = chartsElem.elementIterator(E_CHART); iter.hasNext();) { Element chartElem = (Element) iter.next(); String chartTitle = getAttr(chartElem, A_CHART_TITLE); String category = getAttr(chartElem, A_CHART_CATEGORY, "unknown"); String outfile = getAttr(chartElem, A_CHART_OUTFILE); // inheritable attributes String xAxis = getInheritedAttr(chartElem, A_CHART_XAXIS, ChartSettings.DEFAULT_CHART_XAXIS); String yAxis = getInheritedAttr(chartElem, A_CHART_YAXIS, ""); boolean allowLogScale = getInheritedAttrBoolean(chartElem, A_CHART_ALLOW_LOG_SCALE, ChartSettings.DEFAULT_CHART_ALLOW_LOG_SCALE); boolean plotZero = getInheritedAttrBoolean(chartElem, A_CHART_PLOT_ZERO, ChartSettings.DEFAULT_CHART_PLOT_ZERO); if (!allowLogScale) plotZero = true; int width = getInheritedAttrInt(chartElem, A_CHART_WIDTH, ChartSettings.DEFAULT_CHART_WIDTH); int height = getInheritedAttrInt(chartElem, A_CHART_HEIGHT, ChartSettings.DEFAULT_CHART_HEIGHT); String outDoc = getAttr(chartElem, A_CHART_DOCUMENT, null); String topPlotStr = getAttr(chartElem, A_CHART_TOP_PLOTS, null); int topPlots = -1; if (topPlotStr != null) topPlots = Integer.parseInt(topPlotStr); topPlotStr = getAttr(chartElem, A_CHART_TOP_PLOTS_TYPE, "max"); ChartSettings.TopPlotsType topPlotsType = ChartSettings.TopPlotsType.valueOf(topPlotStr.toUpperCase()); ChartSettings chart = new ChartSettings(chartTitle, category, outfile, xAxis, yAxis, allowLogScale, plotZero, width, height, outDoc, topPlots, topPlotsType); for (Iterator plotIter = chartElem.elementIterator(E_PLOT); plotIter.hasNext();) { Element plotElem = (Element) plotIter.next(); String dataCol = getAttr(plotElem, A_PLOT_DATA_COLUMN, null); // inheritable attributes String legend = getInheritedAttr(plotElem, A_PLOT_LEGEND, null); String infile = getInheritedAttr(plotElem, A_PLOT_INFILE, null); boolean showRaw = getInheritedAttrBoolean(plotElem, A_PLOT_SHOW_RAW, PlotSettings.DEFAULT_PLOT_SHOW_RAW); boolean showMovingAvg = getInheritedAttrBoolean(plotElem, A_PLOT_SHOW_MOVING_AVG, PlotSettings.DEFAULT_PLOT_SHOW_MOVING_AVG); int movingAvgPoints = getInheritedAttrInt(plotElem, A_PLOT_MOVING_AVG_POINTS, PlotSettings.DEFAULT_PLOT_MOVING_AVG_POINTS); double multiplier = getInheritedAttrDouble(plotElem, A_PLOT_MULTIPLIER, PlotSettings.DEFAULT_PLOT_MULTIPLIER); double divisor = getInheritedAttrDouble(plotElem, A_PLOT_DIVISOR, PlotSettings.DEFAULT_PLOT_DIVISOR); boolean nonNegative = getInheritedAttrBoolean(plotElem, A_PLOT_NON_NEGATIVE, PlotSettings.DEFAULT_PLOT_NON_NEGATIVE); boolean percentTime = getInheritedAttrBoolean(plotElem, A_PLOT_PERCENT_TIME, PlotSettings.DEFAULT_PLOT_PERCENT_TIME); String dataFunction = getAttr(plotElem, A_PLOT_DATA_FUNCTION, PlotSettings.DEFAULT_PLOT_DATA_FUNCTION); String aggFunction = getAttr(plotElem, A_PLOT_AGGREGATE_FUNCTION, PlotSettings.DEFAULT_PLOT_AGGREGATE_FUNCTION); String ratioTop = getAttr(plotElem, A_PLOT_RATIO_TOP, null); String ratioBottom = getAttr(plotElem, A_PLOT_RATIO_BOTTOM, null); if ((ratioTop == null && ratioBottom != null) || (ratioTop != null && ratioBottom == null)) { throw new DocumentException("Both ratioTop/ratioBottom need to be specified"); } if ((ratioTop == null && dataCol == null) || (ratioTop != null && dataCol != null)) { throw new DocumentException("Specify either ratio or data"); } boolean optional = getInheritedAttrBoolean(plotElem, A_PLOT_OPTIONAL, PlotSettings.DEFAULT_PLOT_OPTIONAL); PlotSettings plot = new PlotSettings(legend, infile, dataCol, showRaw, showMovingAvg, movingAvgPoints, multiplier, divisor, nonNegative, percentTime, dataFunction, aggFunction, optional, ratioTop, ratioBottom); chart.addPlot(plot); } for (Iterator plotIter = chartElem.elementIterator(E_GROUP_PLOT); plotIter.hasNext();) { Element plotElem = (Element) plotIter.next(); String dataCol = getAttr(plotElem, A_PLOT_DATA_COLUMN); // inheritable attributes String infile = getInheritedAttr(plotElem, A_PLOT_INFILE, null); boolean showRaw = getInheritedAttrBoolean(plotElem, A_PLOT_SHOW_RAW, PlotSettings.DEFAULT_PLOT_SHOW_RAW); boolean showMovingAvg = getInheritedAttrBoolean(plotElem, A_PLOT_SHOW_MOVING_AVG, PlotSettings.DEFAULT_PLOT_SHOW_MOVING_AVG); int movingAvgPoints = getInheritedAttrInt(plotElem, A_PLOT_MOVING_AVG_POINTS, PlotSettings.DEFAULT_PLOT_MOVING_AVG_POINTS); double multiplier = getInheritedAttrDouble(plotElem, A_PLOT_MULTIPLIER, PlotSettings.DEFAULT_PLOT_MULTIPLIER); double divisor = getInheritedAttrDouble(plotElem, A_PLOT_DIVISOR, PlotSettings.DEFAULT_PLOT_DIVISOR); boolean nonNegative = getInheritedAttrBoolean(plotElem, A_PLOT_NON_NEGATIVE, PlotSettings.DEFAULT_PLOT_NON_NEGATIVE); boolean percentTime = getInheritedAttrBoolean(plotElem, A_PLOT_PERCENT_TIME, PlotSettings.DEFAULT_PLOT_PERCENT_TIME); String dataFunction = getAttr(plotElem, A_PLOT_DATA_FUNCTION, PlotSettings.DEFAULT_PLOT_DATA_FUNCTION); String aggFunction = getAttr(plotElem, A_PLOT_AGGREGATE_FUNCTION, PlotSettings.DEFAULT_PLOT_AGGREGATE_FUNCTION); String groupBy = getAttr(plotElem, A_PLOT_GROUP_BY); String ignore = getAttr(plotElem, A_PLOT_IGNORE, null); boolean optional = getInheritedAttrBoolean(plotElem, A_PLOT_OPTIONAL, PlotSettings.DEFAULT_PLOT_OPTIONAL); GroupPlotSettings plot = new GroupPlotSettings(groupBy, ignore, infile, dataCol, showRaw, showMovingAvg, movingAvgPoints, multiplier, divisor, nonNegative, percentTime, dataFunction, aggFunction, optional); chart.addPlot(plot); } charts.add(chart); } return charts; } }