de.iteratec.iteraplan.presentation.dialog.GraphicalReporting.Line.JFreeChartLineGraphicCreator.java Source code

Java tutorial

Introduction

Here is the source code for de.iteratec.iteraplan.presentation.dialog.GraphicalReporting.Line.JFreeChartLineGraphicCreator.java

Source

/*
 * iteraplan is an IT Governance web application developed by iteratec, GmbH
 * Copyright (C) 2004 - 2014 iteratec, GmbH
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY ITERATEC, ITERATEC DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * 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 Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact iteratec GmbH headquarters at Inselkammerstr. 4
 * 82008 Munich - Unterhaching, Germany, or at email address info@iteratec.de.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "iteraplan" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by iteraplan".
 */
package de.iteratec.iteraplan.presentation.dialog.GraphicalReporting.Line;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.Axis;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;

import de.iteratec.iteraplan.businesslogic.service.TimeseriesService;
import de.iteratec.iteraplan.common.Logger;
import de.iteratec.iteraplan.common.MessageAccess;
import de.iteratec.iteraplan.common.UserContext;
import de.iteratec.iteraplan.common.error.IteraplanBusinessException;
import de.iteratec.iteraplan.common.util.DateUtils;
import de.iteratec.iteraplan.model.attribute.AttributeType;
import de.iteratec.iteraplan.model.attribute.EnumAT;
import de.iteratec.iteraplan.model.attribute.EnumAV;
import de.iteratec.iteraplan.model.attribute.NumberAT;
import de.iteratec.iteraplan.model.attribute.Timeseries;
import de.iteratec.iteraplan.model.attribute.Timeseries.TimeseriesEntry;
import de.iteratec.visualizationmodel.jfreechart.AxisFactory;
import de.iteratec.visualizationmodel.jfreechart.ChartFactory;
import de.iteratec.visualizationmodel.jfreechart.JFreeChartSymbol;

/**
 *
 */
public class JFreeChartLineGraphicCreator {

    private static final Logger LOGGER = Logger.getIteraplanLogger(JFreeChartLineGraphicCreator.class);

    public static final int DEFAULT_HEIGHT = 1000;
    public static final int DEFAULT_WIDTH = 1500;

    private String title;
    private Date fromDate;
    private Date toDate;

    private DateAxis xAxis;
    private Axis yAxis;
    private XYDataset dataset;
    private boolean emptyDataset = false;

    private float xResolution;
    private float yResolution;

    private TimeseriesService timeseriesService;

    /**
     * @return timeseriesService the timeseriesService
     */
    public TimeseriesService getTimeseriesService() {
        return timeseriesService;
    }

    public void setTimeseriesService(TimeseriesService timeseriesService) {
        this.timeseriesService = timeseriesService;
    }

    public JFreeChartSymbol generateJFreeChartSymbol(List<Timeseries> timeseriesList, AttributeType attributeType,
            String startDateString, String endDateString) {
        initData(startDateString, endDateString);
        createAxes(attributeType);
        createDataset(timeseriesList, attributeType);
        return createChart();
    }

    public void initData(String startDateString, String endDateString) {
        setFromDate(getDateFromString(startDateString));
        if (endDateString.isEmpty()) {
            setToDate(new Date());
        } else {
            setToDate(getDateFromString(endDateString));
        }
        setxResolution(DEFAULT_WIDTH);
        setyResolution(DEFAULT_HEIGHT);
        title = MessageAccess.getString("graphicalExport.line.Title", UserContext.getCurrentLocale());
    }

    /**
     * 
     */
    private void createDataset(List<Timeseries> timeseriesList, AttributeType attributeType) {

        XYSeriesCollection xysc = new XYSeriesCollection();

        if (!timeseriesList.isEmpty()) {
            for (Timeseries timeseries : timeseriesList) {
                String name = timeseries.getBuildingBlock().getNonHierarchicalName();
                XYSeries xys = new XYSeries(name);
                List<TimeseriesEntry> entries = timeseries.getEntries();
                orderTimeseriesByTime(entries);
                int firstIdx = getIndexFirstElementToDraw(entries);
                int lastIdx = getIndexLastElementToDraw(entries);
                int beforeIdx = getIndexLastElementBeforeFromDate(entries);
                if (firstIdx > -1) {
                    if (beforeIdx > -1) {
                        xys.add(fromDate.getTime(),
                                toDoubleValue(attributeType, entries.get(beforeIdx).getValue()));
                    }
                    if (firstIdx != lastIdx) {
                        for (int i = firstIdx; i <= lastIdx; i++) {
                            TimeseriesEntry entry = entries.get(i);
                            xys.add(entry.getDate().getTime(), toDoubleValue(attributeType, entry.getValue()));
                        }
                    } else {
                        xys.add(entries.get(firstIdx).getDate().getTime(),
                                toDoubleValue(attributeType, entries.get(firstIdx).getValue()));
                    }
                    /**
                     *Index is set in 'getIndexFirstElementToDraw(entries);' to -1 if there are no entries in the timeseries
                     *to prevent an IndexOutOfBoundsException a simple range check is enough.
                     */
                    if (lastIdx >= 0 && lastIdx <= entries.size()) {
                        //Fge zur XYSeries das Datum hinzu und den wert des Eintags an der Stelle(lastidx)
                        xys.add(toDate.getTime(), toDoubleValue(attributeType, entries.get(lastIdx).getValue()));
                    }
                }
                xysc.addSeries(xys);
                LOGGER.debug("Added data series for {0}", name);
            }
        }
        dataset = xysc;

        int seriesCount = dataset.getSeriesCount();

        if (seriesCount == 0) {
            dataset = createEmptyDataset();
            emptyDataset = true;
        } else {
            emptyDataset = false;
        }

    }

    /**
     * @param entries
     * @return index of the last element to add to the diagram
     */
    private int getIndexLastElementToDraw(List<TimeseriesEntry> entries) {
        int idx = -1;
        for (TimeseriesEntry entry : entries) {
            if (entry.getDate().before(toDate)) {
                idx = entries.indexOf(entry);
            }
        }
        return idx;
    }

    /**
     * @param entries
     * @return index of the first element to add to the diagram
     */
    private int getIndexFirstElementToDraw(List<TimeseriesEntry> entries) {
        for (TimeseriesEntry entry : entries) {
            if (entry.getDate().after(fromDate)) {
                return entries.indexOf(entry);
            }
        }
        return -1;
    }

    private int getIndexLastElementBeforeFromDate(List<TimeseriesEntry> entries) {
        int idx = -1;
        for (TimeseriesEntry entry : entries) {
            Date date = entry.getDate();
            if (date.before(fromDate)) {
                int idxDate = entries.indexOf(entry);
                if (idx < 0) {
                    idx = idxDate;
                } else {
                    if (date.after(entries.get(idx).getDate())) {
                        idx = idxDate;
                    }
                }
            }
        }
        return idx;
    }

    /**
     * @param entries
     */
    private void orderTimeseriesByTime(List<TimeseriesEntry> entries) {
        Collections.sort(entries, new Comparator<TimeseriesEntry>() {
            public int compare(TimeseriesEntry entry1, TimeseriesEntry entry2) {
                return entry1.getDate().compareTo(entry2.getDate());
            }
        });
    }

    /**
     * @param attributeType
     * @param value
     * @return a Double value for the given String value
     */
    private Double toDoubleValue(AttributeType attributeType, String value) {
        if (attributeType instanceof NumberAT) {
            return Double.valueOf(value);
        } else {
            if (attributeType instanceof EnumAT) {
                EnumAT enumAt = (EnumAT) attributeType;
                Map<String, Double> map = mapStringValuesToDouble(enumAt.getSortedAttributeValues());
                return map.get(value);
            }
        }
        return null;
    }

    /**
     * @param sortedEnumAVs
     * @return a map between Double and String values
     */
    private Map<String, Double> mapStringValuesToDouble(List<EnumAV> sortedEnumAVs) {
        Map<String, Double> stringToDouble = new HashMap<String, Double>();
        int i = 0;
        for (EnumAV enumAv : sortedEnumAVs) {
            stringToDouble.put(enumAv.getName(), Double.valueOf(i));
            i++;
        }
        return stringToDouble;
    }

    private XYDataset createEmptyDataset() {
        emptyDataset = true;

        XYSeriesCollection xysc = new XYSeriesCollection();
        XYSeries xys = new XYSeries("");
        xys.add(fromDate.getTime(), null);
        xys.add(toDate.getTime(), null);
        xysc.addSeries(xys);
        return xysc;
    }

    /**
     * 
     */
    private void createAxes(AttributeType attributeType) {
        AxisFactory af = new AxisFactory();

        // Time axis (xAxis)
        xAxis = af.createDateAxis(
                MessageAccess.getString("graphicalExport.line.xAxisLabel", UserContext.getCurrentLocale()));
        xAxis.setRange(fromDate, toDate);
        xAxis.setMinimumDate(fromDate);
        xAxis.setMaximumDate(toDate);
        xAxis.setMinorTickCount(5);
        xAxis.setAutoRange(true);

        // Value axis (yAxis)
        if (attributeType instanceof EnumAT) {
            // yAxis for enumerations

            EnumAT enumAT = (EnumAT) attributeType;
            List<EnumAV> attributeValues = enumAT.getSortedAttributeValues();

            String[] enumArray = new String[attributeValues.size()];

            int i = 0;
            for (EnumAV value : attributeValues) {
                enumArray[i] = value.getName();
                i++;
            }

            yAxis = new SymbolAxis(attributeType.getName(), enumArray);

        } else {
            // yAxis for numerics 
            yAxis = new NumberAxis(attributeType.getName());
        }
    }

    /**
     * Creates the chart and applies some styling.
     * @return the JFreeChart wrapped in an iteratec API symbol.
     */
    private JFreeChartSymbol createChart() {
        try {
            ChartFactory cf = new ChartFactory();
            cf.setTitle(title);
            cf.setxAxis(xAxis);
            cf.setyAxis(yAxis);
            JFreeChart chart = cf.createXYStepChart(dataset);
            LegendTitle legend = chart.getLegend();
            legend.setPosition(RectangleEdge.RIGHT);
            legend.setVisible(!emptyDataset); // don't show a legend, if the dataset is empty
            XYPlot xyplot = (XYPlot) chart.getPlot();
            xyplot.setBackgroundAlpha(0.4f);
            JFreeChartSymbol jfcs = new JFreeChartSymbol(chart);
            jfcs.setWidth(xResolution);
            jfcs.setHeight(yResolution);
            return jfcs;
        } catch (Exception e) {
            throw new IteraplanBusinessException(e);
        }
    }

    private static Date getDateFromString(String dateAsString) {
        return DateUtils.parseAsDate(dateAsString, UserContext.getCurrentLocale());
    }

    /**
     * @return fromDate the fromDate
     */
    public Date getFromDate() {
        return fromDate;
    }

    public void setFromDate(Date fromDate) {
        this.fromDate = fromDate;
    }

    /**
     * @return toDate the toDate
     */
    public Date getToDate() {
        return toDate;
    }

    public void setToDate(Date toDate) {
        Date currentDate = new Date();
        if (toDate.after(currentDate)) {
            this.toDate = currentDate;
        } else {
            this.toDate = toDate;
        }
    }

    /**
     * @return xResolution the xResolution
     */
    public float getxResolution() {
        return xResolution;
    }

    public void setxResolution(float xResolution) {
        this.xResolution = xResolution;
    }

    /**
     * @return yResolution the yResolution
     */
    public float getyResolution() {
        return yResolution;
    }

    public void setyResolution(float yResolution) {
        this.yResolution = yResolution;
    }

}