/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.reports.pentaho.service;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.mifos.application.admin.servicefacade.BatchjobsDto;
import org.mifos.application.admin.servicefacade.BatchjobsServiceFacade;
import org.mifos.application.admin.servicefacade.RolesPermissionServiceFacade;
import org.mifos.application.admin.servicefacade.ViewOrganizationSettingsServiceFacade;
import org.mifos.core.MifosRuntimeException;
import org.mifos.framework.exceptions.PersistenceException;
import org.mifos.framework.util.ConfigurationLocator;
import org.mifos.reports.admindocuments.persistence.LegacyAdminDocumentDao;
import org.mifos.reports.business.ReportsBO;
import org.mifos.reports.business.ReportsJasperMap;
import org.mifos.reports.pentaho.PentahoReport;
import org.mifos.reports.pentaho.PentahoReportsServiceFacade;
import org.mifos.reports.pentaho.PentahoValidationError;
import org.mifos.reports.pentaho.params.AbstractPentahoParameter;
import org.mifos.reports.pentaho.params.PentahoInputParameter;
import org.mifos.reports.pentaho.util.PentahoOutputType;
import org.mifos.reports.pentaho.util.PentahoParamParser;
import org.mifos.reports.pentaho.util.PentahoReportLocator;
import org.mifos.reports.pentaho.util.ReflectionException;
import org.mifos.reports.persistence.ReportsPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
import org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.PdfReportUtil;
import org.pentaho.reporting.engine.classic.core.modules.output.table.csv.CSVReportUtil;
import org.pentaho.reporting.engine.classic.core.modules.output.table.html.HtmlReportUtil;
import org.pentaho.reporting.engine.classic.core.modules.output.table.rtf.RTFReportUtil;
import org.pentaho.reporting.engine.classic.core.modules.output.table.xls.ExcelReportUtil;
import org.pentaho.reporting.engine.classic.core.modules.output.table.xml.XmlTableReportUtil;
import org.pentaho.reporting.engine.classic.core.parameters.DefaultParameterContext;
import org.pentaho.reporting.engine.classic.core.parameters.ParameterContext;
import org.pentaho.reporting.engine.classic.core.parameters.ParameterDefinitionEntry;
import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterDefinition;
import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterValidator;
import org.pentaho.reporting.engine.classic.core.parameters.ValidationMessage;
import org.pentaho.reporting.engine.classic.core.parameters.ValidationResult;
import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
public class PentahoReportsServiceImpl implements PentahoReportsServiceFacade {
private final static Logger logger = LoggerFactory.getLogger(PentahoReportsServiceImpl.class);
private final ReportsPersistence reportsPersistence = new ReportsPersistence();
private PentahoParamParser paramParser = new PentahoParamParser();
private RolesPermissionServiceFacade rolesPermissionService;
private LegacyAdminDocumentDao legacyAdminDocumentDao;
private ViewOrganizationSettingsServiceFacade viewOrganizationSettingsServiceFacade;
@Autowired
private BatchjobsServiceFacade batchjobsServiceFacade;
@Autowired
public PentahoReportsServiceImpl(RolesPermissionServiceFacade rolesPermissionService,
LegacyAdminDocumentDao legacyAdminDocumentDao,
ViewOrganizationSettingsServiceFacade viewOrganizationSettingsServiceFacade) {
this.rolesPermissionService = rolesPermissionService;
this.legacyAdminDocumentDao = legacyAdminDocumentDao;
this.viewOrganizationSettingsServiceFacade = viewOrganizationSettingsServiceFacade;
}
@Override
public PentahoReport getReport(Integer reportId, Integer outputTypeId, Map<String, AbstractPentahoParameter> params) {
ByteArrayOutputStream baos = null;
if (!checkAccessToReport(reportId)) {
throw new AccessDeniedException("Access denied");
}
try {
String reportFileName = getReportFilename(reportId);
// load report definition
ResourceManager manager = new ResourceManager();
manager.registerDefaults();
URL url = PentahoReportLocator.getURLForReport(reportFileName);
Resource res = manager.createDirectly(url, MasterReport.class);
MasterReport report = (MasterReport) res.getResource();
PentahoReport result = new PentahoReport();
List<PentahoValidationError> errors = new ArrayList<PentahoValidationError>();
try {
addParametersToReport(report, params);
validate(report, errors);
} catch (ReflectionException ex) {
errors.add(new PentahoValidationError(ex.getMessage()));
}
result.setErrors(errors);
if (errors.isEmpty()) {
baos = new ByteArrayOutputStream();
PentahoOutputType outputType = PentahoOutputType.findById(outputTypeId);
switch (outputType) {
case XLS:
ExcelReportUtil.createXLS(report, baos);
break;
case RTF:
RTFReportUtil.createRTF(report, baos);
break;
case HTML:
HtmlReportUtil.createStreamHTML(report, baos);
break;
case CSV:
CSVReportUtil.createCSV(report, baos, "UTF-8");
break;
case XML:
XmlTableReportUtil.createFlowXML(report, baos);
break;
default: // PDF
PdfReportUtil.createPDF(report, baos);
break;
}
result.setContentType(outputType.getContentType());
result.setFileExtension(outputType.getFileExtension());
result.setName(getReportName(reportId));
result.setContent(baos.toByteArray());
}
return result;
} catch (Exception e) {
throw new MifosRuntimeException(e);
} finally {
closeStream(baos);
}
}
@Override
public PentahoReport getAdminReport(Integer adminReportId, Integer outputTypeId, Map<String, AbstractPentahoParameter> params) {
ByteArrayOutputStream baos = null;
try{
// load report definition
ResourceManager manager = new ResourceManager();
manager.registerDefaults();
String reportName = legacyAdminDocumentDao.getAdminDocumentById(adminReportId.shortValue())
.getAdminDocumentName();
String filename = legacyAdminDocumentDao.getAdminDocumentById(adminReportId.shortValue())
.getAdminDocumentIdentifier();
File file = new File(viewOrganizationSettingsServiceFacade.getAdminDocumentStorageDirectory(), filename);
StringBuilder path = new StringBuilder("file:");
path.append(file.getAbsolutePath());
URL url = new URL(path.toString());
Resource res = manager.createDirectly(url, MasterReport.class);
MasterReport report = (MasterReport) res.getResource();
PentahoReport result = new PentahoReport();
List<PentahoValidationError> errors = new ArrayList<PentahoValidationError>();
try {
addParametersToReport(report, params);
validate(report, errors);
} catch (ReflectionException ex) {
errors.add(new PentahoValidationError(ex.getMessage()));
}
result.setErrors(errors);
if (errors.isEmpty()) {
baos = new ByteArrayOutputStream();
PentahoOutputType outputType = PentahoOutputType.findById(outputTypeId);
switch (outputType) {
case XLS:
ExcelReportUtil.createXLS(report, baos);
break;
case RTF:
RTFReportUtil.createRTF(report, baos);
break;
case HTML:
HtmlReportUtil.createStreamHTML(report, baos);
break;
case CSV:
CSVReportUtil.createCSV(report, baos, "UTF-8");
break;
case XML:
XmlTableReportUtil.createFlowXML(report, baos);
break;
default: // PDF
PdfReportUtil.createPDF(report, baos);
break;
}
result.setContentType(outputType.getContentType());
result.setFileExtension(outputType.getFileExtension());
result.setName(reportName);
result.setContent(baos.toByteArray());
}
return result;
} catch (Exception e) {
throw new MifosRuntimeException(e);
} finally {
closeStream(baos);
}
}
@PostConstruct
public void init() {
ClassicEngineBoot.getInstance().start();
}
private void closeStream(OutputStream stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
logger.error("Error while closing stream", e);
}
}
}
@Override
public String getReportName(Integer reportId) {
String name = null;
if (reportId != null) {
name = this.reportsPersistence.getReport((short) reportId.intValue()).getReportName();
}
return name;
}
@Override
public String getAdminReportFileName(Integer adminReportId) {
try {
return this.legacyAdminDocumentDao.getAdminDocumentById(adminReportId.shortValue())
.getAdminDocumentIdentifier();
} catch (PersistenceException e) {
throw new MifosRuntimeException(e);
}
}
@Override
public Map<String, String> getReportOutputTypes() {
Map<String, String> outputTypes = new HashMap<String, String>();
for (PentahoOutputType outputType : PentahoOutputType.values()) {
outputTypes.put(String.valueOf(outputType.getId()), outputType.getDisplayName());
}
return outputTypes;
}
@Override
public List<AbstractPentahoParameter> getParametersForReport(Integer reportId, HttpServletRequest request, Map<String, AbstractPentahoParameter> selectedValues, boolean update) {
if (!checkAccessToReport(reportId)) {
throw new AccessDeniedException("Access denied");
}
String reportName = getReportFilename(reportId);
MasterReport report = loadReport(reportName);
return paramParser.parseReportParams(report, request, selectedValues, update);
}
private MasterReport loadReport(String reportName) {
ResourceManager manager = new ResourceManager();
manager.registerDefaults();
URL url = PentahoReportLocator.getURLForReport(reportName);
try {
Resource res = manager.createDirectly(url, MasterReport.class);
MasterReport report = (MasterReport) res.getResource();
return report;
} catch (Exception e) {
throw new MifosRuntimeException(e);
}
}
private void addParametersToReport(MasterReport report, Map<String, AbstractPentahoParameter> params)
throws ReflectionException, IOException {
ReportParameterValues rptParamValues = report.getParameterValues();
ReportParameterDefinition paramsDefinition = report.getParameterDefinition();
params.put("mifosLogoPath", getLogoParameterForReport());
for (ParameterDefinitionEntry paramDefEntry : paramsDefinition.getParameterDefinitions()) {
String paramName = paramDefEntry.getName();
AbstractPentahoParameter parameter = params.get(paramName);
if (parameter != null) {
Object val = this.paramParser.parseParamValue(parameter, paramDefEntry);
if (val != null && (!val.getClass().isArray() || Array.getLength(val) > 0)) {
rptParamValues.put(paramName, val);
}
}
}
}
private PentahoInputParameter getLogoParameterForReport() throws IOException {
ConfigurationLocator configurationLocator = new ConfigurationLocator();
org.springframework.core.io.Resource logo = configurationLocator.getUploadedMifosLogo();
PentahoInputParameter logoParameter = new PentahoInputParameter();
logoParameter.setParamName("mifosLogoPath");
logoParameter.setLabelName("mifosLogoPath");
String logoPath = logo.getFile().getAbsolutePath();
logoParameter.setValue(logoPath);
return logoParameter;
}
private String getReportFilename(Integer reportId) {
try {
List<ReportsJasperMap> reports = this.reportsPersistence.findJasperOfReportId(reportId);
if (reports.isEmpty()) {
throw new MifosRuntimeException("Report doesn't contain a report file");
} else {
return reports.get(0).getReportJasper();
}
} catch (PersistenceException ex) {
logger.error("Reports persistence exception", ex);
throw new MifosRuntimeException(ex);
}
}
private void validate(MasterReport report, List<PentahoValidationError> errors) throws ReportProcessingException {
ReportParameterDefinition paramDefinition = report.getParameterDefinition();
ReportParameterValidator validator = paramDefinition.getValidator();
ParameterContext paramContext = new DefaultParameterContext(report);
ValidationResult validationResult = validator.validate(null, paramDefinition, paramContext);
for (ValidationMessage msg : validationResult.getErrors()) {
PentahoValidationError error = new PentahoValidationError(msg.getMessage());
errors.add(error);
}
String[] properties = validationResult.getProperties();
for (String prop : properties) {
for (ValidationMessage msg : validationResult.getErrors(prop)) {
PentahoValidationError error = new PentahoValidationError(prop, msg.getMessage());
errors.add(error);
}
}
}
@Override
public boolean checkAccessToReport(Integer reportId) {
ReportsBO report = this.reportsPersistence.getReport(reportId.shortValue());
boolean result = false;
if (report != null) {
Short activityID = report.getActivityId();
try {
result = this.rolesPermissionService.hasUserAccessForActivity(activityID);
} catch (Exception ex) {
result = false;
}
}
return result;
}
@Override
@PreAuthorize("isFullyAuthenticated()")
public Date getEtlLastUpdateDate(HttpServletRequest request) {
ServletContext context = request.getSession().getServletContext();
Date lastSucessfulRunEtl = null;
try {
List<BatchjobsDto> batchjobs = batchjobsServiceFacade.getBatchjobs(context);
for ( BatchjobsDto batchjob : batchjobs ) {
if(batchjob.getName().equals("ETLReportDWTaskJob")) {
lastSucessfulRunEtl = batchjob.getLastSuccessfulRun();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return lastSucessfulRunEtl;
}
@Override
public boolean isDW(Integer reportId) {
ReportsBO reports = this.reportsPersistence.getReport(new Short(reportId.toString()));
return reports.getIsDW();
}
}