001 package de.deepamehta.plugins.files.provider; 002 003 import de.deepamehta.plugins.files.UploadedFile; 004 005 import org.apache.commons.fileupload.FileItem; 006 import org.apache.commons.fileupload.FileItemFactory; 007 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 008 import org.apache.commons.fileupload.servlet.ServletFileUpload; 009 010 import java.io.InputStream; 011 import java.io.IOException; 012 import java.lang.annotation.Annotation; 013 import java.lang.reflect.Type; 014 import java.util.List; 015 import java.util.logging.Logger; 016 017 import javax.servlet.http.HttpServletRequest; 018 019 import javax.ws.rs.WebApplicationException; 020 import javax.ws.rs.core.Context; 021 import javax.ws.rs.core.MediaType; 022 import javax.ws.rs.core.MultivaluedMap; 023 import javax.ws.rs.ext.MessageBodyReader; 024 import javax.ws.rs.ext.Provider; 025 026 027 028 @Provider 029 public class UploadedFileProvider implements MessageBodyReader<UploadedFile> { 030 031 // ---------------------------------------------------------------------------------------------- Instance Variables 032 033 @Context 034 private HttpServletRequest request; 035 036 private Logger logger = Logger.getLogger(getClass().getName()); 037 038 // -------------------------------------------------------------------------------------------------- Public Methods 039 040 // *** MessageBodyReader Implementation *** 041 042 @Override 043 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 044 // Note: unlike equals() isCompatible() ignores parameters like "charset" in "application/json;charset=UTF-8" 045 return type == UploadedFile.class && mediaType.isCompatible(MediaType.MULTIPART_FORM_DATA_TYPE); 046 } 047 048 @Override 049 public UploadedFile readFrom(Class<UploadedFile> type, Type genericType, Annotation[] annotations, 050 MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) 051 throws IOException, WebApplicationException { 052 try { 053 return parseMultiPart(); 054 } catch (Exception e) { 055 throw new RuntimeException("Creating UploadedFile from message body failed", e); 056 } 057 } 058 059 // ------------------------------------------------------------------------------------------------- Private Methods 060 061 private UploadedFile parseMultiPart() { 062 try { 063 UploadedFile file = null; 064 FileItemFactory factory = new DiskFileItemFactory(); // create a factory for disk-based file items 065 ServletFileUpload upload = new ServletFileUpload(factory); // create a new file upload handler 066 List<FileItem> items = upload.parseRequest(request); // parse the request 067 // FIXME: check if we can use a FileUpload low-level method to parse the request body instead of the 068 // entire request. Advantage: a) no need to inject the HttpServletRequest, b) no double work as the 069 // request is already parsed by jersey, c) no dependency on servlet-api. 070 logger.info("### Parsing multipart/form-data request (" + items.size() + " parts)"); 071 for (FileItem item : items) { 072 String fieldName = item.getFieldName(); 073 if (item.isFormField()) { 074 String value = item.getString(); 075 logger.info("### field \"" + fieldName + "\" => \"" + value + "\""); 076 throw new RuntimeException("\"" + fieldName + "\" is an unexpected field (value=\"" + value + 077 "\")"); 078 } else { 079 if (file != null) { 080 throw new RuntimeException("Only single file uploads are supported"); 081 } 082 file = new UploadedFile(item); 083 logger.info("### field \"" + fieldName + "\" => " + file); 084 } 085 } 086 if (file == null) { 087 throw new RuntimeException("Request does not contain a file part"); 088 } 089 return file; 090 } catch (Exception e) { 091 throw new RuntimeException("Parsing multipart/form-data request failed", e); 092 } 093 } 094 }