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 015package org.apache.tapestry5.upload.internal.services; 016 017import org.apache.commons.fileupload.FileItem; 018import org.apache.commons.fileupload.FileItemFactory; 019import org.apache.commons.fileupload.FileUploadException; 020import org.apache.commons.fileupload.servlet.ServletFileUpload; 021import org.apache.tapestry5.SymbolConstants; 022import org.apache.tapestry5.ioc.annotations.Symbol; 023import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 024import org.apache.tapestry5.ioc.services.ThreadCleanupListener; 025import org.apache.tapestry5.upload.services.MultipartDecoder; 026import org.apache.tapestry5.upload.services.UploadSymbols; 027import org.apache.tapestry5.upload.services.UploadedFile; 028 029import javax.servlet.http.HttpServletRequest; 030import java.io.UnsupportedEncodingException; 031import java.util.Collections; 032import java.util.List; 033import java.util.Map; 034 035/** 036 * Implementation of multipart decoder for servlets. This implementation is perthread scope. 037 */ 038public 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 @Override 072 public UploadedFile getFileUpload(String parameterName) 073 { 074 return uploads.get(parameterName); 075 } 076 077 @Override 078 public HttpServletRequest decode(HttpServletRequest request) 079 { 080 try 081 { 082 request.setCharacterEncoding(requestEncoding); 083 } catch (UnsupportedEncodingException ex) 084 { 085 throw new RuntimeException(ex); 086 } 087 088 List<FileItem> fileItems = parseRequest(request); 089 090 return processFileItems(request, fileItems); 091 } 092 093 @Override 094 public void threadDidCleanup() 095 { 096 for (UploadedFileItem uploaded : uploads.values()) 097 { 098 uploaded.cleanup(); 099 } 100 } 101 102 @SuppressWarnings("unchecked") 103 protected List<FileItem> parseRequest(HttpServletRequest request) 104 { 105 try 106 { 107 return createFileUpload().parseRequest(request); 108 } catch (FileUploadException ex) 109 { 110 uploadException = ex; 111 112 return Collections.emptyList(); 113 } 114 } 115 116 protected ServletFileUpload createFileUpload() 117 { 118 ServletFileUpload upload = new ServletFileUpload(fileItemFactory); 119 120 // set maximum file upload size 121 upload.setSizeMax(maxRequestSize); 122 upload.setFileSizeMax(maxFileSize); 123 124 return upload; 125 } 126 127 protected HttpServletRequest processFileItems(HttpServletRequest request, List<FileItem> fileItems) 128 { 129 if (uploadException == null && fileItems.isEmpty()) 130 { 131 return request; 132 } 133 134 ParametersServletRequestWrapper wrapper = new ParametersServletRequestWrapper(request); 135 136 // First add parameters from the request 137 for (Object e : request.getParameterMap().entrySet()) 138 { 139 Map.Entry<String, String[]> ee = (Map.Entry<String, String[]>) e; 140 for (String s : ee.getValue()) 141 wrapper.addParameter(ee.getKey(), s); 142 } 143 144 for (FileItem item : fileItems) 145 { 146 if (item.isFormField()) 147 { 148 String fieldValue; 149 150 try 151 { 152 153 fieldValue = item.getString(requestEncoding); 154 } catch (UnsupportedEncodingException ex) 155 { 156 throw new RuntimeException(ex); 157 } 158 159 wrapper.addParameter(item.getFieldName(), fieldValue); 160 } else 161 { 162 wrapper.addParameter(item.getFieldName(), item.getName()); 163 addUploadedFile(item.getFieldName(), new UploadedFileItem(item)); 164 } 165 } 166 167 return wrapper; 168 } 169 170 protected void addUploadedFile(String name, UploadedFileItem file) 171 { 172 uploads.put(name, file); 173 } 174 175 @Override 176 public FileUploadException getUploadException() 177 { 178 return uploadException; 179 } 180}