org.exist.xquery.modules.jfreechart.JFreeChartFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.exist.xquery.modules.jfreechart.JFreeChartFactory.java

Source

/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2009 The eXist Project
 *  http://exist-db.org
 *
 *  This program 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
 *  of the License, or (at your option) any later version.
 *
 *  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 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  $Id$
 */
package org.exist.xquery.modules.jfreechart;

import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.StringTokenizer;

import org.apache.log4j.Logger;
import org.exist.xquery.XPathException;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.SpiderWebPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.xml.DatasetReader;
import org.jfree.ui.RectangleEdge;

/**
 * Wrapper for JFreeChart's ChartFactory.
 *
 * @author Dannes Wessels (dizzzz@exist-db.org)
 * @author Andrzej Taramina (andrzej@chaeron.com)
 * @author Leif-Jran Olsson (ljo@exist-db.org)
 */
public class JFreeChartFactory {

    private final static Logger logger = Logger.getLogger(JFreeChartFactory.class);

    /**
     *  Create JFreeChart graph using the supplied parameters.
     *
     * @param chartType One of the many chart types.
     * @param conf      Chart configuration
     * @param is        Inputstream containing chart data
     * @return          Initialized chart or NULL in case of issues.
     * @throws IOException Thrown when a problem is reported while parsing XML data.
     */
    public static JFreeChart createJFreeChart(String chartType, Configuration conf, InputStream is)
            throws XPathException {

        logger.debug("Generating " + chartType);

        // Currently two dataset types supported
        CategoryDataset categoryDataset = null;
        PieDataset pieDataset = null;

        try {
            if ("PieChart".equals(chartType) || "PieChart3D".equals(chartType) || "RingChart".equals(chartType)) {
                logger.debug("Reading XML PieDataset");
                pieDataset = DatasetReader.readPieDatasetFromXML(is);

            } else {
                logger.debug("Reading XML CategoryDataset");
                categoryDataset = DatasetReader.readCategoryDatasetFromXML(is);
            }

        } catch (IOException ex) {
            throw new XPathException(ex.getMessage());

        } finally {
            try {
                is.close();
            } catch (IOException ex) {
                //
            }
        }

        // Return chart
        JFreeChart chart = null;

        // Big chart type switch
        if ("AreaChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createAreaChart(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("BarChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createBarChart(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("BarChart3D".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createBarChart3D(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("LineChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createLineChart(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("LineChart3D".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createLineChart3D(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("MultiplePieChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createMultiplePieChart(conf.getTitle(), categoryDataset, conf.getOrder(),
                    conf.isGenerateLegend(), conf.isGenerateTooltips(), conf.isGenerateUrls());

            setPieChartParameters(chart, conf);

        } else if ("MultiplePieChart3D".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createMultiplePieChart3D(conf.getTitle(), categoryDataset, conf.getOrder(),
                    conf.isGenerateLegend(), conf.isGenerateTooltips(), conf.isGenerateUrls());

            setPieChartParameters(chart, conf);

        } else if ("PieChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createPieChart(conf.getTitle(), pieDataset, conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setPieChartParameters(chart, conf);

        } else if ("PieChart3D".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createPieChart3D(conf.getTitle(), pieDataset, conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setPieChartParameters(chart, conf);

        } else if ("RingChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createRingChart(conf.getTitle(), pieDataset, conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setPieChartParameters(chart, conf);
        } else if ("SpiderWebChart".equalsIgnoreCase(chartType)) {
            SpiderWebPlot plot = new SpiderWebPlot(categoryDataset);
            if (conf.isGenerateTooltips()) {
                plot.setToolTipGenerator(new StandardCategoryToolTipGenerator());
            }
            chart = new JFreeChart(conf.getTitle(), JFreeChart.DEFAULT_TITLE_FONT, plot, false);

            if (conf.isGenerateLegend()) {
                LegendTitle legend = new LegendTitle(plot);
                legend.setPosition(RectangleEdge.BOTTOM);
                chart.addSubtitle(legend);
            } else {
                TextTitle subTitle = new TextTitle(" ");
                subTitle.setPosition(RectangleEdge.BOTTOM);
                chart.addSubtitle(subTitle);
            }

            setCategoryChartParameters(chart, conf);

        } else if ("StackedAreaChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createStackedAreaChart(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("StackedBarChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createStackedBarChart(conf.getTitle(), conf.getDomainAxisLabel(),
                    conf.getRangeAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("StackedBarChart3D".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createStackedBarChart3D(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);

        } else if ("WaterfallChart".equalsIgnoreCase(chartType)) {
            chart = ChartFactory.createWaterfallChart(conf.getTitle(), conf.getCategoryAxisLabel(),
                    conf.getValueAxisLabel(), categoryDataset, conf.getOrientation(), conf.isGenerateLegend(),
                    conf.isGenerateTooltips(), conf.isGenerateUrls());

            setCategoryChartParameters(chart, conf);
        } else {
            logger.error("Illegal chartype. Choose one of " + "AreaChart BarChart BarChart3D LineChart LineChart3D "
                    + "MultiplePieChart MultiplePieChart3D PieChart PieChart3D "
                    + "RingChart SpiderWebChart StackedAreaChart StackedBarChart "
                    + "StackedBarChart3D WaterfallChart");
        }

        setCommonParameters(chart, conf);

        return chart;
    }

    private static void setCategoryChartParameters(JFreeChart chart, Configuration config) throws XPathException {
        setCategoryRange(chart, config);
        setCategoryItemLabelGenerator(chart, config);
        setSeriesColors(chart, config);
        setAxisColors(chart, config);
    }

    private static void setCategoryRange(JFreeChart chart, Configuration config) {
        Double rangeLowerBound = config.getRangeLowerBound();
        Double rangeUpperBound = config.getRangeUpperBound();

        if (rangeUpperBound != null) {
            if (chart.getPlot() instanceof SpiderWebPlot) {
                ((SpiderWebPlot) chart.getPlot()).setMaxValue(rangeUpperBound.doubleValue());
                return;
            } else {
                ((CategoryPlot) chart.getPlot()).getRangeAxis().setUpperBound(rangeUpperBound.doubleValue());
            }
        }

        if (rangeLowerBound != null) {
            ((CategoryPlot) chart.getPlot()).getRangeAxis().setLowerBound(rangeLowerBound.doubleValue());
        }
    }

    private static void setCategoryItemLabelGenerator(JFreeChart chart, Configuration config)
            throws XPathException {
        String className = config.getCategoryItemLabelGeneratorClass();
        CategoryItemLabelGenerator generator = null;

        if (className != null) {
            try {
                Class generatorClass = Class.forName(className);

                Class[] argsClass = new Class[] { String.class, NumberFormat.class };
                String param = config.getCategoryItemLabelGeneratorParameter();
                NumberFormat fmt = new DecimalFormat(config.getCategoryItemLabelGeneratorNumberFormat());
                Object[] args = new Object[] { param, fmt };

                Constructor argsConstructor = generatorClass.getConstructor(argsClass);

                generator = (CategoryItemLabelGenerator) argsConstructor.newInstance(args);
            } catch (Exception e) {
                throw (new XPathException(
                        "Cannot instantiate CategoryItemLabelGeneratorClass: " + className + ", exception: " + e));
            }

            if (chart.getPlot() instanceof SpiderWebPlot) {
                ((SpiderWebPlot) chart.getPlot()).setLabelGenerator(generator);
            } else {
                CategoryItemRenderer renderer = ((CategoryPlot) chart.getPlot()).getRenderer();

                renderer.setBaseItemLabelGenerator(generator);

                renderer.setItemLabelsVisible(true);
            }
        }
    }

    private static void setSeriesColors(JFreeChart chart, Configuration config) {
        String seriesColors = config.getSeriesColors();

        if (chart.getPlot() instanceof SpiderWebPlot) {
            setSeriesColors((SpiderWebPlot) chart.getPlot(), seriesColors);
        } else {
            CategoryItemRenderer renderer = ((CategoryPlot) chart.getPlot()).getRenderer();
            setSeriesColors(renderer, seriesColors);
        }
    }

    private static void setSeriesColors(Object renderer, final String seriesColors) {
        if (seriesColors != null) {
            StringTokenizer st = new StringTokenizer(seriesColors, ",");

            int i = 0;
            while (st.hasMoreTokens()) {
                String colorName = st.nextToken().trim();
                Color color = null;
                try {
                    color = Colour.getColor(colorName);
                } catch (XPathException e) {
                }

                if (color != null) {
                    if (renderer instanceof SpiderWebPlot) {
                        ((SpiderWebPlot) renderer).setSeriesPaint(i, color);
                    } else {
                        ((CategoryItemRenderer) renderer).setSeriesPaint(i, color);
                    }
                } else {
                    logger.warn("Invalid colour name or hex value specified for SeriesColors: " + colorName
                            + ", default colour will be used instead.");
                }

                i++;
            }
        }
    }

    private static void setAxisColors(JFreeChart chart, Configuration config) {
        Color categoryAxisColor = config.getCategoryAxisColor();
        Color valueAxisColor = config.getValueAxisColor();

        if (categoryAxisColor != null) {
            if (chart.getPlot() instanceof SpiderWebPlot) {
                ((SpiderWebPlot) chart.getPlot()).setAxisLinePaint(categoryAxisColor);
            } else {
                ((CategoryPlot) chart.getPlot()).getDomainAxis().setLabelPaint(categoryAxisColor);
            }
        }

        if (valueAxisColor != null) {
            if (chart.getPlot() instanceof SpiderWebPlot) {
                //((SpiderWebPlot) chart.getPlot()).setAxisLinePaint(valueAxisColor);
            } else {
                ((CategoryPlot) chart.getPlot()).getRangeAxis().setLabelPaint(valueAxisColor);
            }
        }
    }

    private static void setPieChartParameters(JFreeChart chart, Configuration config) {
        setPieSectionLabel(chart, config);
        setSectionColors(chart, config);
    }

    private static void setPieSectionLabel(JFreeChart chart, Configuration config) {
        String pieSectionLabel = config.getPieSectionLabel();
        String pieSectionNumberFormat = config.getPieSectionNumberFormat();
        String pieSectionPercentFormat = config.getPieSectionPercentFormat();

        if (pieSectionLabel != null) {
            ((PiePlot) chart.getPlot()).setLabelGenerator(new StandardPieSectionLabelGenerator(pieSectionLabel,
                    new DecimalFormat(pieSectionNumberFormat), new DecimalFormat(pieSectionPercentFormat)));
        }
    }

    private static void setSectionColors(JFreeChart chart, Configuration config) {
        String sectionColors = config.getSectionColors();
        String sectionColorsDelimiter = config.getSectionColorsDelimiter();

        if (sectionColors != null) {
            PiePlot plot = ((PiePlot) chart.getPlot());

            StringTokenizer st = new StringTokenizer(sectionColors, sectionColorsDelimiter);

            while (st.hasMoreTokens()) {
                String sectionName = st.nextToken().trim();
                String colorName = "";

                if (st.hasMoreTokens()) {
                    colorName = st.nextToken().trim();
                }

                Color color = null;

                try {
                    color = Colour.getColor(colorName);
                } catch (XPathException e) {
                }

                if (color != null) {
                    plot.setSectionPaint(sectionName, color);
                } else {
                    logger.warn("Invalid colour name or hex value specified for SectionColors: " + colorName
                            + ", default colour will be used instead. Section Name: " + sectionName);
                }
            }
        }
    }

    private static void setCommonParameters(JFreeChart chart, Configuration config) {
        setColors(chart, config);
    }

    private static void setColors(JFreeChart chart, Configuration config) {
        Color titleColor = config.getTitleColor();
        Color chartBackgroundColor = config.getChartBackgroundColor();
        Color plotBackgroundColor = config.getPlotBackgroundColor();

        if (titleColor != null) {
            chart.getTitle().setPaint(titleColor);
        }

        if (chartBackgroundColor != null) {
            chart.setBackgroundPaint(chartBackgroundColor);
        }

        if (plotBackgroundColor != null) {
            chart.getPlot().setBackgroundPaint(plotBackgroundColor);
        }
    }
}