org.cgiar.ccafs.marlo.action.summaries.InstitutionsSummaryAction.java Source code

Java tutorial

Introduction

Here is the source code for org.cgiar.ccafs.marlo.action.summaries.InstitutionsSummaryAction.java

Source

/*****************************************************************
 * This file is part of Managing Agricultural Research for Learning &
 * Outcomes Platform (MARLO).
 * MARLO 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, either version 3 of the License, or
 * at your option) any later version.
 * MARLO 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 MARLO. If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************/

package org.cgiar.ccafs.marlo.action.summaries;

import org.cgiar.ccafs.marlo.config.APConstants;
import org.cgiar.ccafs.marlo.data.manager.GlobalUnitManager;
import org.cgiar.ccafs.marlo.data.manager.PhaseManager;
import org.cgiar.ccafs.marlo.data.manager.ProjectManager;
import org.cgiar.ccafs.marlo.data.model.Institution;
import org.cgiar.ccafs.marlo.data.model.InstitutionLocation;
import org.cgiar.ccafs.marlo.data.model.InstitutionType;
import org.cgiar.ccafs.marlo.data.model.LocElement;
import org.cgiar.ccafs.marlo.data.model.Project;
import org.cgiar.ccafs.marlo.data.model.ProjectPartner;
import org.cgiar.ccafs.marlo.data.model.ProjectPartnerLocation;
import org.cgiar.ccafs.marlo.data.model.ProjectStatusEnum;
import org.cgiar.ccafs.marlo.utils.APConfig;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.dispatcher.Parameter;
import org.pentaho.reporting.engine.classic.core.CompoundDataFactory;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.ItemBand;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.TableDataFactory;
import org.pentaho.reporting.engine.classic.core.modules.output.table.xls.ExcelReportUtil;
import org.pentaho.reporting.engine.classic.core.util.TypedTableModel;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Andrs Felipe Valencia Rivera. CCAFS
 */

public class InstitutionsSummaryAction extends BaseSummariesAction implements Summary {

    private static final long serialVersionUID = 4871536980466987571L;

    private static Logger LOG = LoggerFactory.getLogger(InstitutionsSummaryAction.class);

    public static double round(double value, int places) {
        if (places < 0) {
            throw new IllegalArgumentException();
        }

        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

    private final ResourceManager resourceManager;

    // Parameters
    private long startTime;
    HashMap<InstitutionType, Set<Institution>> institutionsPerType = new HashMap<InstitutionType, Set<Institution>>();
    HashMap<Institution, Set<Project>> projectsPerInstitution = new HashMap<Institution, Set<Project>>();
    HashMap<Institution, Set<LocElement>> countriesPerInstitution = new HashMap<Institution, Set<LocElement>>();
    Set<LocElement> countries = new HashSet<>();
    Set<Project> projects = new HashSet<>();

    private String partnerType;
    // XLSX bytes
    private byte[] bytesXLSX;

    // Streams
    InputStream inputStream;

    @Inject
    public InstitutionsSummaryAction(APConfig config, GlobalUnitManager crpManager, PhaseManager phaseManager,
            ResourceManager resourceManager, ProjectManager projectManager) {
        super(config, crpManager, phaseManager, projectManager);
        this.resourceManager = resourceManager;
    }

    /**
     * Method to add i8n parameters to masterReport in Pentaho
     * 
     * @param masterReport
     * @return masterReport with i8n parameters added
     */
    private MasterReport addi8nParameters(MasterReport masterReport) {
        if (partnerType.equals("All")) {
            masterReport.getParameterValues().put("i8nSummaryDescription",
                    this.getText("summaries.partners.description", new String[] { this.getSelectedCycle() }));
            masterReport.getParameterValues().put("i8nHeader",
                    this.getText("summaries.partners.header", new String[] { this.getLoggedCrp().getAcronym() }));
        } else {
            masterReport.getParameterValues().put("i8nSummaryDescription", this
                    .getText("summaries.partners.leader.description", new String[] { this.getSelectedCycle() }));
            masterReport.getParameterValues().put("i8nHeader", this.getText("summaries.partners.leader.header",
                    new String[] { this.getLoggedCrp().getAcronym() }));
        }

        masterReport.getParameterValues().put("i8nName", this.getText("summaries.partners.name"));
        masterReport.getParameterValues().put("i8nAcronym", this.getText("summaries.partners.acronym"));
        masterReport.getParameterValues().put("i8nWebSite", this.getText("summaries.partners.website"));
        masterReport.getParameterValues().put("i8nType", this.getText("summaries.partners.type"));
        masterReport.getParameterValues().put("i8nCountry", this.getText("summaries.partners.country"));
        masterReport.getParameterValues().put("i8nProjects", this.getText("caseStudy.projects"));
        masterReport.getParameterValues().put("i8nProjectsTitle", this.getText("summaries.partners.projectTitle"));
        masterReport.getParameterValues().put("i8nProjectCountry",
                "Project " + this.getText("partner.countryOffices"));
        return masterReport;
    }

    private void createIntitutionsProjectsList() {

        // Status of projects
        String[] statuses = { ProjectStatusEnum.Ongoing.getStatusId(), ProjectStatusEnum.Extended.getStatusId() };

        // Get projects with the status defined
        List<Project> projectList = this.getActiveProjectsByPhase(this.getSelectedPhase(), this.getSelectedYear(),
                statuses);

        for (Project project : projectList) {

            List<ProjectPartner> projectPartnerList = project.getProjectPartners().stream().filter(
                    pp -> pp.isActive() && pp.getPhase() != null && pp.getPhase().equals(this.getSelectedPhase()))
                    .collect(Collectors.toList());

            if (!partnerType.equals("All")) {
                List<ProjectPartner> projectPartnerLeaderList = new ArrayList<>();
                for (ProjectPartner projectPartner : projectPartnerList) {
                    projectPartner.setPartnerPersons(projectPartner.getProjectPartnerPersons().stream()
                            .filter(ppp -> ppp.isActive()).collect(Collectors.toList()));
                    if (projectPartner.isLeader()) {
                        projectPartnerLeaderList.add(projectPartner);
                    }
                }
                projectPartnerList = projectPartnerLeaderList;
            }

            for (ProjectPartner projectPartner : projectPartnerList) {
                if (projectPartner.getInstitution() != null) {
                    Institution institution = projectPartner.getInstitution();
                    InstitutionType institutionType = institution.getInstitutionType();
                    List<InstitutionLocation> institutionLocation = institution.getInstitutionsLocations().stream()
                            .filter(l -> l.isActive() && l.isHeadquater()).collect(Collectors.toList());
                    if (institutionLocation != null && institutionLocation.size() > 0) {
                        countries.add(institutionLocation.get(0).getLocElement());
                    }
                    projects.add(project);
                    // institutionsPerType
                    if (institutionsPerType.containsKey(institutionType)) {
                        Set<Institution> institutionSet = institutionsPerType.get(institutionType);
                        institutionSet.add(institution);
                        institutionsPerType.put(institutionType, institutionSet);
                    } else {
                        Set<Institution> institutionSet = new HashSet<>();
                        institutionSet.add(institution);
                        institutionsPerType.put(institutionType, institutionSet);
                    }

                    // projectsPerInstitution
                    if (projectsPerInstitution.containsKey(institution)) {
                        Set<Project> projectSet = projectsPerInstitution.get(institution);
                        projectSet.add(project);
                        projectsPerInstitution.put(institution, projectSet);
                    } else {
                        Set<Project> projectSet = new HashSet<>();
                        projectSet.add(project);
                        projectsPerInstitution.put(institution, projectSet);
                    }

                    // countriesPerInstitution
                    List<ProjectPartnerLocation> projectPartnerLocations = projectPartner
                            .getProjectPartnerLocations().stream().filter(ppl -> ppl.isActive())
                            .collect(Collectors.toList());
                    if (countriesPerInstitution.containsKey(institution)) {
                        Set<LocElement> countriesSet = countriesPerInstitution.get(institution);
                        if (projectPartnerLocations != null && !projectPartnerLocations.isEmpty()) {

                            for (ProjectPartnerLocation projectPartnerLocation : projectPartnerLocations) {
                                if (projectPartnerLocation.getInstitutionLocation() != null) {
                                    countriesSet
                                            .add(projectPartnerLocation.getInstitutionLocation().getLocElement());
                                    countries.add(projectPartnerLocation.getInstitutionLocation().getLocElement());
                                }
                            }
                        }

                        countriesPerInstitution.put(institution, countriesSet);
                    } else {
                        Set<LocElement> countriesSet = new HashSet<>();
                        if (projectPartnerLocations != null && !projectPartnerLocations.isEmpty()) {
                            for (ProjectPartnerLocation projectPartnerLocation : projectPartnerLocations) {
                                if (projectPartnerLocation.getInstitutionLocation() != null) {
                                    countriesSet
                                            .add(projectPartnerLocation.getInstitutionLocation().getLocElement());
                                    countries.add(projectPartnerLocation.getInstitutionLocation().getLocElement());
                                }
                            }
                        }
                        countriesPerInstitution.put(institution, countriesSet);
                    }

                }
            }
        }
    }

    @Override
    public String execute() throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            Resource reportResource = resourceManager.createDirectly(
                    this.getClass().getResource("/pentaho/crp/ProjectPartners.prpt"), MasterReport.class);

            MasterReport masterReport = (MasterReport) reportResource.getResource();
            // Set Main_Query
            CompoundDataFactory cdf = CompoundDataFactory.normalize(masterReport.getDataFactory());
            String masterQueryName = "main";
            TableDataFactory sdf = (TableDataFactory) cdf.getDataFactoryForQuery(masterQueryName);
            TypedTableModel model = this.getMasterTableModel();
            sdf.addTable(masterQueryName, model);
            masterReport.setDataFactory(cdf);
            // Set i8n for pentaho
            masterReport = this.addi8nParameters(masterReport);
            // Get details band
            ItemBand masteritemBand = masterReport.getItemBand();
            // Create new empty subreport hash map
            HashMap<String, Element> hm = new HashMap<String, Element>();
            // method to get all the subreports in the prpt and store in the HashMap
            this.getAllSubreports(hm, masteritemBand);
            this.createIntitutionsProjectsList();
            masterReport.getParameterValues().put("total_inst", projectsPerInstitution.size());
            masterReport.getParameterValues().put("total_countries", countries.size());
            masterReport.getParameterValues().put("total_projects", projects.size());
            this.fillSubreport((SubReport) hm.get("details"), "details");
            this.fillSubreport((SubReport) hm.get("summary"), "summary");
            this.fillSubreport((SubReport) hm.get("institution_types"), "institution_types");
            ExcelReportUtil.createXLSX(masterReport, os);
            bytesXLSX = os.toByteArray();
            os.close();
        } catch (Exception e) {
            LOG.error("Error generating Institutions " + e.getMessage());
            throw e;
        }
        // Calculate time of generation
        long stopTime = System.currentTimeMillis();
        stopTime = stopTime - startTime;
        LOG.info("Downloaded successfully: " + this.getFileName() + ". User: "
                + this.getCurrentUser().getComposedCompleteName() + ". CRP: " + this.getLoggedCrp().getAcronym()
                + ". Cycle: " + this.getSelectedCycle() + ". Time to generate: " + stopTime + "ms.");
        return SUCCESS;
    }

    private void fillSubreport(SubReport subReport, String query) {
        CompoundDataFactory cdf = CompoundDataFactory.normalize(subReport.getDataFactory());
        TableDataFactory sdf = (TableDataFactory) cdf.getDataFactoryForQuery(query);
        TypedTableModel model = null;
        switch (query) {
        case "details":
            model = this.getDetailsTableModel();
            break;
        case "summary":
            model = this.getSummaryTableModel();
            break;
        case "institution_types":
            model = this.getInstitutionTypesTableModel();
            break;
        }
        sdf.addTable(query, model);
        subReport.setDataFactory(cdf);
    }

    @Override
    public int getContentLength() {
        return bytesXLSX.length;
    }

    @Override
    public String getContentType() {
        return "application/xlsx";
    }

    private TypedTableModel getDetailsTableModel() {
        TypedTableModel model = new TypedTableModel(
                new String[] { "ins_name", "ins_acr", "web_site", "ins_type", "country", "Projects",
                        "projectCountry" },
                new Class[] { String.class, String.class, String.class, String.class, String.class, String.class,
                        String.class },
                0);

        Map<Institution, Set<Project>> result = projectsPerInstitution.entrySet().stream()
                .sorted((s1, s2) -> s1.getKey().getName().compareTo(s2.getKey().getName()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new));

        for (Institution institution : result.keySet()) {
            String insName = "", insAcr = "", webSite = "", insType = "", country = "", projects = "",
                    projectCountry = "";
            insName = institution.getName() != null && !institution.getName().trim().isEmpty()
                    ? institution.getName()
                    : null;
            insAcr = institution.getAcronym() != null && !institution.getAcronym().trim().isEmpty()
                    ? institution.getAcronym()
                    : null;
            webSite = institution.getWebsiteLink() != null && !institution.getWebsiteLink().trim().isEmpty()
                    ? institution.getWebsiteLink()
                    : null;
            insType = institution.getInstitutionType().getName() != null
                    && !institution.getInstitutionType().getName().trim().isEmpty()
                            ? institution.getInstitutionType().getName()
                            : null;
            List<InstitutionLocation> locations = institution.getInstitutionsLocations().stream()
                    .filter(l -> l.isActive() && l.isHeadquater()).collect(Collectors.toList());
            if (locations != null && !locations.isEmpty()) {
                country = locations.get(0).getLocElement().getName();
            }
            if (country.isEmpty()) {
                country = null;
            }

            Set<Project> projectSet = projectsPerInstitution.get(institution);
            if (projectSet != null && !projectSet.isEmpty()) {
                List<Project> projectList = projectSet.stream().sorted((p1, p2) -> p1.getId().compareTo(p2.getId()))
                        .collect(Collectors.toList());
                for (Project project : projectList) {
                    if (projects.isEmpty()) {
                        projects += "P" + project.getId();
                    } else {
                        projects += ", P" + project.getId();
                    }
                }
            }
            if (projects.isEmpty()) {
                projects = null;
            }
            Set<LocElement> locationSet = countriesPerInstitution.get(institution);
            if (locationSet != null && !locationSet.isEmpty()) {
                List<LocElement> locationList = locationSet.stream()
                        .sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
                for (LocElement locElement : locationList) {
                    if (projectCountry.isEmpty()) {
                        projectCountry += locElement.getName();
                    } else {
                        projectCountry += ", " + locElement.getName();
                    }
                }
            }
            if (projectCountry.isEmpty()) {
                projectCountry = null;
            }

            model.addRow(new Object[] { insName, insAcr, webSite, insType, country, projects, projectCountry });
        }
        return model;
    }

    @SuppressWarnings("unused")
    private File getFile(String fileName) {
        // Get file from resources folder
        ClassLoader classLoader = this.getClass().getClassLoader();
        File file = new File(classLoader.getResource(fileName).getFile());
        return file;
    }

    @Override
    public String getFileName() {
        StringBuffer fileName = new StringBuffer();
        if (partnerType.equals("All")) {
            fileName.append("ProjectPartnersSummary-");
        } else {
            fileName.append("ProjectLeadingInstitutionsSummary-");
        }
        fileName.append(this.getLoggedCrp().getAcronym() + "-");
        fileName.append(this.getSelectedCycle() + "-");
        fileName.append(this.getSelectedYear() + "_");
        fileName.append(new SimpleDateFormat("yyyyMMdd-HHmm").format(new Date()));
        fileName.append(".xlsx");
        return fileName.toString();
    }

    @Override
    public InputStream getInputStream() {
        if (inputStream == null) {
            inputStream = new ByteArrayInputStream(bytesXLSX);
        }
        return inputStream;
    }

    private TypedTableModel getInstitutionTypesTableModel() {
        TypedTableModel model = new TypedTableModel(new String[] { "count_ins", "name_percentage" },
                new Class[] { Integer.class, String.class }, 0);
        Map<InstitutionType, Set<Institution>> result = institutionsPerType.entrySet().stream()
                .sorted((s1, s2) -> new Integer(s2.getValue().size()).compareTo(new Integer(s1.getValue().size())))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new));
        int totalInstitutions = projectsPerInstitution.size();
        DecimalFormat percentageFormat = new DecimalFormat("##.##%");

        for (InstitutionType institutionType : result.keySet()) {
            String namePercentage = "";
            Integer countIns = null;
            countIns = institutionsPerType.get(institutionType).size();
            namePercentage = institutionType.getName();
            Double percentajeOfTotal = 0.0;
            if (totalInstitutions > 0) {
                percentajeOfTotal = countIns * 100.0 / totalInstitutions;
            } else {
                percentajeOfTotal = 0.0;
            }

            model.addRow(new Object[] { countIns,
                    namePercentage + " - " + percentageFormat.format(round(percentajeOfTotal / 100, 4)) });
        }
        return model;
    }

    private TypedTableModel getMasterTableModel() {
        // Initialization of Model
        TypedTableModel model = new TypedTableModel(new String[] { "date", "center", "showDescription" },
                new Class[] { String.class, String.class, Boolean.class });
        String center = this.getLoggedCrp().getAcronym();

        ZonedDateTime timezone = ZonedDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-d 'at' HH:mm ");
        String zone = timezone.getOffset() + "";
        if (zone.equals("Z")) {
            zone = "+0";
        }
        String date = timezone.format(format) + "(GMT" + zone + ")";
        model.addRow(new Object[] { date, center, this.hasSpecificities(APConstants.CRP_REPORTS_DESCRIPTION) });
        return model;
    }

    private TypedTableModel getSummaryTableModel() {
        TypedTableModel model = new TypedTableModel(new String[] { "ins_name", "acronym", "projects" },
                new Class[] { String.class, String.class, Integer.class }, 0);
        Map<Institution, Set<Project>> result = projectsPerInstitution.entrySet().stream()
                .sorted((i1, i2) -> new Integer(i2.getValue().size()).compareTo(new Integer(i1.getValue().size())))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new));
        int count = 0;
        for (Institution institution : result.keySet()) {
            if (count > 9) {
                break;
            }
            String insName = "", insAcr = "";
            Integer projects = null;
            insName = institution.getName();
            insAcr = institution.getAcronym();
            projects = projectsPerInstitution.get(institution).size();
            model.addRow(new Object[] { insName, insAcr, projects });
            count++;
        }
        return model;
    }

    @Override
    public void prepare() {
        try {
            Map<String, Parameter> parameters = this.getParameters();
            partnerType = StringUtils.trim(parameters.get(APConstants.SUMMARY_PARTNER_TYPE).getMultipleValues()[0]);
        } catch (Exception e) {
            LOG.warn("Failed to get " + APConstants.SUMMARY_PARTNER_TYPE
                    + " parameter. Parameter will be set as All. Exception: " + e.getMessage());
            partnerType = "All";
        }
        this.setGeneralParameters();
        // Calculate time to generate report
        startTime = System.currentTimeMillis();
        LOG.info("Start report download: " + this.getFileName() + ". User: "
                + this.getCurrentUser().getComposedCompleteName() + ". CRP: " + this.getLoggedCrp().getAcronym()
                + ". Cycle: " + this.getSelectedCycle());
    }

}