/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero 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/>.
*/
package org.kuali.kfs.module.ar.web.struts;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.kuali.kfs.module.ar.ArConstants;
import org.kuali.kfs.module.ar.ArPropertyConstants;
import org.kuali.kfs.module.ar.businessobject.ContractsGrantsSuspendedInvoiceSummaryReport;
import org.kuali.kfs.module.ar.report.ContractsGrantsReportDataHolder;
import org.kuali.kfs.module.ar.report.ContractsGrantsReportSearchCriteriaDataHolder;
import org.kuali.kfs.module.ar.report.service.ContractsGrantsReportDataBuilderService;
import org.kuali.kfs.module.ar.report.service.ContractsGrantsReportHelperService;
import org.kuali.kfs.sys.DynamicCollectionComparator;
import org.kuali.kfs.sys.DynamicCollectionComparator.SortOrder;
import org.kuali.kfs.sys.KFSConstants.ReportGeneration;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.kns.lookup.Lookupable;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.kns.util.WebUtils;
import org.kuali.rice.kns.web.struts.action.KualiLookupAction;
import org.kuali.rice.kns.web.struts.form.LookupForm;
import org.kuali.rice.kns.web.ui.ResultRow;
import org.kuali.rice.krad.bo.BusinessObject;
import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.KRADConstants;
import org.kuali.rice.krad.util.ObjectUtils;
/**
* This Action Class defines all the core methods for Contracts & Grants Lookup.
*/
public abstract class ContractsGrantsReportLookupAction extends KualiLookupAction {
private static volatile ContractsGrantsReportHelperService contractsGrantsReportHelperService;
private static volatile DataDictionaryService dataDictionaryService;
/**
* @see org.kuali.rice.kns.web.struts.action.KualiLookupAction#execute(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
// d-16544-s is field name from display table tab.
String sortIndexParameter = request.getParameter("d-16544-s");
if (sortIndexParameter != null) {
// to store how many times user clicks sort links
Integer clickedSession = ObjectUtils.isNull(GlobalVariables.getUserSession().retrieveObject(ArConstants.NUM_SORT_INDEX_CLICK_SESSION_KEY)) ? new Integer(1) : (Integer) GlobalVariables.getUserSession().retrieveObject(ArConstants.NUM_SORT_INDEX_CLICK_SESSION_KEY);
if (ObjectUtils.isNotNull(GlobalVariables.getUserSession().retrieveObject(ArConstants.SORT_INDEX_SESSION_KEY)) && GlobalVariables.getUserSession().retrieveObject(ArConstants.SORT_INDEX_SESSION_KEY).toString().equals(sortIndexParameter)) {
GlobalVariables.getUserSession().addObject(ArConstants.NUM_SORT_INDEX_CLICK_SESSION_KEY, new Integer(clickedSession + 1));
}
GlobalVariables.getUserSession().addObject(ArConstants.SORT_INDEX_SESSION_KEY, sortIndexParameter);
}
if (form instanceof ContractsGrantsReportLookupForm) {
((ContractsGrantsReportLookupForm)form).setDisplayActionsForRow(shouldDisplayActionsForRow());
}
return super.execute(mapping, form, request, response);
}
/**
* This method implements the print functionality - basically, pdf generation - for children reports
*
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public ActionForward print(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
LookupForm lookupForm = (LookupForm) form;
List<ContractsGrantsSuspendedInvoiceSummaryReport> displayList = lookupReportValues(lookupForm, request, validateLookupFields());
final String sortPropertyName = sortReportValues(displayList);
// build report
ContractsGrantsReportDataBuilderService reportDataBuilderService = getContractsGrantsReportDataBuilderService();
ContractsGrantsReportDataHolder cgSuspendedInvoiceSummaryReportDataHolder = reportDataBuilderService.buildReportDataHolder(displayList, sortPropertyName);
// build search criteria for report
buildSearchCriteriaReportSection(cgSuspendedInvoiceSummaryReportDataHolder.getSearchCriteria(), lookupForm.getFieldsForLookup());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String reportFileName = generateReportPdf(cgSuspendedInvoiceSummaryReportDataHolder, baos);
WebUtils.saveMimeOutputStreamAsFile(response, ReportGeneration.PDF_MIME_TYPE, baos, reportFileName + ReportGeneration.PDF_FILE_EXTENSION);
return null;
}
/**
* Determines whether or not to validate the lookup fields before carrying out the looup
* @return true to validate the lookup fields, false otherwise
*/
protected boolean validateLookupFields() {
return true;
}
/**
* When the report prints out, it lists the fields that were used for the search criteria query; this builds that
* @param searchCriteria the reporty versions of the fields
* @param fieldsForLookup the fields from the lookup itself
*/
protected void buildSearchCriteriaReportSection(List<ContractsGrantsReportSearchCriteriaDataHolder> searchCriteria, Map fieldsForLookup) {
for (Object field : fieldsForLookup.keySet()) {
String fieldString = (ObjectUtils.isNull(field)) ? "" : field.toString();
String valueString = (ObjectUtils.isNull(fieldsForLookup.get(field))) ? "" : fieldsForLookup.get(field).toString();
if (StringUtils.isNotBlank(fieldString) && StringUtils.isNotBlank(valueString) &&
!ArConstants.ReportsConstants.reportSearchCriteriaExceptionList.contains(fieldString) &&
!fieldString.startsWith(ArPropertyConstants.RANGE_LOWER_BOUND_KEY_PREFIX)) {
final ControlDefinition controldef = getDataDictionaryService().getAttributeControlDefinition(getPrintSearchCriteriaClass(), fieldString);
if (controldef != null && !controldef.isHidden()) {
ContractsGrantsReportSearchCriteriaDataHolder criteriaData = generateDataHolder(fieldString, valueString);
searchCriteria.add(criteriaData);
}
}
}
}
/**
* Generates a single field for the buildReportForSearchCriteria
* @param fieldString the name of the field
* @param valueString the value from the lookup
* @return the generated ContractsGrantsReportSearchCriteriaDataHolder
*/
protected ContractsGrantsReportSearchCriteriaDataHolder generateDataHolder(String fieldString, String valueString) {
ContractsGrantsReportSearchCriteriaDataHolder criteriaData = new ContractsGrantsReportSearchCriteriaDataHolder();
String label = getDataDictionaryService().getAttributeLabel(getPrintSearchCriteriaClass(), fieldString);
criteriaData.setSearchFieldLabel(label);
criteriaData.setSearchFieldValue(valueString);
return criteriaData;
}
/**
* @param displayList
* @param sortPropertyName
*/
protected void sortReport(List displayList, String sortPropertyName) {
Integer numSortIndexClick = (ObjectUtils.isNull(GlobalVariables.getUserSession().retrieveObject(ArConstants.NUM_SORT_INDEX_CLICK_SESSION_KEY))) ? 1 : new Integer(GlobalVariables.getUserSession().retrieveObject(ArConstants.NUM_SORT_INDEX_CLICK_SESSION_KEY).toString());
if (((numSortIndexClick) % 2) == 0) {
DynamicCollectionComparator.sort(displayList, SortOrder.DESC, sortPropertyName);
}
else {
DynamicCollectionComparator.sort(displayList, SortOrder.ASC, sortPropertyName);
}
}
/**
* Looks up the values for the report
* @param form the LookupForm to help us with the lookup
* @param request the request to get the search method from
* @param performValidate if true, will perform validation on the values before performing the lookup
* @return a List of the report values for the given action
* @throws Exception thrown if findMethodToCall gets ticked
*/
protected <B extends BusinessObject> List<B> lookupReportValues(LookupForm form, HttpServletRequest request, boolean performValidate) throws Exception {
String methodToCall = findMethodToCall(form, request);
if (methodToCall.equalsIgnoreCase(KRADConstants.SEARCH_METHOD)) {
GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_METHOD);
}
Lookupable kualiLookupable = form.getLookupable();
if (ObjectUtils.isNull(kualiLookupable)) {
throw new RuntimeException("Lookupable is null.");
}
if (performValidate) {
kualiLookupable.validateSearchParameters(form.getFields());
}
List<B> displayList = new ArrayList<B>();
List<ResultRow> resultTable = new ArrayList<ResultRow>();
// this is for 200 limit. turn it off for report.
boolean bounded = false;
displayList = (List<B>) kualiLookupable.performLookup(form, resultTable, bounded);
return displayList;
}
/**
* Sorts the values for a report
* @param displayList the List of report values to sort (in List)
* @param sortFieldName the field name that the List should be sorted by
* @return the name of the property to be sorted against
*/
protected <B extends BusinessObject> String sortReportValues(List<B> displayList) {
Object sortIndexObject = GlobalVariables.getUserSession().retrieveObject(ArConstants.SORT_INDEX_SESSION_KEY);
// set default sort index as 0 (Proposal Number)
if (ObjectUtils.isNull(sortIndexObject)) {
sortIndexObject = "0";
}
// get sort property
String sortPropertyName = getContractsGrantsReportHelperService().getFieldNameForSorting(Integer.parseInt(sortIndexObject.toString()), getSortFieldName());
// sort list
sortReport(displayList, sortPropertyName);
return sortPropertyName;
}
/**
* @return the default value that sorts on the pdf generation should sort on
*/
protected abstract String getSortFieldName();
/**
* Generates the report PDF
* @param reportDataHolder the information to report on
* @param reportInfo information about where to store the report and formatting
* @param baos the stream to write the PDF to
* @return the file name of the generated report
*/
protected String generateReportPdf(ContractsGrantsReportDataHolder reportDataHolder, ByteArrayOutputStream baos) {
final String reportFileName = getContractsGrantsReportHelperService().generateReport(reportDataHolder, getContractsGrantsReportDataBuilderService().getReportInfo(), baos);
return reportFileName;
}
/**
* @return the name of the bean which helps the child Action build the reports associated
*/
public abstract String getReportBuilderServiceBeanName();
/**
* @return the class used during pdf generation to build search criteria against
*/
public abstract Class<? extends BusinessObject> getPrintSearchCriteriaClass();
/**
* Always returns false, as most reports do not have actions associated
* @return true if the form should display actions per row, false otherwise
*/
public boolean shouldDisplayActionsForRow() {
return false;
}
/**
* Generates the report title for generated reports. If null, a report title will not be set
* @param lookupForm a form with information which may be used in the title
* @return String the title for the report
*/
public abstract String generateReportTitle(LookupForm lookupForm);
public ContractsGrantsReportHelperService getContractsGrantsReportHelperService() {
if (contractsGrantsReportHelperService == null) {
contractsGrantsReportHelperService = SpringContext.getBean(ContractsGrantsReportHelperService.class);
}
return contractsGrantsReportHelperService;
}
/**
* Returns the ContractsGrantsReportDataBuilderService which builds reports out of the given detailClass
* @param detailClass the detailClass to find a builder service for
* @return the ContractsGrantsReportDataBuilderService
*/
public ContractsGrantsReportDataBuilderService getContractsGrantsReportDataBuilderService() {
return SpringContext.getBean(ContractsGrantsReportDataBuilderService.class, getReportBuilderServiceBeanName());
}
public DataDictionaryService getDataDictionaryService() {
if (dataDictionaryService == null) {
dataDictionaryService = SpringContext.getBean(DataDictionaryService.class);
}
return dataDictionaryService;
}
}