/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo Framework
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.report.internal.controller;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.DataDefinitionService;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.EntityList;
import com.qcadoo.report.api.ReportException;
import com.qcadoo.report.api.ReportService;
import com.qcadoo.report.api.ReportService.ReportType;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
@Controller
public class ReportDevelopmentController {
private static final String L_PARAMS = "params";
private static final String L_LOCALE = "locale";
private static final String L_TEMPLATE = "template";
private static final String L_QCADOO_REPORT_REPORT = "qcadooReport/report";
private static final String L_HQL = "hql";
private static final String L_QCADOO_REPORT_HQL = "qcadooReport/hql";
private static final Logger LOG = LoggerFactory.getLogger(ReportDevelopmentController.class);
@Autowired
private DataDefinitionService dataDefinitionService;
@Autowired
private ReportService reportService;
@Value("${showReportDevelopment}")
private boolean showReportDevelopment;
@RequestMapping(value = "developReport/hql", method = RequestMethod.GET)
public ModelAndView showHqlForm() {
if (!showReportDevelopment) {
return new ModelAndView(new RedirectView("/"));
}
return new ModelAndView(L_QCADOO_REPORT_HQL);
}
@RequestMapping(value = "developReport/hql", method = RequestMethod.POST)
public ModelAndView executeHql(@RequestParam(L_HQL) final String hql) {
if (!showReportDevelopment) {
return new ModelAndView(new RedirectView("/"));
}
try {
List<Entity> entities = dataDefinitionService.get("qcadooPlugin", "plugin").find(hql).list().getEntities();
if (entities.isEmpty()) {
return new ModelAndView(L_QCADOO_REPORT_HQL).addObject(L_HQL, hql).addObject("isEmpty", true);
} else {
DataDefinition dataDefinition = entities.get(0).getDataDefinition();
List<String> headers = new ArrayList<String>();
if (!isDynamicDataDefinition(dataDefinition)) {
headers.add("id");
}
headers.addAll(dataDefinition.getFields().keySet());
List<List<String>> rows = new ArrayList<List<String>>();
for (Entity entity : entities) {
List<String> row = new ArrayList<String>();
if (!isDynamicDataDefinition(dataDefinition)) {
row.add(String.valueOf(entity.getId()));
}
for (String field : dataDefinition.getFields().keySet()) {
if (entity.getField(field) == null) {
row.add("");
} else if (entity.getField(field) instanceof EntityList) {
row.add("[]");
} else {
row.add(String.valueOf(entity.getField(field)));
}
}
rows.add(row);
}
return new ModelAndView(L_QCADOO_REPORT_HQL).addObject(L_HQL, hql).addObject("headers", headers)
.addObject("rows", rows).addObject("isOk", true);
}
} catch (Exception e) {
return showException(L_QCADOO_REPORT_HQL, e).addObject(L_HQL, hql);
}
}
private ModelAndView showException(final String view, final Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
return new ModelAndView(view).addObject("exceptionMessage", e.getMessage()).addObject("exception", writer.toString())
.addObject("isError", true);
}
private boolean isDynamicDataDefinition(final DataDefinition dataDefinition) {
return dataDefinition.getPluginIdentifier().equals("qcadooModel") && dataDefinition.getName().startsWith("dynamic");
}
@RequestMapping(value = "developReport/report", method = RequestMethod.GET)
public ModelAndView showReportForm() {
if (!showReportDevelopment) {
return new ModelAndView(new RedirectView("/"));
}
return new ModelAndView(L_QCADOO_REPORT_REPORT);
}
@RequestMapping(value = "developReport/report", method = RequestMethod.POST)
public ModelAndView uploadReportFile(@RequestParam("file") final MultipartFile file, final HttpServletRequest request) {
if (!showReportDevelopment) {
return new ModelAndView(new RedirectView("/"));
}
if (file.isEmpty()) {
return new ModelAndView(L_QCADOO_REPORT_REPORT).addObject("isFileInvalid", true);
}
try {
String template = IOUtils.toString(file.getInputStream());
List<ReportParameter> params = getReportParameters(template);
return new ModelAndView(L_QCADOO_REPORT_REPORT).addObject(L_TEMPLATE, template).addObject("isParameter", true)
.addObject(L_PARAMS, params).addObject(L_LOCALE, "en");
} catch (Exception e) {
return showException(L_QCADOO_REPORT_REPORT, e);
}
}
private final List<String> ignoredParameters = Arrays.asList("Author");
@SuppressWarnings("unchecked")
private List<ReportParameter> getReportParameters(final String template) throws JDOMException, IOException {
Document document = new SAXBuilder().build(new ByteArrayInputStream(template.getBytes()));
Namespace namespace = Namespace.getNamespace("http://jasperreports.sourceforge.net/jasperreports");
List<Element> parameters = document.getRootElement().getChildren("parameter", namespace);
List<ReportParameter> params = new ArrayList<ReportParameter>();
for (Element parameter : parameters) {
String value = null;
if (ignoredParameters.contains(parameter.getAttributeValue("name"))) {
continue;
}
if (parameter.getChild("defaultValueExpression", namespace) != null) {
value = parameter.getChild("defaultValueExpression", namespace).getTextNormalize().replaceAll("\\\"", "");
}
params.add(new ReportParameter(parameter.getAttributeValue("name"), parameter.getAttributeValue("class"), value));
}
return params;
}
@RequestMapping(value = "developReport/generate", method = RequestMethod.POST)
public ModelAndView generateReport(@RequestParam(value = L_TEMPLATE) final String template,
@RequestParam(value = "type") final String type, @RequestParam(value = L_LOCALE) final String locale,
final HttpServletRequest request, final HttpServletResponse response) {
if (!showReportDevelopment) {
return new ModelAndView(new RedirectView("/"));
}
List<ReportParameter> params = null;
try {
params = getReportParameters(template);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return showException(L_QCADOO_REPORT_REPORT, e).addObject(L_TEMPLATE, template).addObject("isParameter", true)
.addObject(L_LOCALE, locale);
}
try {
ReportType reportType = ReportType.valueOf(type.toUpperCase(Locale.ENGLISH));
Locale reportLocale = new Locale(locale);
Map<String, Object> parameters = new HashMap<String, Object>();
for (ReportParameter param : params) {
param.setValue(request.getParameter("params[" + param.getName() + "]"));
parameters.put(param.getName(), param.getRawValue());
}
byte[] report = reportService.generateReport(template, reportType, parameters, reportLocale);
response.setContentLength(report.length);
response.setContentType(reportType.getMimeType());
response.setHeader("Content-disposition", "attachment; filename=report." + type);
response.addHeader("Expires", "Tue, 03 Jul 2001 06:00:00 GMT");
response.addHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.addHeader("Pragma", "no-cache");
OutputStream out = response.getOutputStream();
try {
IOUtils.copy(new ByteArrayInputStream(report), out);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new ReportException(ReportException.Type.ERROR_WHILE_COPYING_REPORT_TO_RESPONSE, e);
}
out.flush();
return null;
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return showException(L_QCADOO_REPORT_REPORT, e).addObject(L_TEMPLATE, template).addObject("isParameter", true)
.addObject(L_PARAMS, params).addObject(L_LOCALE, locale);
}
}
public static class ReportParameter {
private static final String JAVA_UTIL_LIST = "java.util.List";
private final String name;
private final String clazz;
private Object value;
public ReportParameter(final String name, final String clazz, final String value) {
this.name = name;
this.clazz = clazz;
this.value = convertValueToObject(value);
}
public void setValue(final String value) {
this.value = convertValueToObject(value);
}
public String getClazz() {
return clazz;
}
public String getName() {
return name;
}
public Object getRawValue() {
return value;
}
public String getValue() {
return convertValueToString(value);
}
@SuppressWarnings("rawtypes")
private String convertValueToString(final Object value) {
if (value == null) {
return "";
} else if (JAVA_UTIL_LIST.equals(clazz)) {
return StringUtils.join((List) value, ",");
} else {
return String.valueOf(value);
}
}
private Object convertValueToObject(final String value) {
if (JAVA_UTIL_LIST.equals(clazz) && !org.springframework.util.StringUtils.hasText(value)) {
return Collections.emptyList();
} else if (JAVA_UTIL_LIST.equals(clazz) && "EntityIds".equals(name)) {
String[] strings = value.trim().split("\\s*,\\s*");
List<Long> values = new ArrayList<Long>();
for (String string : strings) {
values.add(Long.valueOf(string));
}
return values;
} else if (JAVA_UTIL_LIST.equals(clazz)) {
String[] values = value.trim().split("\\s*,\\s*");
return Arrays.asList(values);
} else {
return value;
}
}
}
}