package fr.openwide.core.wicket.more.fileapi.resource; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException; import org.apache.commons.fileupload.FileUploadException; import org.apache.wicket.injection.Injector; import org.apache.wicket.protocol.http.servlet.MultipartServletWebRequest; import org.apache.wicket.protocol.http.servlet.ServletWebRequest; import org.apache.wicket.request.http.flow.AbortWithHttpErrorCodeException; import org.apache.wicket.request.resource.AbstractResource; import org.apache.wicket.util.lang.Bytes; import org.apache.wicket.util.string.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import fr.openwide.core.wicket.more.fileapi.behavior.FileUploadBehavior; import fr.openwide.core.wicket.more.fileapi.model.FileApiFile; /** * From https://github.com/martin-g/blogs/tree/master/file-upload * * The resource that handles the file uploads. Reads the file items from the * request parameters and uses FileManager to store them. Additionally cares * about the response's content type and body. */ public abstract class AbstractFileUploadResource extends AbstractResource { private static final long serialVersionUID = 7699763145818556913L; private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileUploadResource.class); public AbstractFileUploadResource() { super(); Injector.get().inject(this); } /** * Defines what is the maximum size of the uploaded files. * * @return */ protected abstract Bytes getMaxSize(); /** * Delegates to store the uploaded files * * @param fileItems * @throws IOException */ protected abstract void saveFiles(Attributes attributes, List<FileApiFile> identifiers, List<FileItem> fileItems, List<FileApiFile> successFiles, List<FileApiFile> errorFiles) throws IOException; /** * Reads and stores the uploaded files * * @param attributes * @return */ @Override protected ResourceResponse newResourceResponse(Attributes attributes) { final ResourceResponse resourceResponse = new ResourceResponse(); final ServletWebRequest webRequest = (ServletWebRequest) attributes.getRequest(); try { MultipartServletWebRequest multiPartRequest; try { multiPartRequest = webRequest.newMultipartWebRequest(getMaxSize(), "ignored"); multiPartRequest.parseFileParts(); } catch (SizeLimitExceededException fileLimitException) { // cas où la limite globale d'upload est dépassée String responseContent = generateJsonFileSizeErrorResponse(resourceResponse, webRequest); prepareResponse(resourceResponse, webRequest, responseContent); return resourceResponse; } catch (FileUploadException e) { // peut arriver dans le cas du cancel LOGGER.info("An error occurred while uploading a file", e); prepareResponse(resourceResponse, webRequest, null); return resourceResponse; } Map<String, List<FileItem>> files = multiPartRequest.getFiles(); List<FileItem> fileItems = files.get(FileUploadBehavior.PARAMETERS_FILE_UPLOAD); List<FileApiFile> fileApiFiles = FileUploadBehavior.readFileApiFiles(multiPartRequest.getRequestParameters()); if (fileApiFiles.size() != fileItems.size()) { throw new IllegalStateException("Files and uploaded files list size inconsistent"); } List<FileApiFile> successFiles = Lists.newArrayList(); List<FileApiFile> errorFiles = Lists.newArrayList(); saveFiles(attributes, fileApiFiles, fileItems, successFiles, errorFiles); String responseContent = generateJsonResponse(resourceResponse, webRequest, fileItems, successFiles, errorFiles); prepareResponse(resourceResponse, webRequest, responseContent); } catch (RuntimeException | FileUploadException | IOException fux) { LOGGER.error("An error occurred while uploading a file", fux); throw new AbortWithHttpErrorCodeException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fux.getMessage()); } return resourceResponse; } /** * Sets the response's content type and body * * @param resourceResponse * @param webRequest * @param fileItems * @throws FileUploadException * @throws IOException */ protected void prepareResponse(ResourceResponse resourceResponse, ServletWebRequest webRequest, final String responseContent) throws FileUploadException, IOException { resourceResponse.setContentType("application/json"); resourceResponse.setWriteCallback(new WriteCallback() { @Override public void writeData(Attributes attributes) throws IOException { attributes.getResponse().write(responseContent); } }); } /** * Decides what should be the response's content type depending on the * 'Accept' request header. HTML5 browsers work with "application/json", * older ones use IFrame to make the upload and the response should be HTML. * Read http://blueimp.github.com/jQuery-File-Upload/ docs for more info. * * @param acceptHeader * @return */ protected boolean wantsHtml(String acceptHeader) { return !Strings.isEmpty(acceptHeader) && acceptHeader.contains("text/html"); } /** * Should generate the response's body in JSON format * * @param resourceResponse * @param webRequest * @param files * @return * @throws JsonProcessingException */ protected String generateJsonResponse(ResourceResponse resourceResponse, ServletWebRequest webRequest, List<FileItem> files, List<FileApiFile> successFiles, List<FileApiFile> errorFiles) throws JsonProcessingException { HashMap<String, Object> response = Maps.newHashMap(); response.put("successFileList", successFiles); response.put("errorFileList", errorFiles); try { return FileUploadBehavior.OBJECT_MAPPER.writeValueAsString(response); } catch (JsonProcessingException e) { LOGGER.error("Erreur de sérialisation d'une réponse d'upload", e); throw e; } } protected String generateJsonFileSizeErrorResponse(ResourceResponse resourceResponse, ServletWebRequest webRequest) throws JsonProcessingException { HashMap<String, Object> response = Maps.newHashMap(); response.put("uploadFailsErrorMessage", getFileSizeErrorMessage()); try { return FileUploadBehavior.OBJECT_MAPPER.writeValueAsString(response); } catch (JsonProcessingException e) { LOGGER.error("Erreur de sérialisation d'une réponse d'upload", e); throw e; } } protected abstract String getFileSizeErrorMessage(); }