/* * @(#)ChartGenerator.java * * Copyright 2009 Instituto Superior Tecnico * Founding Authors: Luis Cruz, Nuno Ochoa, Paulo Abrantes * * https://fenix-ashes.ist.utl.pt/ * * This file is part of the Expenditure Tracking Module. * * The Expenditure Tracking Module 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 * 3 of the License, or (at your option) any later version. * * The Expenditure Tracking Module 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 the Expenditure Tracking Module. If not, see <http://www.gnu.org/licenses/>. * */ package pt.ist.expenditureTrackingSystem.presentationTier.actions.statistics; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Map; import java.util.Map.Entry; import javax.imageio.ImageIO; import module.workflow.activities.WorkflowActivity; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.AxisLocation; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.data.CategoryDataset; import org.jfree.data.DefaultCategoryDataset; import pt.ist.expenditureTrackingSystem.domain.acquisitions.AcquisitionProcessStateType; import pt.ist.expenditureTrackingSystem.domain.acquisitions.RefundProcessStateType; import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.AllocateFundsPermanently; import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.AllocateProjectFundsPermanently; import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.Approve; import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.Authorize; import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.FundAllocation; import pt.ist.expenditureTrackingSystem.domain.acquisitions.activities.commons.ProjectFundAllocation; import pt.ist.expenditureTrackingSystem.domain.acquisitions.refund.activities.ConfirmInvoices; import pt.ist.expenditureTrackingSystem.domain.acquisitions.refund.activities.RefundPerson; import pt.ist.expenditureTrackingSystem.domain.acquisitions.refund.activities.SubmitForInvoiceConfirmation; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.ConfirmInvoice; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.CreateAcquisitionPurchaseOrderDocument; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.PayAcquisition; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SendPurchaseOrderToSupplier; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SetSkipSupplierFundAllocation; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SkipPurchaseOrderDocument; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SubmitForApproval; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SubmitForConfirmInvoice; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.SubmitForFundAllocation; import pt.ist.expenditureTrackingSystem.domain.acquisitions.simplified.activities.UnsetSkipSupplierFundAllocation; import pt.ist.expenditureTrackingSystem.domain.statistics.ChartData; import pt.ist.expenditureTrackingSystem.domain.statistics.LogEntry; import pt.ist.expenditureTrackingSystem.domain.statistics.RefundProcessActivityLogStatistics; import pt.ist.expenditureTrackingSystem.domain.statistics.RefundProcessStatistics; import pt.ist.expenditureTrackingSystem.domain.statistics.SimplifiedProcessStatistics; /** * * @author Luis Cruz * @author Paulo Abrantes * */ public class ChartGenerator { protected static JFreeChart createBarChart(final CategoryDataset categoryDataset, final String title) { final JFreeChart chart = ChartFactory.createBarChart3D(title, "", "", categoryDataset, PlotOrientation.VERTICAL, true, true, false); chart.setBackgroundPaint(new Color(0xF5, 0xF5, 0xF5)); final CategoryPlot plot = chart.getCategoryPlot(); plot.setRangeAxisLocation(AxisLocation.TOP_OR_LEFT); final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); return chart; } protected static byte[] createBarChartImage(final CategoryDataset categoryDataset, final String title) throws RuntimeException, IOException { final JFreeChart chart = createBarChart(categoryDataset, title); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final BufferedImage bufferedImage = chart.createBufferedImage(625, 475); ImageIO.write(bufferedImage, "png", outputStream); bufferedImage.flush(); outputStream.close(); return outputStream.toByteArray(); } protected static byte[] createBarChartImage(final ChartData chartData) throws RuntimeException, IOException { final JFreeChart chart = createBarChart(chartData.getDataset(), chartData.getTitle()); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final BufferedImage bufferedImage = chart.createBufferedImage(625, 475); ImageIO.write(bufferedImage, "png", outputStream); bufferedImage.flush(); outputStream.close(); return outputStream.toByteArray(); } public static CategoryDataset simplifiedProcessStatisticsChart(final SimplifiedProcessStatistics simplifiedProcessStatistics) { final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); final Map<AcquisitionProcessStateType, Integer> map = simplifiedProcessStatistics.getNumberOfProcessesByAcquisitionProcessStateType(); char c = 'A'; for (final Entry<AcquisitionProcessStateType, Integer> entry : map.entrySet()) { final AcquisitionProcessStateType acquisitionProcessStateType = entry.getKey(); final Integer numberOfProcesses = entry.getValue(); if (numberOfProcesses.intValue() > 0) { dataset.addValue(numberOfProcesses, "" + c + " - " + acquisitionProcessStateType.getLocalizedName(), Character.valueOf(c++)); } } return dataset; } public static CategoryDataset refundProcessStatisticsChart(final RefundProcessStatistics refundProcessStatistics) { final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); final Map<RefundProcessStateType, Integer> map = refundProcessStatistics.getNumberOfProcessesByRefundProcessStateType(); char c = 'A'; for (final Entry<RefundProcessStateType, Integer> entry : map.entrySet()) { final RefundProcessStateType refundProcessStateType = entry.getKey(); final Integer numberOfProcesses = entry.getValue(); if (numberOfProcesses.intValue() > 0) { dataset.addValue(numberOfProcesses, "" + c + " - " + refundProcessStateType.getLocalizedName(), Character.valueOf(c++)); } } return dataset; } private static CategoryDataset refundProcessStatisticsActivityTimeChart( final RefundProcessActivityLogStatistics refundProcessActivityLogStatistics) { final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); char c = 'A'; for (final LogEntry logEntry : refundProcessActivityLogStatistics.getLogEntries()) { final WorkflowActivity abstractActivity = logEntry.getAbstractActivity(); if (isRelevanteActivity(abstractActivity)) { final String name = abstractActivity.getLocalizedName(); int indexOfSpan = name.indexOf('<'); final String label = indexOfSpan > 0 ? name.substring(0, indexOfSpan) : name; dataset.addValue(logEntry.getDays(), "" + c + " - " + label, Character.valueOf(c++)); } } return dataset; } private static boolean isRelevanteActivity(final WorkflowActivity abstractActivity) { if (abstractActivity == null) { return false; } final Class clazz = abstractActivity.getClass(); return clazz == CreateAcquisitionPurchaseOrderDocument.class || clazz == SendPurchaseOrderToSupplier.class || clazz == SkipPurchaseOrderDocument.class || clazz == SubmitForApproval.class || clazz == SubmitForFundAllocation.class || clazz == Authorize.class || clazz == AllocateProjectFundsPermanently.class || clazz == AllocateFundsPermanently.class || clazz == ProjectFundAllocation.class || clazz == FundAllocation.class || clazz == PayAcquisition.class || clazz == SubmitForConfirmInvoice.class || clazz == ConfirmInvoice.class || clazz == SetSkipSupplierFundAllocation.class || clazz == UnsetSkipSupplierFundAllocation.class || clazz == pt.ist.expenditureTrackingSystem.domain.acquisitions.refund.activities.SubmitForApproval.class || clazz == Approve.class || clazz == SubmitForInvoiceConfirmation.class || clazz == ConfirmInvoices.class || clazz == RefundPerson.class; } public static byte[] simplifiedProcessStatisticsImage(final SimplifiedProcessStatistics simplifiedProcessStatistics) throws RuntimeException, IOException { final CategoryDataset dataset = simplifiedProcessStatisticsChart(simplifiedProcessStatistics); return createBarChartImage(dataset, "Número de Processos"); } public static byte[] refundProcessStatisticsImage(final RefundProcessStatistics refundProcessStatistics) throws RuntimeException, IOException { final CategoryDataset dataset = refundProcessStatisticsChart(refundProcessStatistics); return createBarChartImage(dataset, "Número de Processos"); } public static byte[] refundProcessStatisticsActivityTimeImage( final RefundProcessActivityLogStatistics refundProcessActivityLogStatistics) throws RuntimeException, IOException { final CategoryDataset dataset = refundProcessStatisticsActivityTimeChart(refundProcessActivityLogStatistics); return createBarChartImage(dataset, "Tempo Médio por Actividade (em Dias)"); } }