/* * $Id$ * * Copyright 2006, The jCoderZ.org Project. 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 of the jCoderZ.org Project 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 REGENTS 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 REGENTS AND 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 org.jcoderz.phoenix.chart2d; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.Map.Entry; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import net.sourceforge.chart2d.Chart2D; import net.sourceforge.chart2d.Chart2DProperties; import net.sourceforge.chart2d.Dataset; import net.sourceforge.chart2d.GraphChart2D; import net.sourceforge.chart2d.GraphChart2DProperties; import net.sourceforge.chart2d.GraphProperties; import net.sourceforge.chart2d.LBChart2D; import net.sourceforge.chart2d.LLChart2D; import net.sourceforge.chart2d.LegendProperties; import net.sourceforge.chart2d.MultiColorsProperties; import net.sourceforge.chart2d.Object2DProperties; import net.sourceforge.chart2d.PieChart2D; import net.sourceforge.chart2d.PieChart2DProperties; import net.sourceforge.chart2d.WarningRegionProperties; import org.apache.xpath.XPathAPI; import org.apache.xpath.objects.XObject; import org.jcoderz.commons.types.Date; import org.jcoderz.commons.util.Constants; import org.jcoderz.commons.util.IoUtil; import org.jcoderz.commons.util.LoggingProxy; import org.jcoderz.commons.util.LoggingUtils; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Generated implementation for documents valid against * the chart2d dtd. * * Also give the ability to collect input data from a certain set of * xml files. * The format is currently quite tailored to the needs of a cruise * control log file analysis. This might be opened up if further * requirements come up. * * The format is given by the chart2d api. Look there * http://chart2d.sourceforge.net/ for details. * * The special data collection is always started with a ! do * mark the special format. * * For the <code>AxisLabelText</code> there are 2 additional * attributes: * * <code>count</code>: The number of labels on the x-Axis. * If the dataset contains <code>count * 2</code> or more * entries, n (= <i>number of datasets</i> / count) are put * together in one label. * * <code>max</code>: The maximum number of datasets that are * allowed to be put together under one label. If the number of * available datasets is more than <code>count * max</code> the * elder datasets are discarded. * * The element of <code>AxisLabelText</code> can contain a regular * expression, that is used to search for the logfiles used as * input datasets. The search is started recursive from the * given <i>context path</i>. Path separators must be given * as '/' characters if needed. The first group on the regular * expression is used as label for the dataset. An example could * be <code>!.*log.*BUILD_([0-9]*)\.xml</code> with would use the * number after the <code>BUILD_</code> as labeltext. * * The element of <code>LegendLabelsTexts</code> is the z-Axis. * If the element starts with a <code>!</code> character the * rest must be a xpath expression returning a node set. Each * node of the nodeset will build a element (and label) * on the z-Axis. A valid expression could be: * <code>!/cruisecontrol/findingsummary/servicelevelxml/service/@name</code>. * * The element of <code>Data</code> could also be an xpath * expression. The handler then iterates over this for each * file (dataset) and each value available for the z-Axis. The string * $z is replaced by the current z-Axis value before the xpath * expression is evaluated against the current file (dataset). The * handler takes care for the <code>Set</code>, <code>Category</code>, * <code>Data</code> element nesting. A valid expression could be: * <code>!/cruisecontrol/findingsummary/servicelevelxml/service[@name = '$z']/@quality</code>. * The expression should evaluate to a node that can be parsed as a * float using <code>Float.parseFloat</code> or to a ant timestring * matching the regular pattern * <code>"(([0-9]+) minutes? )?([0-9]+) seconds?"</code> the timestring * will be converted into the number of seconds. Other formats might be * added. * * @author Andreas Mandel * @author Netbeans Code generator. */ public class Chart2DHandlerImpl implements Chart2DHandler { private static final int DEFAULT_WIDTH = 768; private static final int DEFAULT_HEIGHT = 1024; private static final int DEBUG_ARG_NUM = 3; private static final String TIME_PATTERN = "(([0-9]+) minutes? )?([0-9]+) seconds?"; private static final int TIME_PATTERN_MINUTES_GROUP = 2; private static final int TIME_PATTERN_SECONDS_GROUP = 3; private static boolean sDebug = false; private static boolean sMultible = false; private Object2DProperties mObject2DProperties; private Chart2DProperties mChart2DProperties; private GraphChart2DProperties mGraphChart2DProperties; private List mCurrentLabelText; private PieChart2DProperties mPieChart2DProperties; private LegendProperties mLegendProperties; private final List mDataSets = new ArrayList(); private final List mMultiColorsProperties = new ArrayList(); private final List mGraphProperties = new ArrayList(); private final List mWarningRegionProperties = new ArrayList(); private int mWidth = DEFAULT_WIDTH; private int mHeight = DEFAULT_HEIGHT; private String mFilename; private String mType; private List mCurrentDataSet; private List mCurrentSet; private List mCurrentCategory; private MultiColorsProperties mCurrentMultiColorsProperties; private List mCurrentMultiColors; private String mChartType; private List mCurrentLegendLabelsTexts; private boolean mDoConvertToStacked; private final File mDataRepository; private final Set mFilePatterns = new TreeSet(); private final List mXaxis = new ArrayList(); private int mXaxisModulus = 1; private final Map mXpathCache = new HashMap(); private DocumentBuilder mDocumentBuilder; /** * A new handler for cart2d files. * The repository directory is used to read input xml files and to * read and store a cache file. * * @param dataRepository the directory to the logfiles, * can be null. */ public Chart2DHandlerImpl (File dataRepository) { mDataRepository = dataRepository; if (mDataRepository != null) { collectPatterns(mDataRepository, null); if (mFilePatterns.isEmpty()) { throw new RuntimeException("No files found in repository path " + mDataRepository + "."); } readCache(); } } /** * Commandline interface to this handler. * Parameters should be * <input file or dir> [context path] [debug] * * @param args args the commandline aruments. * @throws IOException if a io problem occures. */ public static void main (String[] args) throws IOException { File[] in; File para; if ((args.length < 1) || (args.length > DEBUG_ARG_NUM)) { String msg; msg = "Usage: java " + Chart2DHandlerImpl.class.getName() + " <input file or directory> [context path] [debug]"; log(msg); throw new IllegalArgumentException(msg); } if (args.length == DEBUG_ARG_NUM) { sDebug = true; } File dataRepository = null; if (args.length > 1) { if (args[1].equals("debug")) { sDebug = true; } else { dataRepository = new File(args[1]); } } if (sDebug) { LoggingUtils.setGlobalHandlerLogLevel(Level.ALL); Logger.getLogger("org.jcoderz.phoenix.chart2d").setLevel(Level.ALL); Logger.getLogger("").setLevel(Level.ALL); } para = new File(args[0]); if (para.isFile()) { in = new File[] {para}; } else { final FilenameFilter filter = new FilenameFilter() { public boolean accept (File dir, String name) { return name.endsWith(".xml"); } }; in = para.listFiles(filter); } sMultible = in.length > 1; final Iterator i = Arrays.asList(in).iterator(); while (i.hasNext()) { final File current = (File) i.next(); log("in: " + current.getAbsolutePath()); try { final Chart2DHandlerImpl handler = new Chart2DHandlerImpl(dataRepository); Chart2DHandler theHandler = handler; if (sDebug) { theHandler = (Chart2DHandler) LoggingProxy.getProxy(handler); } Chart2DParser.parse(new InputSource(new FileInputStream(current)), theHandler); handler.writeCache(); } catch (Exception ex) { log("Got exception", ex); } } log("Done."); } /** {@inheritDoc} */ public void handleGraphLabelsLinesStyle (final Attributes meta) throws SAXException { // } /** * Handles opening of Category a new ArrayList is created to * collect inner Data elements. * @param meta the attributes that come with the element. * @throws SAXException never. */ public void startCategory (final Attributes meta) throws SAXException { if (mCurrentSet.size() < mCurrentLabelText.size()) { logDebug("startCategory x = " + mCurrentSet.size() + "/" + mCurrentLabelText.get(mCurrentSet.size())); } mCurrentCategory = new ArrayList(); } /** * Handles the closing of Category. * The Category data, containing the collected Data elements * is added to the corrent Set. * @throws SAXException never. */ public void endCategory () throws SAXException { if (mCurrentSet.size() < mCurrentLabelText.size()) { logDebug("endCategory x = " + mCurrentSet.size() + "/" + mCurrentLabelText.get(mCurrentSet.size())); } mCurrentSet.add(mCurrentCategory); mCurrentCategory = null; } /** * Handles opening of MultiColorsProperties. * @param meta the attributes that come with the element. * @throws SAXException never. */ public void startMultiColorsProperties (final Attributes meta) throws SAXException { final MultiColorsProperties props = new MultiColorsProperties(); props.setMultiColorsPropertiesToDefaults(); setProperties(props, meta); mCurrentMultiColorsProperties = props; mCurrentMultiColors = new ArrayList(); } /** * Handles the end of the MultiColorsProperties element. * Adds the collected MultiColors to the properties. * @throws SAXException never. */ public void endMultiColorsProperties () throws SAXException { if (!mCurrentMultiColors.isEmpty()) { mCurrentMultiColorsProperties .setColorsCustom((Color[]) mCurrentMultiColors .toArray(new Color[] {})); } mMultiColorsProperties.add(mCurrentMultiColorsProperties); mCurrentMultiColors = null; } /** * Handles opening of LBChart2D and registeres the chart type * accordingly. * @param meta the attributes that come with the element. * @throws SAXException never. */ public void startLBChart2D (final Attributes meta) throws SAXException { mChartType = "LBChart2D"; } /** {@inheritDoc} */ public void endLBChart2D () throws SAXException { // } /** * Handles the content of the LegentLablesTexts element. * Special handling for xpath expressions is done here. * See {@link Chart2DHandlerImpl} for details. * @param data the element content. * @param meta attributes set with the element. * @throws SAXException if an error occurs. */ public void handleLegendLabelsTexts (final String data, final Attributes meta) throws SAXException { if (data.startsWith("!")) { try { final DocumentBuilder builder = getDocumentBuilder(); final Document document = builder.parse( new File(mDataRepository, ((Pair) mXaxis.get(mXaxis.size() - 1)).getFileName())); final NodeIterator i = XPathAPI.selectNodeIterator( document, data.substring(1)); Node node = i.nextNode(); while (node != null) { logDebug("Legend Label: " + node.getNodeValue()); mCurrentLegendLabelsTexts.add(node.getNodeValue()); node = i.nextNode(); } } catch (Exception ex) { final SAXException e = new SAXException(ex); e.initCause(ex); throw e; } } else { mCurrentLegendLabelsTexts.add(data); } } /** {@inheritDoc} */ public void startDataset (final Attributes meta) throws SAXException { mDoConvertToStacked = meta.getIndex("DoConvertToStacked") != -1; mCurrentDataSet = new ArrayList(); } /** * Called at the end of a dataset. * The collected data is passed to chart2d. * @throws SAXException if an error occures. */ public void endDataset () throws SAXException { final int zSize = ((List) ((List) mCurrentDataSet.get(0)).get(0)).size(); final int ySize = ((List) mCurrentDataSet.get(0)).size(); final Dataset dataset = new Dataset(mCurrentDataSet.size(), ySize, zSize); if (!sMultible) { log("Dimension: [" + mCurrentDataSet.size() + "][" + ySize + "][" + zSize + "]"); } Iterator i; Iterator j; Iterator k; int x; int y; int z; x = 0; i = mCurrentDataSet.iterator(); while (i.hasNext()) { y = 0; j = ((List) i.next()).iterator(); while (j.hasNext()) { z = 0; k = ((List) j.next()).iterator(); while (k.hasNext()) { final float f = ((Float) k.next()).floatValue(); if (!sMultible) { log("point[" + x + "/" + mCurrentLegendLabelsTexts.get(x) + "][" + y + "/" + mCurrentLabelText.get(y) + "][" + z + "] = " + f); } dataset.set(x, y, z, f); z++; } y++; } x++; } if (mDoConvertToStacked) { dataset.doConvertToStacked(); } mDataSets.add(dataset); mCurrentDataSet = null; } /** {@inheritDoc} */ public void handlePieChart2DProperties (final Attributes meta) throws SAXException { mPieChart2DProperties = new PieChart2DProperties(); mPieChart2DProperties.setPieChart2DPropertiesToDefaults(); setProperties(mPieChart2DProperties, meta); } /** {@inheritDoc} */ public void startGraphChart2DProperties (final Attributes meta) throws SAXException { mGraphChart2DProperties = new GraphChart2DProperties(); mGraphChart2DProperties.setGraphChart2DPropertiesToDefaults(); setProperties(mGraphChart2DProperties, meta); mCurrentLabelText = new ArrayList(); } /** {@inheritDoc} */ public void endGraphChart2DProperties () throws SAXException { if (!mCurrentLabelText.isEmpty()) { mGraphChart2DProperties .setLabelsAxisLabelsTexts((String[]) mCurrentLabelText .toArray(new String[] {})); } } /** {@inheritDoc} */ public void handleAxisLabelText (final java.lang.String data, final Attributes meta) throws SAXException { if (data.startsWith("!")) { // Maximum number of builds aggregated in one label final int max = Integer.parseInt(meta.getValue("max")); // number of labels final int count = Integer.parseInt(meta.getValue("count")); Collection map = fileMatcher(data.substring(1)); int size = map.size(); if (size == 0) { throw new RuntimeException("No files found for pattern " + data + " in " + mDataRepository + "."); } if (size > max * count) { final List newList = new ArrayList(max * count); final Iterator it = map.iterator(); int remove = size - (max * count); while (remove > 0) { it.next(); remove--; } while (it.hasNext()) { newList.add(it.next()); } map = newList; size = map.size(); } mXaxisModulus = Math.max(1, size / count); logDebug("Will have " + mXaxisModulus + " enties per category."); mXaxis.addAll(map); final Iterator i = map.iterator(); int xPos = 0; while (i.hasNext()) { final String label = ((Pair) i.next()).getLabel(); if (xPos % mXaxisModulus == 0) { logDebug("X-Label: " + label); mCurrentLabelText.add(label); } xPos++; } } else { mCurrentLabelText.add(data); } } private List fileMatcher (String filePattern) { final List result = new ArrayList(); final Pattern pattern = Pattern.compile(filePattern); final Iterator i = mFilePatterns.iterator(); while (i.hasNext()) { final String fileName = (String) i.next(); final Matcher m = pattern.matcher(fileName); if (m.matches()) { result.add(new Pair(fileName, m.group(1))); } } return result; } /** {@inheritDoc} */ public void startChart2D (final Attributes meta) throws SAXException { String value; value = meta.getValue("Width"); if (value != null) { mWidth = Integer.decode(value).intValue(); } value = meta.getValue("Height"); if (value != null) { mHeight = Integer.decode(value).intValue(); } value = meta.getValue("Type"); if (value != null) { mType = value; } value = meta.getValue("Filename"); if (value != null) { mFilename = value; } } /** {@inheritDoc} */ public void endChart2D () throws SAXException { try { Chart2D chart2d = null; if ("PieChart2D".equals(mChartType)) { final PieChart2D chart = new PieChart2D(); chart.setObject2DProperties(mObject2DProperties); chart.setChart2DProperties(mChart2DProperties); chart.setPieChart2DProperties(mPieChart2DProperties); chart.setLegendProperties(mLegendProperties); chart.setDataset((Dataset) mDataSets.get(0)); chart.setMultiColorsProperties( (MultiColorsProperties) mMultiColorsProperties.get(0)); chart2d = chart; } else if ("LLChart2D".equals(mChartType)) { final LLChart2D chart = new LLChart2D(); fillChartData(chart); chart2d = chart; } else if ("LBChart2D".equals(mChartType)) { final LBChart2D chart = new LBChart2D(); fillChartData(chart); chart2d = chart; } else { throw new SAXException("Unknown chart type " + mChartType + "."); } final Dimension size = new Dimension(mWidth, mHeight); chart2d.setMaximumSize(size); chart2d.setPreferredSize(size); if (chart2d.validate(false)) { javax.imageio.ImageIO.write(chart2d.getImage(), mType, new File( mFilename)); log("out: " + new File(mFilename).getAbsolutePath()); } else { chart2d.validate(true); } } catch (Exception ex) { final SAXException e = new SAXException(ex); e.initCause(ex); throw e; } } /** {@inheritDoc} */ public void startLLChart2D (final Attributes meta) throws SAXException { mChartType = "LLChart2D"; } /** {@inheritDoc} */ public void endLLChart2D () throws SAXException { // } /** {@inheritDoc} */ public void handleGraphNumbersLinesStyle (final Attributes meta) throws SAXException { // } /** {@inheritDoc} */ public void handleData (final java.lang.String data, final Attributes meta) throws SAXException { if (data.startsWith("!")) { // LOOPIT final Iterator z = mCurrentLegendLabelsTexts.iterator(); while (z.hasNext()) { final String zValue = (String) z.next(); int xPos = 0; final Iterator x = mXaxis.iterator(); while (x.hasNext()) { final Pair pair = (Pair) x.next(); final String fileName = pair.getFileName(); String query = data.substring(1); query = query.replaceAll("\\$z", zValue); String value = resolveXpath(fileName, query); if (value.length() == 0) { value = "0"; } else if (value.indexOf("second") != -1) { value = parseAntTime(value); } mCurrentCategory.add(new Float(Float.parseFloat(value))); xPos++; while (xPos % mXaxisModulus != 0 && !x.hasNext()) { xPos++; // continue chart with last value. mCurrentCategory.add(new Float(Float.parseFloat(value))); } if ((xPos % mXaxisModulus == 0 && x.hasNext()) || (!x.hasNext() && z.hasNext())) { endCategory(); // it is save to call startCategory without a entry... startCategory(null); } } if (z.hasNext()) { endSet(); startSet(null); startCategory(null); } } } else { mCurrentCategory.add(new Float(Float.parseFloat(data))); } } private String parseAntTime (String value) { final Pattern pat = Pattern.compile(TIME_PATTERN); final Matcher mat = pat.matcher(value); logDebug("grops " + value); String result = value; if (mat.matches()) { int minutes = 0; int seconds = 0; if (mat.group(TIME_PATTERN_MINUTES_GROUP) != null) { minutes = Integer.parseInt( mat.group(TIME_PATTERN_MINUTES_GROUP)); } if (mat.group(TIME_PATTERN_SECONDS_GROUP) != null) { seconds = Integer.parseInt( mat.group(TIME_PATTERN_SECONDS_GROUP)); } result = String.valueOf( Date.SECONDS_PER_MINUTE * minutes + seconds); } return result; } private String resolveXpath (String fileName, String xpath) throws SAXException { logDebug(xpath + " in " + fileName); String result = null; final String cacheKey = xpath + "@" + fileName; result = (String) mXpathCache.get(cacheKey); if (result == null) { try { final DocumentBuilder builder = getDocumentBuilder(); final Document document = builder.parse(new File(mDataRepository, fileName)); final XObject object = XPathAPI.eval(document, xpath); result = object.str(); } catch (Exception ex) { final SAXException e = new SAXException(ex); e.initCause(ex); throw e; } logDebug(" = " + result); mXpathCache.put(cacheKey, result); } else { logDebug(" = " + result + " (cached)"); } return result; } /** {@inheritDoc} */ public void startPieChart2D (final Attributes meta) throws SAXException { mChartType = "PieChart2D"; } /** {@inheritDoc} */ public void endPieChart2D () throws SAXException { // } /** {@inheritDoc} */ public void handleObject2DProperties (final Attributes meta) throws SAXException { mObject2DProperties = new Object2DProperties(); mObject2DProperties.setObject2DPropertiesToDefaults(); setProperties(mObject2DProperties, meta); } /** {@inheritDoc} */ public void handleWarningRegionProperties (final Attributes meta) throws SAXException { final WarningRegionProperties props = new WarningRegionProperties(); props.setToDefaults(); setProperties(props, meta); } /** {@inheritDoc} */ public void handleChart2DProperties (final Attributes meta) throws SAXException { mChart2DProperties = new Chart2DProperties(); mChart2DProperties.setChart2DPropertiesToDefaults(); setProperties(mChart2DProperties, meta); } /** {@inheritDoc} */ public void startSet (final Attributes meta) throws SAXException { if (mCurrentDataSet.size() < mCurrentLegendLabelsTexts.size()) { logDebug("startSet z = " + mCurrentDataSet.size() + "/" + mCurrentLegendLabelsTexts.get(mCurrentDataSet.size())); } mCurrentSet = new ArrayList(); } /** {@inheritDoc} */ public void endSet () throws SAXException { if (mCurrentDataSet.size() < mCurrentLegendLabelsTexts.size()) { logDebug("endSet z = " + mCurrentDataSet.size() + "/" + mCurrentLegendLabelsTexts.get(mCurrentDataSet.size())); } mCurrentDataSet.add(mCurrentSet); mCurrentSet = null; } /** {@inheritDoc} */ public void startGraphProperties (final Attributes meta) throws SAXException { final GraphProperties props = new GraphProperties(); props.setGraphPropertiesToDefaults(); setProperties(props, meta); mGraphProperties.add(props); } /** {@inheritDoc} */ public void endGraphProperties () throws SAXException { // } /** {@inheritDoc} */ public void handleColorsCustom (final java.lang.String data, final Attributes meta) throws SAXException { mCurrentMultiColors.add(getColor(data)); } /** {@inheritDoc} */ public void startLegendProperties (final Attributes meta) throws SAXException { mLegendProperties = new LegendProperties(); mLegendProperties.setLegendPropertiesToDefaults(); mCurrentLegendLabelsTexts = new ArrayList(); } /** {@inheritDoc} */ public void endLegendProperties () throws SAXException { if (!mCurrentLegendLabelsTexts.isEmpty()) { mLegendProperties .setLegendLabelsTexts((String[]) mCurrentLegendLabelsTexts .toArray(new String[] {})); } } private void setProperties (Object props, final Attributes meta) { int i = meta.getLength() - 1; for (; i >= 0; i--) { final String key = meta.getQName(i); final String value = meta.getValue(i); Method m; final String setterName = "set" + key; try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {String.class}); m.invoke(props, new Object[] {value}); } catch (Exception ex) { m = null; } if (m == null) { try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {Boolean.TYPE}); m.invoke(props, new Object[] {Boolean.valueOf(value)}); } catch (Exception ex) { m = null; } } if (m == null) { try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {Integer.TYPE}); m.invoke(props, new Object[] {getInteger(value, props)}); } catch (Exception ex) { m = null; } } if (m == null) { try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {Color.class}); m.invoke(props, new Object[] {getColor(value)}); } catch (Exception ex) { m = null; } } if (m == null) { try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {Float.TYPE}); m.invoke(props, new Object[] {Float.valueOf(value)}); } catch (Exception ex) { m = null; } } if (m == null) { try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {Dimension.class}); m.invoke(props, new Object[] {getDimension(value)}); } catch (Exception ex) { m = null; } } if (m == null) { try { m = props.getClass().getDeclaredMethod(setterName, new Class[] {java.awt.AlphaComposite.class}); m.invoke(props, new Object[] {getAlphaComposite(value, props)}); } catch (Exception ex) { m = null; } } if (m == null) { log("Could not set " + props.getClass().getName() + "." + setterName + " = " + value); } } } private Color getColor (String col) { Color c = null; try { try { c = Color.decode(col); } catch (Exception ex) { final Field f = Color.class.getField(col); c = (Color) f.get(null); } } catch (Exception ex) { // no match } return c; } private Dimension getDimension (String val) { final double w = Double.parseDouble(val.substring(0, val.indexOf('x'))); final double h = Double.parseDouble(val.substring(1 + val.indexOf('x'))); final Dimension d = new Dimension(); d.setSize(w, h); return d; } private Integer getInteger (String value, Object properties) throws Exception { int i; try { i = Integer.decode(value).intValue(); } catch (Exception ex) { try { final Field f = properties.getClass().getField(value); i = f.getInt(null); } catch (Exception exx) { final Field f = java.awt.Font.class.getField(value); i = f.getInt(null); } } return new Integer(i); } private AlphaComposite getAlphaComposite (String value, Object properties) throws Exception { AlphaComposite alpha = null; try { final Field f = properties.getClass().getField( value.toUpperCase(Constants.SYSTEM_LOCALE)); alpha = (AlphaComposite) f.get(null); } catch (Exception exx) { try { final Field f = AlphaComposite.class.getField( value.toUpperCase(Constants.SYSTEM_LOCALE)); alpha = AlphaComposite.getInstance(f.getInt(null)); } catch (Exception ex) { try { final Field f = AlphaComposite.class.getField(value); alpha = (AlphaComposite) f.get(null); } catch (Exception exxx) { // no match } } } return alpha; } private void fillChartData (final GraphChart2D chart) { chart.setObject2DProperties(mObject2DProperties); chart.setChart2DProperties(mChart2DProperties); chart.setGraphChart2DProperties(mGraphChart2DProperties); chart.setLegendProperties(mLegendProperties); Iterator i = mDataSets.iterator(); while (i.hasNext()) { chart.addDataset((Dataset) i.next()); } i = mMultiColorsProperties.iterator(); while (i.hasNext()) { chart.addMultiColorsProperties((MultiColorsProperties) i.next()); } i = mGraphProperties.iterator(); while (i.hasNext()) { chart.addGraphProperties((GraphProperties) i.next()); } i = mWarningRegionProperties.iterator(); while (i.hasNext()) { chart.addWarningRegionProperties( (WarningRegionProperties) i.next()); } } /** * Reads the xpath query cache if possible. */ private void readCache () { BufferedReader reader = null; try { final File inFile = new File(mDataRepository, "stat-cache"); if (inFile.canRead()) { reader = new BufferedReader(new FileReader(inFile)); String line = reader.readLine(); while (line != null) { if (line.length() > 0) { final String[] data = line.split("\t"); if (data.length > 1) { mXpathCache.put(data[0], data[1]); } else { mXpathCache.put(data[0], ""); } line = reader.readLine(); } } } } catch (IOException ex) { throw new RuntimeException("Failed to read cache.", ex); } finally { IoUtil.close(reader); } } /** * Writes the xpath query cache if possible. */ public void writeCache () { if (mDataRepository != null) { BufferedWriter writer = null; try { final File file = new File(mDataRepository, "stat-cache"); writer = new BufferedWriter(new FileWriter(file, false)); final Iterator i = mXpathCache.entrySet().iterator(); while (i.hasNext()) { final Entry entry = (Entry) i.next(); writer.write((String) entry.getKey()); writer.write('\t'); writer.write((String) entry.getValue()); writer.write('\n'); } } catch (IOException ex) { throw new RuntimeException("Failed to write cache.", ex); } finally { IoUtil.close(writer); } } } /** * Collects files available in the given path. * @param dataRepository the path to look in * @param path the pattern representation of the path; */ private void collectPatterns (File dataRepository, String path) { final String thisPath; if (path == null) { thisPath = ""; } else { thisPath = path + "/" + dataRepository.getName(); } if (dataRepository.isFile()) { mFilePatterns.add(thisPath); } else if (dataRepository.isDirectory()) { final File[] sub = dataRepository.listFiles(); for (int i = 0; i < sub.length; i++) { collectPatterns(sub[i], thisPath); } } } /** Returns the lazy initialized document builder. */ private DocumentBuilder getDocumentBuilder () throws ParserConfigurationException { if (mDocumentBuilder == null) { mDocumentBuilder = DocumentBuilderFactory.newInstance(). newDocumentBuilder(); } return mDocumentBuilder; } private static void log (String data) { System.out.println(data); } private static void log (String data, Throwable thr) { System.out.println(data + thr.getMessage()); thr.printStackTrace(System.out); } private static void logDebug (String data) { if (sDebug) { log(data); } } private static class Pair { private final String mFileName; private final String mLabel; public Pair (final String fileName, final String label) { super(); mFileName = fileName; mLabel = label; } public String getFileName () { return mFileName; } public String getLabel () { return mLabel; } } }