package pl.touk.tola.spring.mvc.export.controller;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import pl.touk.tola.gwt.shared.ExportParameters;
import pl.touk.tola.gwt.shared.ExportParameters.ExportParameterNameInRequest;
import pl.touk.tola.spring.mvc.export.Exporter;
import pl.touk.tola.spring.mvc.export.exporters.CsvExporter;
import pl.touk.tola.spring.mvc.export.exporters.XlsExporter;
import pl.touk.wonderfulsecurity.springsecurity.WsecUserDetails;
/**
* Kontroler do exportu tabelki do csv.
* Wymaga podania w requescie trzech parametrów:
* clazz - nazwa beana hibernate'owego do wyciagniecia z bazy
* filePrefix - nazwa pliku, który ma być zwrócony
* sortColumn - kolumna (bean property), po ktorej mają być posortowane dane;
*
* Parametry są okreslone w enumeracji ExportParameterNameInRequest.
*
* Wszystkie inne parametry traktowane są jako parametry dla hibernate i umozliwiają wyszukanie w bazie na zasadzie:
* select xxx where param = XXX;
* Parametry są postaci <paramName>=<paramValue>||<paramType> np:
* ..&idProduktu=2||java.lang.Long..
*
* Kontroller obsługuje następujące typy:
* java.lang.String
* java.lang.Long
* java.lang.Integer
*
* Kontroller jest wrażliwy na uprawnienia. Definiuje się je przez ustawienie w mapie: permissionMapping par:
* <nazwaBeanu>, <uprawnienie>
* np:
* <property name="permissionMapping">
* <map>
* <entry key="pl.touk.nsw.fe.shared.model.publishingPlan.PublishingPlanItemBean" value="PUBLISHING_PLAN_TAB"/>
* <entry key="pl.touk.nsw.fe.shared.model.ap.mediaCampaigns.ReportPromoVersionBean" value="MEDIA_CAMPAIGNS_TAB"/>
* </map>
* </property>
*
* @author rpietra
*/
public class ExportController extends AbstractController {
public static final String DELIMETER = "\\|\\|";
private Log log = LogFactory.getLog(ExportController.class);
private final Exporter csvExporter;
private final Exporter xlsExporter;
private HashMap<String, String> permissionMapping;
public ExportController(CsvExporter csvExporter, XlsExporter xlsExporter) {
this.csvExporter = csvExporter;
this.xlsExporter = xlsExporter;
}
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
ExportParameters exportParameters = getExportParametersFromRequest(request);
prepareResponseHeader(response, exportParameters);
if (areAllRequiredParams(exportParameters)) {
if (hasPermission(exportParameters.getClazz())) {
if (exportParameters.isXlsExport()) {
xlsExporter.exportData(exportParameters, response.getOutputStream());
} else {
csvExporter.exportData(exportParameters, response.getOutputStream());
}
} else {
createResponse(response, "Brak uprawnień do eksportu.");
}
} else {
log.warn("Błąd exportu danych. Brak parametrów eksportu na serwerze.");
createResponse(response, "Błąd eksportu danych. Brak parametrów eksportu na serwerze.");
}
return null;
}
private void createResponse(HttpServletResponse response, String msg) throws IOException {
Writer w = new OutputStreamWriter(response.getOutputStream());
w.write(msg);
w.close();
}
private ExportParameters getExportParametersFromRequest(HttpServletRequest request) {
String fileNamePrefix = request.getParameter(ExportParameterNameInRequest.filePrefix.name());
String clazz = request.getParameter(ExportParameterNameInRequest.clazz.name());
String sortColumn = request.getParameter(ExportParameterNameInRequest.sortColumn.name());
String xlsExportString = request.getParameter(ExportParameterNameInRequest.xlsExport.name());
Boolean xlsExport = new Boolean(xlsExportString);//TODO: to sie moze wywalić
Map<String, Object> parametersMap = copyParametersFromRequest(request);
return new ExportParameters(clazz, sortColumn, fileNamePrefix, parametersMap, xlsExport);
}
private boolean areAllRequiredParams(ExportParameters exportParameters) {
boolean clazz = exportParameters.getClazz() != null;
boolean parameters = exportParameters.getParameters() != null;
boolean sortColumn = exportParameters.getSortColumn() != null;
if (!parameters) {
exportParameters.setParameters(new HashMap<String, Object>());
}
return clazz && sortColumn;
}
private boolean hasPermission(String clazz) {
WsecUserDetails user = (WsecUserDetails) ((SecurityContext) SecurityContextHolder.getContext()).getAuthentication().getPrincipal();
String neededPermissionName = permissionMapping.get(clazz);
for (GrantedAuthority authority : user.getAuthorities()) {
if (authority.getAuthority().equals(neededPermissionName)) {
return true;
}
}
return false;
}
private void prepareResponseHeader(HttpServletResponse response, ExportParameters exportParameters) {
String fileName = exportParameters.getFilenamePrefix();
//TODO: to ponizej jest niefajnie napisane
if (exportParameters.isXlsExport()) {
fileName = (fileName != null && fileName.trim().length() > 0) ? fileName.trim() + ".xls" : "export.xls";
fileName = fileName.replaceAll(" ", "_");
response.addHeader("Content-Type", "application/xls");
} else {
fileName = (fileName != null && fileName.trim().length() > 0) ? fileName.trim() + ".csv" : "export.csv";
fileName = fileName.replaceAll(" ", "_");
response.addHeader("Content-Type", "text/csv");
}
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
}
private Map<String, Object> copyParametersFromRequest(HttpServletRequest request) {
Map<String, Object> returnParameters = new HashMap<String, Object>();
Enumeration enumeration = request.getParameterNames();
while (enumeration.hasMoreElements()) {
String paramName = (String) enumeration.nextElement();
String paramValue = request.getParameter(paramName);
if (nonStandardParameter(paramName)) {
returnParameters.put(paramName, decodeParameterValue(paramValue));
}
}
return returnParameters;
}
protected Object decodeParameterValue(String parameter) {
String[] param = parameter.split(DELIMETER);
if (param.length == 2) {
String paramType = param[1];
String paramValue = param[0];
if (equalsAndNotNull(paramType, "java.lang.Long")) {
return Long.valueOf(paramValue);
}
if (equalsAndNotNull(paramType, "java.lang.Integer")) {
return Integer.valueOf(paramValue);
}
if (equalsAndNotNull(paramType, "java.lang.String")) {
return paramValue;
}
}
throw new IllegalArgumentException("Zła wartość parametru dodatkowego w url" + parameter);
}
public void setPermissionMapping(HashMap<String, String> hashMap) {
this.permissionMapping = hashMap;
}
private boolean equalsAndNotNull(String stringA, String stringB) {
return stringA != null && stringA.equals(stringB);
}
private boolean nonStandardParameter(String paramName) {
try {
ExportParameterNameInRequest.valueOf(paramName);
} catch (Exception exc) {
return true;
}
return false;
}
}