001 // Copyright 2007, 2008, 2010, 2011 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry5.upload.internal.services; 016 017 import org.apache.commons.fileupload.FileItem; 018 import org.apache.commons.fileupload.FileItemFactory; 019 import org.apache.commons.fileupload.FileUploadException; 020 import org.apache.commons.fileupload.servlet.ServletFileUpload; 021 import org.apache.tapestry5.SymbolConstants; 022 import org.apache.tapestry5.ioc.annotations.Symbol; 023 import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 024 import org.apache.tapestry5.ioc.services.ThreadCleanupListener; 025 import org.apache.tapestry5.upload.services.MultipartDecoder; 026 import org.apache.tapestry5.upload.services.UploadSymbols; 027 import org.apache.tapestry5.upload.services.UploadedFile; 028 029 import javax.servlet.http.HttpServletRequest; 030 import java.io.UnsupportedEncodingException; 031 import java.util.Collections; 032 import java.util.List; 033 import java.util.Map; 034 035 /** 036 * Implementation of multipart decoder for servlets. This implementation is perthread scope. 037 */ 038 public class MultipartDecoderImpl implements MultipartDecoder, ThreadCleanupListener 039 { 040 private final Map<String, UploadedFileItem> uploads = CollectionFactory.newMap(); 041 042 private final FileItemFactory fileItemFactory; 043 044 private final long maxRequestSize; 045 046 private final long maxFileSize; 047 048 private final String requestEncoding; 049 050 private FileUploadException uploadException; 051 052 public MultipartDecoderImpl( 053 054 FileItemFactory fileItemFactory, 055 056 @Symbol(UploadSymbols.REQUESTSIZE_MAX) 057 long maxRequestSize, 058 059 @Symbol(UploadSymbols.FILESIZE_MAX) 060 long maxFileSize, 061 062 @Symbol(SymbolConstants.CHARSET) 063 String requestEncoding) 064 { 065 this.fileItemFactory = fileItemFactory; 066 this.maxRequestSize = maxRequestSize; 067 this.maxFileSize = maxFileSize; 068 this.requestEncoding = requestEncoding; 069 } 070 071 public UploadedFile getFileUpload(String parameterName) 072 { 073 return uploads.get(parameterName); 074 } 075 076 public HttpServletRequest decode(HttpServletRequest request) 077 { 078 try 079 { 080 request.setCharacterEncoding(requestEncoding); 081 } catch (UnsupportedEncodingException ex) 082 { 083 throw new RuntimeException(ex); 084 } 085 086 List<FileItem> fileItems = parseRequest(request); 087 088 return processFileItems(request, fileItems); 089 } 090 091 public void threadDidCleanup() 092 { 093 for (UploadedFileItem uploaded : uploads.values()) 094 { 095 uploaded.cleanup(); 096 } 097 } 098 099 @SuppressWarnings("unchecked") 100 protected List<FileItem> parseRequest(HttpServletRequest request) 101 { 102 try 103 { 104 return createFileUpload().parseRequest(request); 105 } catch (FileUploadException ex) 106 { 107 uploadException = ex; 108 109 return Collections.emptyList(); 110 } 111 } 112 113 protected ServletFileUpload createFileUpload() 114 { 115 ServletFileUpload upload = new ServletFileUpload(fileItemFactory); 116 117 // set maximum file upload size 118 upload.setSizeMax(maxRequestSize); 119 upload.setFileSizeMax(maxFileSize); 120 121 return upload; 122 } 123 124 protected HttpServletRequest processFileItems(HttpServletRequest request, List<FileItem> fileItems) 125 { 126 if (uploadException == null && fileItems.isEmpty()) 127 { 128 return request; 129 } 130 131 ParametersServletRequestWrapper wrapper = new ParametersServletRequestWrapper(request); 132 133 // First add parameters from the request 134 for (Object e : request.getParameterMap().entrySet()) 135 { 136 Map.Entry<String, String[]> ee = (Map.Entry<String, String[]>) e; 137 for (String s : ee.getValue()) 138 wrapper.addParameter(ee.getKey(), s); 139 } 140 141 for (FileItem item : fileItems) 142 { 143 if (item.isFormField()) 144 { 145 String fieldValue; 146 147 try 148 { 149 150 fieldValue = item.getString(requestEncoding); 151 } catch (UnsupportedEncodingException ex) 152 { 153 throw new RuntimeException(ex); 154 } 155 156 wrapper.addParameter(item.getFieldName(), fieldValue); 157 } else 158 { 159 wrapper.addParameter(item.getFieldName(), item.getName()); 160 addUploadedFile(item.getFieldName(), new UploadedFileItem(item)); 161 } 162 } 163 164 return wrapper; 165 } 166 167 protected void addUploadedFile(String name, UploadedFileItem file) 168 { 169 uploads.put(name, file); 170 } 171 172 public FileUploadException getUploadException() 173 { 174 return uploadException; 175 } 176 }