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 }