blob: 86de489ca4ba72db7fcd18e0bde53b8f1f195229 [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.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
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 javax.ws.rs.core.MediaType;
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.StandbyGroupRepository;
import org.eclipse.openk.sp.db.dao.StandbyListRepository;
import org.eclipse.openk.sp.db.dao.StandbyScheduleBodyRepository;
import org.eclipse.openk.sp.db.dao.StandbyStatusRepository;
import org.eclipse.openk.sp.db.dao.UserRepository;
import org.eclipse.openk.sp.db.model.Address;
import org.eclipse.openk.sp.db.model.ContactData;
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.StandbyStatus;
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.rest.reports.ReportRestService;
import org.eclipse.openk.sp.util.DateHelper;
import org.eclipse.openk.sp.util.FileHelper;
import org.eclipse.openk.sp.util.ReportGroupDtoConverter;
import org.eclipse.openk.sp.util.ReportGroupNameDtoConverter;
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
StandbyStatusRepository standbyStatusRepository;
@Autowired
StandbyGroupRepository standbyGroupRepository;
@Autowired
ReportGroupDtoConverter reportGroupDtoConverter;
@Autowired
ReportGroupNameDtoConverter reportGroupDtoConverter2;
@Autowired
StandbyListRepository standbyListRepository;
@Autowired
UserRepository userRepository;
@Autowired
FileHelper fileHelper;
protected List<Long> lsTempRemovalIds = new ArrayList<>();
private String reportDirectory;
private String workDirectory;
private static final String REPORT_NAME = "report for ";
private static final String APP_PROPERTIES_NAME = "/application.properties";
public static final String REPORT_MAX10_GROUPS = "Diensthabende_MA_je_BG_(max._10)";
public static final String REPORT_MAX10_GROUPS_ONLY_NAMES = "Diensthabende_MA_je_BG_(max._60)_nur_beginnende_Duration_pro_Tag";
public static final String REPORT_ALL_GROUPS = "Diensthabende_MA_je_BG_Details";
public static final 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
* @throws SpException
*/
public List<ReportDto> getReports() throws SpException {
ArrayList<ReportDto> listReports = new ArrayList<>();
try {
init();
for (File file : fileHelper.loadFolderFromFileSystemOrResource(reportDirectory, true).listFiles()) {
String fileExtension = FileHelper.getFileExtension(file);
if (allowedReports.contains(fileExtension)) {
String reportName = file.getName();
reportName = reportName.substring(0, reportName.lastIndexOf('.'));
ReportDto reportDto = new ReportDto();
reportDto.setReportName(reportName);
int defaultDayRange = 7;
// setting default dayrange
if (reportName.equals(ReportController.REPORT_ALL_GROUPS)) {
defaultDayRange = 30;
}
reportDto.setDefaultDayRange(defaultDayRange);
listReports.add(reportDto);
}
}
// sorting by reportname
Collections.sort(listReports, (o1, o2) -> o1.getReportName().compareTo(o2.getReportName()));
return listReports;
} catch (Exception e) {
SpErrorEntry ee = SpExceptionEnum.DEFAULT_EXCEPTION.getEntry();
ee.setE(e);
throw new SpException(ee);
}
}
public File generateReport(ReportDto reportDto) throws SpException {
List<ReportInputDto> inputDtos = null;
if (reportDto.getReportName().equals(REPORT_MAX10_GROUPS)) {
// 10 Gruppen Plan
LOGGER.info(REPORT_NAME + REPORT_MAX10_GROUPS);
inputDtos = reportGroupDtoConverter.get10Rows(reportDto);
} else if (reportDto.getReportName().equals(REPORT_MAX10_GROUPS_ONLY_NAMES)) {
// 60 Gruppen Plan
LOGGER.info(REPORT_NAME + REPORT_MAX10_GROUPS_ONLY_NAMES);
inputDtos = reportGroupDtoConverter2.get60Rows(reportDto);
} else {
// persönlicher Einsatzplan und Detailplan
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 {
// 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.getPrintFormat(), 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) {
body.setStartDateStr(DateHelper.convertToLocalString(body.getValidFrom(), null));
}
public void calcReportEndDate(StandbyScheduleBody body) {
body.setEndDateStr(DateHelper.convertToLocalString(body.getValidTo(), null));
}
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());
LOGGER.debug("outputFilePath: " + workDirectory + File.separator + reportName + "_" + token + "."
+ 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 = FileHelper.getTextFromInputStream(is, StandardCharsets.UTF_8);
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) {
String shortDatePattern = "dd.MM.yyyy";
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, shortDatePattern));
task.setParameterValue("bis", DateHelper.convertToString(null, shortDatePattern));
task.setParameterValue("reportLevel", "--");
task.setParameterValue("reportName", "--");
task.setParameterValue("user", "--");
} else {
if (reportDto.getStandByListId() != null && standbyListRepository.exists(reportDto.getStandByListId())) {
StandbyList sbl = standbyListRepository.findOne(reportDto.getStandByListId());
task.setParameterValue("liste", sbl.getTitle());
} else {
task.setParameterValue("liste", "--");
}
if (reportDto.getValidFromDate() != null) {
String pattern = (reportDto.getReportName().equals(ReportController.REPORT_MAX10_GROUPS_ONLY_NAMES))
? shortDatePattern
: null;
task.setParameterValue("von", DateHelper.convertToLocalString(reportDto.getValidFromDate(), pattern));
}
if (reportDto.getValidToDate() != null) {
String pattern = (reportDto.getReportName().equals(ReportController.REPORT_MAX10_GROUPS_ONLY_NAMES))
? shortDatePattern
: null;
task.setParameterValue("bis", DateHelper.convertToLocalString(reportDto.getValidToDate(), pattern));
}
if (reportDto.getStatusId() != null && standbyStatusRepository.exists(reportDto.getStatusId())) {
StandbyStatus status = standbyStatusRepository.findOne(reportDto.getStatusId());
task.setParameterValue("reportLevel", status.getTitle());
} else {
task.setParameterValue("reportLevel", "--");
}
if (reportDto.getReportName() != null) {
task.setParameterValue("reportName", reportDto.getReportName());
}
if (reportDto.getUserId() != null && userRepository.exists(reportDto.getUserId())) {
User user = userRepository.findOne(reportDto.getUserId());
task.setParameterValue("user", user.getFirstname() + " " + user.getLastname());
} else {
task.setParameterValue("user", "--");
}
}
Date currentDate = null;
try {
if (reportDto != null && reportDto.getCurrentDate() != null) {
currentDate = DateHelper.getDateFromString(reportDto.getCurrentDate(), "yyyy-MM-dd'T'hh:mm:ss.SSS'Z'");
}
} catch (ParseException e) {
LOGGER.error(e, e);
}
task.setParameterValue("created", DateHelper.convertToString(currentDate, "dd.MM.yyyy HH:mm:ss"));
return isSet;
}
public List<StandbyScheduleBody> performReportQuery(ReportDto reportDto) throws SpException {
Long[] groupIds = null;
Date validFrom = (reportDto.getValidFromDate());
Date validTo = (reportDto.getValidToDate());
List<StandbyScheduleBody> result = null;
Long reportLevel = reportDto.getStatusId();
LOGGER.info("[" + validFrom + "," + validTo + "]");
if (reportDto.getStandByGroup() != null) {
LOGGER.info("report for one group");
groupIds = new Long[1];
groupIds[0] = reportDto.getStandByGroup().getId();
} else if (reportDto.getStandByListId() != null && standbyListRepository.exists(reportDto.getStandByListId())) {
LOGGER.info("report for many groups");
StandbyList sbl = standbyListRepository.findOne(reportDto.getStandByListId());
reportDto.setStandByList(sbl);
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 < 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.findData(groupIds, validFrom, validTo, reportLevel);
Map<Long, StandbyGroup> foundGroups = new HashMap<>();
// collect groups
for (StandbyScheduleBody sbbody : result) {
foundGroups.put(sbbody.getStandbyGroup().getId(), sbbody.getStandbyGroup());
}
List<StandbyScheduleBody> resultWithEmpty = new ArrayList<>();
resultWithEmpty.addAll(result);
// create empty body for empty group
for (Long gId : groupIds) {
if (!foundGroups.containsKey(gId)) {
StandbyScheduleBody emptyBody = new StandbyScheduleBody();
// setting dates
emptyBody.setValidFrom(validFrom);
emptyBody.setValidTo(validTo);
// setting group
emptyBody.setStandbyGroup(standbyGroupRepository.findOne(gId));
// setting empty user
User user = new User();
user.setFirstname("");
user.setLastname("");
ContactData emptyContact = new ContactData();
emptyContact.setPhone("");
emptyContact.setCellphone("");
emptyContact.setRadiocomm("");
emptyContact.setPager("");
user.setBusinessContactData(emptyContact);
Address emptyAddress = new Address();
emptyAddress.setCommunity("");
user.setPrivateAddress(emptyAddress);
user.setPrivateContactData(emptyContact);
emptyBody.setUser(user);
// add to result
resultWithEmpty.add(emptyBody);
}
}
result = resultWithEmpty;
}
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) {
if (reportDto.getPrintFormat().equals("xlsx")) {
response.setContentType("application/octet-stream");
} else if (reportDto.getPrintFormat().equals("pdf")) {
response.setContentType(MediaType.APPLICATION_JSON);
}
response.setHeader("Content-Disposition",
"attachment; filename=" + reportDto.getReportName() + "." + reportDto.getPrintFormat());
}
}