blob: 3d0fd423ac2b872f931f84d08bde4f74f063a962 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2018 Mettenmeier GmbH
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
package org.eclipse.openk.sp.controller.reports;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.report.engine.api.EXCELRenderOption;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineConstants;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.eclipse.birt.report.engine.api.PDFRenderOption;
import org.eclipse.birt.report.engine.api.RenderOption;
import org.eclipse.core.internal.registry.RegistryProviderFactory;
import org.eclipse.openk.common.Globals;
import org.eclipse.openk.sp.controller.AbstractController;
import org.eclipse.openk.sp.db.dao.StandbyListRepository;
import org.eclipse.openk.sp.db.dao.StandbyScheduleBodyRepository;
import org.eclipse.openk.sp.db.dao.UserRepository;
import org.eclipse.openk.sp.db.model.StandbyGroup;
import org.eclipse.openk.sp.db.model.StandbyList;
import org.eclipse.openk.sp.db.model.StandbyScheduleBody;
import org.eclipse.openk.sp.db.model.User;
import org.eclipse.openk.sp.dto.report.ReportDto;
import org.eclipse.openk.sp.dto.report.ReportInputDto;
import org.eclipse.openk.sp.exceptions.SpErrorEntry;
import org.eclipse.openk.sp.exceptions.SpException;
import org.eclipse.openk.sp.exceptions.SpExceptionEnum;
import org.eclipse.openk.sp.util.DateHelper;
import org.eclipse.openk.sp.util.FileHelper;
import org.eclipse.openk.sp.util.ReportGroupDtoConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
@Service
@Transactional(rollbackFor = Exception.class)
public class ReportController extends AbstractController {
protected static final Logger LOGGER = Logger.getLogger(ReportController.class);
@Autowired
StandbyScheduleBodyRepository standbyScheduleBodyRepository;
@Autowired
ReportGroupDtoConverter reportGroupDtoConverter;
@Autowired
StandbyListRepository standbyListRepository;
@Autowired
UserRepository userRepository;
@Autowired
FileHelper fileHelper;
protected List<Long> lsTempRemovalIds = new ArrayList<>();
private String reportDirectory;
private String workDirectory;
private static String REPORT_NAME = "report for ";
private static final String APP_PROPERTIES_NAME = "/application.properties";
private static String REPORT_MAX10_GROUPS = "Diensthabende_Mitarbeiter_je_Bereitschaftsgruppe";
private static String REPORT_ALL_GROUPS = "Diensthabende_Mitarbeiter_je_Bereitschaftsgruppe_mit_Details";
private static String REPORT_ONE_USER = "Persönlicher_Einsatzplan";
private static final Set<String> allowedReports = new HashSet<>(Arrays.asList("rptdesign"));
private JsonElement reportConfig;
public String init() {
Properties property = null;
try {
property = fileHelper.loadPropertiesFromResource(APP_PROPERTIES_NAME);
reportDirectory = property.getProperty("reports.path");
workDirectory = property.getProperty("reports.workdirectory");
File workDirectoryFile = fileHelper.loadFolderFromFileSystemOrResource(workDirectory, false);
if (!workDirectoryFile.exists()) {
LOGGER.info("the work directory for the files was not found! Creating one..");
workDirectoryFile.mkdirs();
}
File reportConfigFile = fileHelper.loadFileFromFileSystemOrResource(reportDirectory, "config.json", false);
if (!reportConfigFile.exists()) {
LOGGER.error("a report config does not exist");
} else {
String content = new String(Files.readAllBytes(reportConfigFile.toPath()), StandardCharsets.UTF_8);
JsonParser parser = new JsonParser();
reportConfig = parser.parse(content);
}
return reportDirectory;
} catch (IOException e) {
LOGGER.error(e, e);
}
return null;
}
/**
* Method to query all reports.
*
* @return
*/
public List<ReportDto> getReports() {
ArrayList<ReportDto> listReports = new ArrayList<>();
init();
for (File file : fileHelper.loadFolderFromFileSystemOrResource(reportDirectory, true).listFiles()) {
String fileExtension = FilenameUtils.getExtension(file.getAbsolutePath());
if (allowedReports.contains(fileExtension)) {
String reportName = FilenameUtils.removeExtension(file.getName());
ReportDto reportDto = new ReportDto(reportName);
reportDto.setDefaultDayRange(31);
listReports.add(reportDto);
}
}
return listReports;
}
public File generateReport(ReportDto reportDto) throws SpException {
List<ReportInputDto> inputDtos = null;
if (reportDto.getReportName().equals(REPORT_MAX10_GROUPS)) {
LOGGER.info(REPORT_NAME + REPORT_MAX10_GROUPS);
inputDtos = reportGroupDtoConverter.getRows(reportDto);
} else {
SpErrorEntry ee = SpExceptionEnum.NO_DATA_FOR_REPORT_FOUND.getEntry();
List<StandbyScheduleBody> result = performReportQuery(reportDto);
LOGGER.debug(result.size() + " records found for reporting");
if (result.isEmpty()) {
LOGGER.warn(ee.getMessage());
throw new SpException(ee);
}
if (reportDto.getStandByList() != null) {
LOGGER.info(REPORT_NAME + REPORT_ALL_GROUPS);
inputDtos = compress2ResultOnGroups(reportDto, result);
} else {
StandbyScheduleBody lastBody = null;
// persönlicher Einsatzplan
LOGGER.info(REPORT_NAME + REPORT_ONE_USER);
inputDtos = compress1ResultOnGroups(reportDto, result);
}
}
LOGGER.info("packing dataset for report with " + inputDtos.size() + " rows!");
init();
return generateBirtReport(reportDto.getReportName(), reportDto.getFormat(), inputDtos, reportDto);
}
/**
* compress only bodies that are not interrupted
*
* @param reportDto
* @param result
* @return
*/
private List<ReportInputDto> compressResultLevel1(List<ReportInputDto> reportInputDataSet, ReportDto reportDto,
List<StandbyScheduleBody> result) {
StandbyScheduleBody lastBody = null;
for (StandbyScheduleBody standbyBody : result) {
if (lastBody != null
&& (lastBody.getUser().getId().longValue() == standbyBody.getUser().getId().longValue())
&& (lastBody.getValidTo().compareTo(standbyBody.getValidFrom()) == 0)) {
lastBody.setValidTo(standbyBody.getValidTo());
calcReportEndDate(lastBody);
} else {
lastBody = standbyBody.copy();
calcReportStartDate(lastBody);
calcReportEndDate(lastBody);
ReportInputDto reportInputDto = new ReportInputDto();
reportInputDto.setReportDto(reportDto);
reportInputDto.setStandbyScheduleBody(lastBody);
reportInputDataSet.add(reportInputDto);
}
}
return reportInputDataSet;
}
/**
* compress bodies as long as the user is not changed
*
* @param reportDto
* @param result
* @param groupSort
* @return
*/
private List<ReportInputDto> compressResultLevel2(List<ReportInputDto> reportInputDataSet, ReportDto reportDto,
List<StandbyScheduleBody> result, int groupSort) {
StandbyScheduleBody lastBody = null;
for (StandbyScheduleBody standbyBody : result) {
if (lastBody != null
&& lastBody.getUser().getId().longValue() == standbyBody.getUser().getId().longValue()) {
lastBody.setValidTo(standbyBody.getValidTo());
calcReportEndDate(lastBody);
} else {
lastBody = standbyBody.copy();
calcReportStartDate(lastBody);
calcReportEndDate(lastBody);
ReportInputDto reportInputDto = new ReportInputDto();
reportInputDto.setReportDto(reportDto);
reportInputDto.setStandbyScheduleBody(lastBody);
reportInputDto.setGroupSort(groupSort);
reportInputDataSet.add(reportInputDto);
}
}
return reportInputDataSet;
}
private List<ReportInputDto> compress2ResultOnGroups(ReportDto reportDto, List<StandbyScheduleBody> result) {
List<ReportInputDto> reportInputDataSet = new ArrayList<>();
StandbyList sbl = reportDto.getStandByList();
List<StandbyGroup> groups = sbl.getLsStandbyGroups();
Map<Long, List<StandbyScheduleBody>> groupMap = new HashMap<>();
// init all Lists
for (StandbyGroup standbyGroup : groups) {
groupMap.put(standbyGroup.getId(), new ArrayList<StandbyScheduleBody>());
}
// sort by group
for (StandbyScheduleBody body : result) {
List<StandbyScheduleBody> groupList = groupMap.get(body.getStandbyGroup().getId());
groupList.add(body);
Collections.sort(groupList, (o1, o2) -> o1.getValidFrom().compareTo(o2.getValidFrom()));
}
int groupSort = 0;
// compact
for (StandbyGroup standbyGroup : groups) {
LOGGER.debug("compactiong for group: " + standbyGroup.getTitle() + " on position " + groupSort);
List<StandbyScheduleBody> groupList = groupMap.get(standbyGroup.getId());
LOGGER.debug("from " + groupList.size() + " in " + reportInputDataSet.size());
reportInputDataSet = compressResultLevel2(reportInputDataSet, reportDto, groupList, groupSort);
groupSort++;
}
return reportInputDataSet;
}
public List<ReportInputDto> compress1ResultOnGroups(ReportDto reportDto, List<StandbyScheduleBody> result) {
List<ReportInputDto> reportInputDataSet = new ArrayList<>();
Map<Long, List<StandbyScheduleBody>> groupMap = new HashMap<>();
// sort by group
for (StandbyScheduleBody body : result) {
Long groupId = body.getStandbyGroup().getId();
if (groupMap.containsKey(groupId)) {
List<StandbyScheduleBody> groupList = groupMap.get(groupId);
groupList.add(body);
Collections.sort(groupList, (o1, o2) -> o1.getValidFrom().compareTo(o2.getValidFrom()));
} else {
// init all List
groupMap.put(groupId, new ArrayList<StandbyScheduleBody>());
List<StandbyScheduleBody> groupList = groupMap.get(groupId);
groupList.add(body);
}
}
Set<Long> keySet = groupMap.keySet();
for (Long groupId : keySet) {
List<StandbyScheduleBody> groupList = groupMap.get(groupId);
LOGGER.debug("compacting over groupId: " + groupId);
LOGGER.debug("from " + groupList.size() + " in " + reportInputDataSet.size());
compressResultLevel1(reportInputDataSet, reportDto, groupList);
}
return reportInputDataSet;
}
public void calcReportStartDate(StandbyScheduleBody body) {
GregorianCalendar calendar = new GregorianCalendar(Locale.GERMANY);
calendar.setTime(body.getValidFrom());
body.setStartDateStr(DateHelper.convertToLocalString(calendar.getTime(), "EE. dd.MM.yy HH:mm"));
}
public void calcReportEndDate(StandbyScheduleBody body) {
GregorianCalendar calendar = new GregorianCalendar(Locale.GERMANY);
calendar.setTime(body.getValidTo());
body.setEndDateStr(DateHelper.convertToLocalString(calendar.getTime(), "EE. dd.MM.yy HH:mm"));
}
public IReportEngine initialiseBirtEngine() {
IReportEngine engine = null;
try {
final EngineConfig config = new EngineConfig();
config.setLogConfig(workDirectory, Level.FINE);
Platform.startup(config);
IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
engine = factory.createReportEngine(config);
engine.changeLogLevel(Level.WARNING);
LOGGER.info("Successfully startet the BIRT engine");
} catch (Exception e) {
LOGGER.error(e, e);
}
return engine;
}
public File generateBirtReport(String reportName, String format, List<ReportInputDto> inputDtos,
ReportDto reportDto) {
String token = String.valueOf(new Random().nextLong());
try (InputStream rptdFileStream = new FileInputStream(
fileHelper.loadFileFromFileSystemOrResource(reportDirectory, reportName + ".rptdesign", true))) {
LOGGER.info("Found design file " + reportName + ".rptdesign. inside " + reportDirectory);
IReportEngine engine = initialiseBirtEngine();
IReportRunnable iReportRunnable = engine.openReportDesign(rptdFileStream);
IRunAndRenderTask task = engine.createRunAndRenderTask(iReportRunnable);
task.getAppContext().put(EngineConstants.APPCONTEXT_CLASSLOADER_KEY,
ReportController.class.getClassLoader());
LOGGER.info("Filling reports with DATASET. Found [" + inputDtos.size() + "] items.");
task.getAppContext().put("APP_CONTEXT_KEY_OK_DATASET", inputDtos);
RenderOption options = null;
setTaskParameters(task, reportDto);
if (format.equals("xlsx")) {
options = new EXCELRenderOption();
options.setOutputFormat("xlsx");
} else if (format.equals("xls")) {
options = new EXCELRenderOption();
options.setOutputFormat("xls");
} else {
options = new PDFRenderOption();
options.setOutputFormat("pdf");
}
LOGGER.info("Format for the report is " + options.getOutputFormat());
options.setOutputFileName(
workDirectory + File.separator + reportName + "_" + token + "." + options.getOutputFormat());
task.setRenderOption(options);
task.run();
LOGGER.info("Report creation successfull. Shuting Engine down and closing task..");
task.close();
engine.destroy();
Platform.shutdown();
RegistryProviderFactory.releaseDefault();
} catch (Exception e) {
LOGGER.error("While creating the report something went terribly wrong", e);
}
return fileHelper.loadFileFromFileSystemOrResource(workDirectory, reportName + "_" + token + "." + format,
true);
}
/**
* Method to get custom report text
*
* @param planRequest
* @return
* @throws IOException
*/
public String customText(String templateFile, Object... obj) throws IOException {
LOGGER.info("resource: " + templateFile);
InputStream is = fileHelper.loadFileFromResource(templateFile);
String newHtmlBody = null;
if (is != null) {
String htmlBody = IOUtils.toString(is, StandardCharsets.UTF_8.name());
newHtmlBody = MessageFormat.format(htmlBody, obj);
}
return newHtmlBody;
}
/**
* Setting the parameter values of a report
*
* @param task
* @param inputDtos
*/
public boolean setTaskParameters(IRunAndRenderTask task, ReportDto reportDto) {
boolean isSet = true;
try {
LOGGER.info("read custom text for reports");
String text1 = customText(Globals.REPORT_TEXT1);
String text2 = customText(Globals.REPORT_TEXT2);
String text3 = customText(Globals.REPORT_TEXT3);
task.setParameterValue("customText1", text1);
task.setParameterValue("customText2", text2);
task.setParameterValue("customText3", text3);
} catch (IOException e) {
LOGGER.error("report properties could not be read!");
}
if (reportDto == null) {
task.setParameterValue("liste", "--");
task.setParameterValue("von", DateHelper.convertToString(null, "dd.MM.yyyy"));
task.setParameterValue("bis", DateHelper.convertToString(null, "dd.MM.yyyy"));
task.setParameterValue("reportLevel", "--");
task.setParameterValue("reportName", "--");
task.setParameterValue("user", "--");
} else {
if (reportDto.getStandByList() != null) {
task.setParameterValue("liste", reportDto.getStandByList().getTitle());
}
if (reportDto.getFrom() != null) {
task.setParameterValue("von", DateHelper.convertToString(reportDto.getFrom(), "dd.MM.yyyy"));
}
if (reportDto.getTo() != null) {
task.setParameterValue("bis", DateHelper.convertToString(reportDto.getTo(), "dd.MM.yyyy"));
}
if (reportDto.getReportLevel() != null) {
task.setParameterValue("reportLevel", reportDto.getReportLevel());
}
if (reportDto.getReportName() != null) {
task.setParameterValue("reportName", reportDto.getReportName());
}
if (reportDto.getUserId() != null) {
User user = userRepository.findOne(reportDto.getUserId());
task.setParameterValue("user", user.getFirstname() + " " + user.getLastname());
}
}
task.setParameterValue("created", DateHelper.convertToString(null, "dd.MM.yyyy HH:mm:ss"));
return isSet;
}
public List<StandbyScheduleBody> performReportQuery(ReportDto reportDto) throws SpException {
Long[] groupIds = null;
Date validFrom = DateHelper.getStartOfDay(reportDto.getFrom());
Date validTo = DateHelper.getEndOfDay(reportDto.getTo());
List<StandbyScheduleBody> result = null;
Long reportLevel = 2L;
LOGGER.info("[" + validFrom + "," + validTo + "]");
if (reportDto.getReportLevel().equals("Plan-Ebene")) {
reportLevel = 1L;
}
if (reportDto.getStandByGroup() != null) {
LOGGER.info("report for one group");
groupIds = new Long[1];
groupIds[0] = reportDto.getStandByGroup().getId();
} else if (reportDto.getStandByList() != null) {
LOGGER.info("report for many groups");
StandbyList sbl = reportDto.getStandByList();
List<StandbyGroup> groups = sbl.getLsStandbyGroups();
int maxGroups = groups.size();
if (groups.isEmpty()) {
LOGGER.warn("performReportQuery: No groups in list! ");
throw new SpException(HttpStatus.SC_METHOD_NOT_ALLOWED,
"Es kann kein Report zu einer Liste ohne Guppen erstellt werden!", new Exception());
}
groupIds = new Long[maxGroups];
for (int i = 0; i < groups.size() && i < maxGroups; i++) {
groupIds[i] = groups.get(i).getId();
}
} else if (reportDto.getUserId() != null) {
// Persönlicher Einsatzplan
LOGGER.info("report for one person");
} else {
LOGGER.warn("performReportQuery: No group and no list is selected! ");
throw new SpException(HttpStatus.SC_METHOD_NOT_ALLOWED,
"performReportQuery: No group and no list is selected! ", new Exception());
}
if (reportDto.getUserId() != null) {
LOGGER.info("query for one person");
result = standbyScheduleBodyRepository.findByUserAndDateAndStatus(reportDto.getUserId(), validFrom, validTo,
reportLevel);
} else {
LOGGER.info("query for groups");
result = standbyScheduleBodyRepository.findByGroupsAndDateAndStatus(groupIds, validFrom, validTo,
reportLevel);
}
return result;
}
public void flushReportFile(File reportFile, OutputStream out) {
try (FileInputStream in = new FileInputStream(reportFile);) {
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
out.flush();
if (reportFile.exists()) {
in.close();
Files.delete(reportFile.toPath());
} else {
throw new FileNotFoundException();
}
} catch (Exception e) {
LOGGER.error(e, e);
}
}
public void setResponseData(HttpServletResponse response, ReportDto reportDto) {
response.setContentType("application/" + reportDto.getFormat());
response.setHeader("Content-disposition",
"attachment; filename=" + reportDto.getReportName() + "." + reportDto.getFormat());
}
}