/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ package ro.nextreports.server.service; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; import java.text.Normalizer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.quartz.JobDetail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import org.springframework.security.access.annotation.Secured; import org.springframework.transaction.annotation.Transactional; import ro.nextreports.engine.ReportRunner; import ro.nextreports.engine.exporter.XlsExporter; import ro.nextreports.engine.exporter.exception.NoDataFoundException; import ro.nextreports.engine.util.ParameterUtil; import ro.nextreports.server.StorageConstants; import ro.nextreports.server.audit.AuditEvent; import ro.nextreports.server.audit.Auditor; import ro.nextreports.server.dao.StorageDao; import ro.nextreports.server.domain.DateRange; import ro.nextreports.server.domain.Entity; import ro.nextreports.server.domain.Report; import ro.nextreports.server.domain.ReportResultEvent; import ro.nextreports.server.domain.ReportRuntime; import ro.nextreports.server.domain.ReportRuntimeTemplate; import ro.nextreports.server.domain.RunReportHistory; import ro.nextreports.server.domain.SchedulerJob; import ro.nextreports.server.exception.FormatNotSupportedException; import ro.nextreports.server.exception.NotFoundException; import ro.nextreports.server.exception.ReportEngineException; import ro.nextreports.server.report.DefaultExportContext; import ro.nextreports.server.report.ExportContext; import ro.nextreports.server.report.ExternalParameter; import ro.nextreports.server.report.ReportConstants; import ro.nextreports.server.report.ReportEngine; import ro.nextreports.server.report.jasper.util.JasperUtil; import ro.nextreports.server.report.next.NextUtil; import ro.nextreports.server.schedule.QuartzJobHandler; import ro.nextreports.server.web.security.SecurityUtil; /** * Created by IntelliJ IDEA. User: mihai.panaitescu Date: Feb 14, 2008 Time: * 10:51:43 AM */ public class DefaultReportService implements ReportService { private static final Logger LOG = LoggerFactory.getLogger(DefaultReportService.class); private StorageDao storageDao; private QuartzJobHandler quartzJobHandler; private Auditor auditor; private HashMap<String, ReportListener> reportListeners = new HashMap<String, ReportListener>(); private Map<String, ReportEngine> reportEngines; @Required public void setStorageDao(StorageDao storageDao) { this.storageDao = storageDao; } @Required public void setQuartzJobHandler(QuartzJobHandler quartzJobHandler) { this.quartzJobHandler = quartzJobHandler; } @Required public void setReportEngines(Map<String, ReportEngine> reportEngines) { this.reportEngines = reportEngines; } @Required public void setAuditor(Auditor auditor) { this.auditor = auditor; } private ReportEngine getReportEngine(Report report) { if (report == null) { return null; } String reportType = report.getType(); if (reportType == null) { return null; } return reportEngines.get(reportType); } public void stopExport(String key, String reportType) { if (reportType == null) { return; } ReportEngine engine = reportEngines.get(reportType); if (engine != null) { engine.stopExport(key); } } public List<String> getSupportedOutputs(Report report) { ReportEngine reportEngine = getReportEngine(report); if (reportEngine == null) { return new ArrayList<String>(); } List<String> supportedOutputs = new ArrayList<String>(); if (reportEngine.supportExcelOutput()) { supportedOutputs.add(ReportConstants.EXCEL_FORMAT); } if (reportEngine.supportExcelXOutput()) { supportedOutputs.add(ReportConstants.EXCEL_XLSX_FORMAT); } if (reportEngine.supportHtmlOutput()) { supportedOutputs.add(ReportConstants.HTML_FORMAT); } if (reportEngine.supportPdfOutput()) { supportedOutputs.add(ReportConstants.PDF_FORMAT); } if (reportEngine.supportRtfOutput()) { supportedOutputs.add(ReportConstants.RTF_FORMAT); } if (reportEngine.supportDocxOutput()) { supportedOutputs.add(ReportConstants.DOCX_FORMAT); } if (reportEngine.supportTsvOutput()) { supportedOutputs.add(ReportConstants.TSV_FORMAT); } if (reportEngine.supportTxtOutput()) { supportedOutputs.add(ReportConstants.TXT_FORMAT); } if (reportEngine.supportXmlOutput()) { supportedOutputs.add(ReportConstants.XML_FORMAT); } if (reportEngine.supportCsvOutput()) { supportedOutputs.add(ReportConstants.CSV_FORMAT); } if (reportEngine.supportETL()) { supportedOutputs.add(ReportConstants.ETL_FORMAT); } if (reportEngine.supportJSONSimpleOutput()) { supportedOutputs.add(ReportConstants.JSON_SIMPLE_FORMAT); } if (reportEngine.supportJSONFullOutput()) { supportedOutputs.add(ReportConstants.JSON_FULL_FORMAT); } return supportedOutputs; } @Transactional(readOnly = true) public byte[] reportTo(Report report, ReportRuntime reportRuntime, String creator, String key) throws ReportEngineException, FormatNotSupportedException, NoDataFoundException, InterruptedException { try { report = (Report) storageDao.getEntityById(report.getId()); } catch (Exception e) { throw new ReportEngineException(e); } ReportEngine engine = getReportEngine(report); if (engine == null) { throw new ReportEngineException("Report engine not found for type"); } String outputType = reportRuntime.getOutputType(); if (!getSupportedOutputs(report).contains(outputType)) { throw new FormatNotSupportedException("Format not supported"); } // create the context of the export ExportContext exportContext = new DefaultExportContext(); exportContext.setId(report.getId()); exportContext.setCreator(creator); exportContext.setReportDataSource(report.getDataSource()); exportContext.setServerReportName(report.getName()); exportContext.setReportContent(report.getContent()); if (report.getType().equals(ReportConstants.JASPER)) { reportRuntime.setParametersValues( JasperUtil.updateJasperParameterValues(report, reportRuntime.getParametersValues()), reportRuntime.getHistoryParametersDisplayNames()); } exportContext.setReportParameterValues(reportRuntime.getParametersValues()); exportContext.setKey(key); exportContext.setLayoutType(reportRuntime.getLayoutType()); exportContext.setHeaderPerPage(reportRuntime.isHeaderPerPage()); // export try { byte[] result = null; if (ReportConstants.CSV_FORMAT.equals(outputType)) { result = engine.exportReportToCsv(exportContext); } else if (ReportConstants.EXCEL_FORMAT.equals(outputType)) { result = engine.exportReportToExcel(exportContext); } else if (ReportConstants.EXCEL_XLSX_FORMAT.equals(outputType)) { result = engine.exportReportToExcelX(exportContext); } else if (ReportConstants.HTML_FORMAT.equals(outputType)) { result = engine.exportReportToHtml(exportContext); } else if (ReportConstants.PDF_FORMAT.equals(outputType)) { result = engine.exportReportToPdf(exportContext); } else if (ReportConstants.RTF_FORMAT.equals(outputType)) { result = engine.exportReportToRtf(exportContext); } else if (ReportConstants.DOCX_FORMAT.equals(outputType)) { result = engine.exportReportToDocx(exportContext); } else if (ReportConstants.TSV_FORMAT.equals(outputType)) { result = engine.exportReportToTsv(exportContext); } else if (ReportConstants.TXT_FORMAT.equals(outputType)) { result = engine.exportReportToTxt(exportContext); } else if (ReportConstants.XML_FORMAT.equals(outputType)) { result = engine.exportReportToXml(exportContext); } else if (ReportConstants.TXT_FORMAT.equals(outputType)) { result = engine.exportReportToTxt(exportContext); } else if (ReportConstants.ETL_FORMAT.equals(outputType)) { engine.exportReportToEtl(exportContext); result = null; } else if (ReportConstants.JSON_SIMPLE_FORMAT.equals(outputType)) { result = engine.exportReportToJSonSimple(exportContext); } else if (ReportConstants.JSON_FULL_FORMAT.equals(outputType)) { result = engine.exportReportToJSonFull(exportContext); } // parameters values may be computed at runtime so put them in // reportRuntime to have them for history reportRuntime.updateDynamicParameterValues(exportContext.getReportParameterValues()); return result; } catch (NoDataFoundException ex) { // parameters values may be computed at runtime so put them in // reportRuntime to have them for history reportRuntime.updateDynamicParameterValues(exportContext.getReportParameterValues()); throw ex; } } @Transactional(readOnly = true) public String[] reportToURL(Report report, ReportRuntime reportRuntime, String creator, String key) throws ReportEngineException, FormatNotSupportedException, NoDataFoundException, InterruptedException { LOG.debug("Run report : " + report.getPath()); byte[] bytes = reportTo(report, reportRuntime, creator, key); if (bytes == null) { return null; } StringBuffer sb = new StringBuffer(100); sb.append(storageDao.getSettings().getReportsHome()); sb.append('/'); File dir = new File(sb.toString()); dir.mkdirs(); String reportFileName = getReportFileName(report, key, reportRuntime.getOutputType()); sb.append(reportFileName); String reportFile = sb.toString(); FileOutputStream fos = null; try { fos = new FileOutputStream(reportFile); fos.write(bytes); } catch (IOException e) { e.printStackTrace(); LOG.error(e.getMessage(), e); } finally { if (fos != null) { try { fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } } // excel metadata if (ReportRunner.EXCEL_FORMAT.equals(reportRuntime.getOutputType())) { XlsExporter.createSummaryInformation(reportFile, getBaseReportFileName(report)); } String url = getReportURL(reportFileName); System.out.println("url = " + url); String[] result = new String[2]; result[0] = reportFileName; result[1] = url; return result; } @Transactional(readOnly = true) public void runReport(SchedulerJob schedulerJob) { try { quartzJobHandler.addJob(schedulerJob); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Transactional(readOnly = true) public void runMonitorReport(JobDetail jobDetail) { try { quartzJobHandler.runMonitorJob(jobDetail); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private String getBaseReportFileName(Report report) { // get last token after '/' character String reportName = report.getName(); int pos = reportName.lastIndexOf('/'); if (pos != -1) { reportName = reportName.substring(pos + 1); } return reportName; } private String getReportFileName(Report report, String key, String format) { StringBuffer buffer = new StringBuffer(100); buffer.append(encodeFileName(getBaseReportFileName(report))); buffer.append("_"); buffer.append(System.currentTimeMillis()); buffer.append(key); buffer.append('.'); buffer.append(getReportFileExtension(report, format)); return buffer.toString(); } private String getReportFileExtension(Report report, String format) { if (ReportConstants.CSV_FORMAT.equals(format)) { return "csv"; } else if (ReportConstants.EXCEL_FORMAT.equals(format)) { return "xls"; } else if (ReportConstants.EXCEL_XLSX_FORMAT.equals(format)) { if (NextUtil.hasMacroTemplate(storageDao.getSettings(), report)) { return "xlsm"; } else { return "xlsx"; } } else if (ReportConstants.HTML_FORMAT.equals(format)) { return "html"; } else if (ReportConstants.PDF_FORMAT.equals(format)) { return "pdf"; } else if (ReportConstants.RTF_FORMAT.equals(format)) { return "rtf"; } else if (ReportConstants.DOCX_FORMAT.equals(format)) { return "docx"; } else if (ReportConstants.TSV_FORMAT.equals(format)) { return "tsv"; } else if (ReportConstants.TXT_FORMAT.equals(format)) { return "txt"; } else if (ReportConstants.HTML_FORMAT.equals(format)) { return "html"; } else if (ReportConstants.XML_FORMAT.equals(format)) { return "xml"; } else if (ReportConstants.JSON_SIMPLE_FORMAT.equals(format)) { return "json"; } else if (ReportConstants.JSON_FULL_FORMAT.equals(format)) { return "json"; } else { return "rep"; } } // This method is used when we save the report and when we create the URL // link // The link must not contain strange characters in order to open the report // file inside browser // // First we normalize the string (all letters with accents will be replaced // with their corresponding without accents) // All group of spaces are replaced with - // All characters different from a standard set are deleted private String encodeFileName(String fileName) { String result = Normalizer.normalize(fileName, Normalizer.Form.NFD).replaceAll("\\s+", "-") .replaceAll("[^A-Za-z0-9_\\-\\.]", ""); if (result.isEmpty()) { result = "report"; } return result; } @Transactional(readOnly = true) public String getReportURL(String reportFileName) { if (ReportConstants.ETL_FORMAT.equals(reportFileName)) { // not exactly a url, but shown inside RuntimeHistoryPanel return reportFileName; } String encodedString = null; try { StringBuffer buffer = new StringBuffer(50); buffer.append(storageDao.getSettings().getReportsUrl()); buffer.append('/'); reportFileName = encodeFileName(reportFileName); buffer.append(reportFileName); encodedString = buffer.toString(); } catch (Exception e) { // should not happen for "UTF-8" e.printStackTrace(); LOG.error(e.getMessage(), e); } return encodedString; } @Transactional(readOnly = true) public Map<String, Serializable> getReportUserParameters(Report report, List<ExternalParameter> externalParameters) throws Exception { report = (Report) storageDao.getEntity(report.getPath()); ReportEngine engine = getReportEngine(report); if (engine == null) { throw new ReportEngineException("Report engine not found for type"); } return engine.getReportUserParameters(report, externalParameters); } @Transactional(readOnly = true) public Map<String, Serializable> getReportUserParametersForEdit(Report report) throws Exception { report = (Report) storageDao.getEntity(report.getPath()); ReportEngine engine = getReportEngine(report); if (engine == null) { throw new ReportEngineException("Report engine not found for type"); } return engine.getReportUserParametersForEdit(report); } @Transactional public void restoreReportVersion(String path, String versionName) throws NotFoundException { storageDao.restoreVersion(path, versionName); storageDao.getEntitiesCache().remove(storageDao.getEntity(path).getId()); AuditEvent auditEvent = new AuditEvent("Restore report version"); auditEvent.getContext().put("PATH", path); auditEvent.getContext().put("VERSION_NAME", versionName); auditor.logEvent(auditEvent); } @Transactional public void clearReportFiles(Report report) throws Exception { ReportEngine engine = getReportEngine(report); if (engine == null) { throw new ReportEngineException("Report engine not found for type"); } engine.clearReportFiles(report); } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<RunReportHistory> getRunHistory() { return storageDao.getRunHistory(); } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<RunReportHistory> getRunHistory(String reportPath) throws NotFoundException { return storageDao.getRunHistory(reportPath); } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<RunReportHistory> getRunHistoryForRange(String reportPath, DateRange range) throws NotFoundException { return storageDao.getRunHistoryForRange(reportPath, range); } @Transactional public long deleteRunHistoryForRange(String reportPath, DateRange range, boolean exportToLog) throws NotFoundException { return storageDao.deleteRunHistoryForRange(reportPath, range, exportToLog); } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<ReportRuntimeTemplate> getReportTemplates(String reportPath) throws NotFoundException { return storageDao.getReportTemplates(reportPath); } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<ReportRuntimeTemplate> getReportTemplatesById(String reportId) throws NotFoundException { return storageDao.getReportTemplatesById(reportId); } @Transactional(readOnly = true) public List<String> getImages(Report report) { ReportEngine engine = getReportEngine(report); return engine.getImages(report); } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<Report> getTableReports() throws NotFoundException { List<Report> reports = new ArrayList<Report>(); Entity[] entities = storageDao.getEntitiesByClassName(StorageConstants.REPORTS_ROOT, Report.class.getName()); for (Entity entity : entities) { Report report = (Report) entity; if (report.getType().equals(ReportConstants.NEXT)) { ro.nextreports.engine.Report nextReport = NextUtil.getNextReport(storageDao.getSettings(), report); if (report.isTableType() && ParameterUtil .allParametersHaveDefaults(ParameterUtil.getUsedNotHiddenParametersMap(nextReport)) && NextUtil.reportHasHeader(nextReport)) { reports.add(report); } } } return reports; } @Transactional(readOnly = true) @Secured("AFTER_ACL_COLLECTION_READ") public List<Report> getAlarmReports() throws NotFoundException { List<Report> reports = new ArrayList<Report>(); Entity[] entities = storageDao.getEntitiesByClassName(StorageConstants.REPORTS_ROOT, Report.class.getName()); for (Entity entity : entities) { Report report = (Report) entity; if (report.getType().equals(ReportConstants.NEXT)) { ro.nextreports.engine.Report nextReport = NextUtil.getNextReport(storageDao.getSettings(), report); if (report.isAlarmType() && ParameterUtil .allParametersHaveDefaults(ParameterUtil.getUsedNotHiddenParametersMap(nextReport))) { reports.add(report); } } } return reports; } @Override public void addReportListener(ReportListener reportListener) { reportListeners.put(SecurityUtil.getLoggedUsername(), reportListener); } @Override public void removeReportListener() { reportListeners.remove(SecurityUtil.getLoggedUsername()); } @Override public void notifyReportListener(ReportResultEvent event) { ReportListener reportListener = reportListeners.get(event.getCreator()); if (reportListener != null) { reportListener.onFinishRun(event); } } }