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.commons.util.CollectionFactory; 022import org.apache.tapestry5.http.TapestryHttpSymbolConstants; 023import org.apache.tapestry5.ioc.annotations.Symbol; 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(TapestryHttpSymbolConstants.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 protected List<FileItem> parseRequest(HttpServletRequest request) 103 { 104 try 105 { 106 return createFileUpload().parseRequest(request); 107 } catch (FileUploadException ex) 108 { 109 uploadException = ex; 110 111 return Collections.emptyList(); 112 } 113 } 114 115 protected ServletFileUpload createFileUpload() 116 { 117 ServletFileUpload upload = new ServletFileUpload(fileItemFactory); 118 119 // set maximum file upload size 120 upload.setSizeMax(maxRequestSize); 121 upload.setFileSizeMax(maxFileSize); 122 123 return upload; 124 } 125 126 protected HttpServletRequest processFileItems(HttpServletRequest request, List<FileItem> fileItems) 127 { 128 if (uploadException == null && fileItems.isEmpty()) 129 { 130 return request; 131 } 132 133 ParametersServletRequestWrapper wrapper = new ParametersServletRequestWrapper(request); 134 135 // First add parameters from the request 136 for (Map.Entry<String, String[]> e : request.getParameterMap().entrySet()) 137 { 138 for (String s : e.getValue()) 139 wrapper.addParameter(e.getKey(), s); 140 } 141 142 for (FileItem item : fileItems) 143 { 144 if (item.isFormField()) 145 { 146 String fieldValue; 147 148 try 149 { 150 151 fieldValue = item.getString(requestEncoding); 152 } catch (UnsupportedEncodingException ex) 153 { 154 throw new RuntimeException(ex); 155 } 156 157 wrapper.addParameter(item.getFieldName(), fieldValue); 158 } else 159 { 160 wrapper.addParameter(item.getFieldName(), item.getName()); 161 addUploadedFile(item.getFieldName(), new UploadedFileItem(item)); 162 } 163 } 164 165 return wrapper; 166 } 167 168 protected void addUploadedFile(String name, UploadedFileItem file) 169 { 170 uploads.put(name, file); 171 } 172 173 @Override 174 public FileUploadException getUploadException() 175 { 176 return uploadException; 177 } 178}