KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > multipart > commons > CommonsFileUploadSupport


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.multipart.commons;
18
19 import java.io.IOException JavaDoc;
20 import java.io.UnsupportedEncodingException JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import org.apache.commons.fileupload.FileItem;
28 import org.apache.commons.fileupload.FileItemFactory;
29 import org.apache.commons.fileupload.FileUpload;
30 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import org.springframework.core.io.Resource;
35 import org.springframework.util.StringUtils;
36 import org.springframework.web.util.WebUtils;
37
38 /**
39  * Base class for multipart resolvers that use Jakarta Commons FileUpload
40  * 1.1 or higher.
41  *
42  * <p>Provides common configuration properties and parsing functionality
43  * for multipart requests, using a Map of Spring CommonsMultipartFile instances
44  * as representation of uploaded files and a String-based parameter Map as
45  * representation of uploaded form fields.
46  *
47  * <p>Subclasses implement concrete resolution strategies for Servlet or Portlet
48  * environments: see CommonsMultipartResolver and CommonsPortletMultipartResolver,
49  * respectively. This base class is not tied to either of those APIs, factoring
50  * out common functionality.
51  *
52  * @author Juergen Hoeller
53  * @since 2.0
54  * @see CommonsMultipartFile
55  * @see CommonsMultipartResolver
56  * @see org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver
57  */

58 public abstract class CommonsFileUploadSupport {
59
60     protected final Log logger = LogFactory.getLog(getClass());
61
62     private final DiskFileItemFactory fileItemFactory;
63
64     private final FileUpload fileUpload;
65
66     private boolean uploadTempDirSpecified = false;
67
68
69     /**
70      * Instantiate a new CommonsFileUploadSupport with its
71      * corresponding FileItemFactory and FileUpload instances.
72      * @see #newFileItemFactory
73      * @see #newFileUpload
74      */

75     public CommonsFileUploadSupport() {
76         this.fileItemFactory = newFileItemFactory();
77         this.fileUpload = newFileUpload(getFileItemFactory());
78     }
79
80
81     /**
82      * Return the underlying <code>org.apache.commons.fileupload.disk.DiskFileItemFactory</code>
83      * instance. There is hardly any need to access this.
84      * @return the underlying DiskFileItemFactory instance
85      */

86     public DiskFileItemFactory getFileItemFactory() {
87         return fileItemFactory;
88     }
89
90     /**
91      * Return the underlying <code>org.apache.commons.fileupload.FileUpload</code>
92      * instance. There is hardly any need to access this.
93      * @return the underlying FileUpload instance
94      */

95     public FileUpload getFileUpload() {
96         return fileUpload;
97     }
98
99     /**
100      * Set the maximum allowed size (in bytes) before uploads are refused.
101      * -1 indicates no limit (the default).
102      * @param maxUploadSize the maximum upload size allowed
103      * @see org.apache.commons.fileupload.FileUploadBase#setSizeMax
104      */

105     public void setMaxUploadSize(long maxUploadSize) {
106         this.fileUpload.setSizeMax(maxUploadSize);
107     }
108
109     /**
110      * Set the maximum allowed size (in bytes) before uploads are written to disk.
111      * Uploaded files will still be received past this amount, but they will not be
112      * stored in memory. Default is 10240, according to Commons FileUpload.
113      * @param maxInMemorySize the maximum in memory size allowed
114      * @see org.apache.commons.fileupload.disk.DiskFileItemFactory#setSizeThreshold
115      */

116     public void setMaxInMemorySize(int maxInMemorySize) {
117         this.fileItemFactory.setSizeThreshold(maxInMemorySize);
118     }
119
120     /**
121      * Set the default character encoding to use for parsing requests,
122      * to be applied to headers of individual parts and to form fields.
123      * Default is ISO-8859-1, according to the Servlet spec.
124      * <p>If the request specifies a character encoding itself, the request
125      * encoding will override this setting. This also allows for generically
126      * overriding the character encoding in a filter that invokes the
127      * <code>ServletRequest.setCharacterEncoding</code> method.
128      * @param defaultEncoding the character encoding to use
129      * @see javax.servlet.ServletRequest#getCharacterEncoding
130      * @see javax.servlet.ServletRequest#setCharacterEncoding
131      * @see WebUtils#DEFAULT_CHARACTER_ENCODING
132      * @see org.apache.commons.fileupload.FileUploadBase#setHeaderEncoding
133      */

134     public void setDefaultEncoding(String JavaDoc defaultEncoding) {
135         this.fileUpload.setHeaderEncoding(defaultEncoding);
136     }
137
138     protected String JavaDoc getDefaultEncoding() {
139         String JavaDoc encoding = getFileUpload().getHeaderEncoding();
140         if (encoding == null) {
141             encoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
142         }
143         return encoding;
144     }
145
146     /**
147      * Set the temporary directory where uploaded files get stored.
148      * Default is the servlet container's temporary directory for the web application.
149      * @see org.springframework.web.util.WebUtils#TEMP_DIR_CONTEXT_ATTRIBUTE
150      */

151     public void setUploadTempDir(Resource uploadTempDir) throws IOException JavaDoc {
152         if (!uploadTempDir.exists() && !uploadTempDir.getFile().mkdirs()) {
153             throw new IllegalArgumentException JavaDoc("Given uploadTempDir [" + uploadTempDir + "] could not be created");
154         }
155         this.fileItemFactory.setRepository(uploadTempDir.getFile());
156         this.uploadTempDirSpecified = true;
157     }
158
159     protected boolean isUploadTempDirSpecified() {
160         return uploadTempDirSpecified;
161     }
162
163
164     /**
165      * Factory method for a Commons DiskFileItemFactory instance.
166      * <p>Default implementation returns a standard DiskFileItemFactory.
167      * Can be overridden to use a custom subclass, e.g. for testing purposes.
168      * @return the new DiskFileItemFactory instance
169      */

170     protected DiskFileItemFactory newFileItemFactory() {
171         return new DiskFileItemFactory();
172     }
173
174     /**
175      * Factory method for a Commons FileUpload instance.
176      * <p><b>To be implemented by subclasses.</b>
177      * @param fileItemFactory the Commons FileItemFactory to build upon
178      * @return the Commons FileUpload instance
179      */

180     protected abstract FileUpload newFileUpload(FileItemFactory fileItemFactory);
181
182
183     /**
184      * Determine an appropriate FileUpload instance for the given encoding.
185      * <p>Default implementation returns the shared FileUpload instance
186      * if the encoding matches, else creates a new FileUpload instance
187      * with the same configuration other than the desired encoding.
188      * @param encoding the character encoding to use
189      * @return an appropriate FileUpload instance.
190      */

191     protected FileUpload prepareFileUpload(String JavaDoc encoding) {
192         FileUpload fileUpload = getFileUpload();
193         FileUpload actualFileUpload = fileUpload;
194
195         // Use new temporary FileUpload instance if the request specifies
196
// its own encoding that does not match the default encoding.
197
if (encoding != null && !encoding.equals(fileUpload.getHeaderEncoding())) {
198             actualFileUpload = newFileUpload(getFileItemFactory());
199             actualFileUpload.setSizeMax(fileUpload.getSizeMax());
200             actualFileUpload.setHeaderEncoding(encoding);
201         }
202
203         return actualFileUpload;
204     }
205
206     /**
207      * Parse the given List of Commons FileItems into a Spring MultipartParsingResult,
208      * containing Spring MultipartFile instances and a Map of multipart parameter.
209      * @param fileItems the Commons FileIterms to parse
210      * @param encoding the encoding to use for form fields
211      * @return the Spring MultipartParsingResult
212      * @see CommonsMultipartFile#CommonsMultipartFile(org.apache.commons.fileupload.FileItem)
213      */

214     protected MultipartParsingResult parseFileItems(List JavaDoc fileItems, String JavaDoc encoding) {
215         Map JavaDoc multipartFiles = new HashMap JavaDoc();
216         Map JavaDoc multipartParameters = new HashMap JavaDoc();
217
218         // Extract multipart files and multipart parameters.
219
for (Iterator JavaDoc it = fileItems.iterator(); it.hasNext();) {
220             FileItem fileItem = (FileItem) it.next();
221             if (fileItem.isFormField()) {
222                 String JavaDoc value = null;
223                 if (encoding != null) {
224                     try {
225                         value = fileItem.getString(encoding);
226                     }
227                     catch (UnsupportedEncodingException JavaDoc ex) {
228                         if (logger.isWarnEnabled()) {
229                             logger.warn("Could not decode multipart item '" + fileItem.getFieldName() +
230                                     "' with encoding '" + encoding + "': using platform default");
231                         }
232                         value = fileItem.getString();
233                     }
234                 }
235                 else {
236                     value = fileItem.getString();
237                 }
238                 String JavaDoc[] curParam = (String JavaDoc[]) multipartParameters.get(fileItem.getFieldName());
239                 if (curParam == null) {
240                     // simple form field
241
multipartParameters.put(fileItem.getFieldName(), new String JavaDoc[] { value });
242                 }
243                 else {
244                     // array of simple form fields
245
String JavaDoc[] newParam = StringUtils.addStringToArray(curParam, value);
246                     multipartParameters.put(fileItem.getFieldName(), newParam);
247                 }
248             }
249             else {
250                 // multipart file field
251
CommonsMultipartFile file = new CommonsMultipartFile(fileItem);
252                 multipartFiles.put(file.getName(), file);
253                 if (logger.isDebugEnabled()) {
254                     logger.debug("Found multipart file [" + file.getName() + "] of size " + file.getSize() +
255                             " bytes with original filename [" + file.getOriginalFilename() + "], stored " +
256                             file.getStorageDescription());
257                 }
258             }
259         }
260         return new MultipartParsingResult(multipartFiles, multipartParameters);
261     }
262
263     /**
264      * Cleanup the Spring MultipartFiles created during multipart parsing,
265      * potentially holding temporary data on disk.
266      * <p>Deletes the underlying Commons FileItem instances.
267      * @param multipartFiles Collection of MultipartFile instances
268      * @see org.apache.commons.fileupload.FileItem#delete()
269      */

270     protected void cleanupFileItems(Collection JavaDoc multipartFiles) {
271         for (Iterator JavaDoc it = multipartFiles.iterator(); it.hasNext();) {
272             CommonsMultipartFile file = (CommonsMultipartFile) it.next();
273             if (logger.isDebugEnabled()) {
274                 logger.debug("Cleaning up multipart file [" + file.getName() + "] with original filename [" +
275                         file.getOriginalFilename() + "], stored " + file.getStorageDescription());
276             }
277             file.getFileItem().delete();
278         }
279     }
280
281
282     /**
283      * Holder for a Map of Spring MultipartFiles and a Map of
284      * multipart parameters.
285      */

286     protected static class MultipartParsingResult {
287
288         private final Map JavaDoc multipartFiles;
289
290         private final Map JavaDoc multipartParameters;
291
292         /**
293          * Create a new MultipartParsingResult.
294          * @param multipartFiles Map of field name to MultipartFile instance
295          * @param multipartParameters Map of field name to form field String value
296          */

297         public MultipartParsingResult(Map JavaDoc multipartFiles, Map JavaDoc multipartParameters) {
298             this.multipartFiles = multipartFiles;
299             this.multipartParameters = multipartParameters;
300         }
301
302         /**
303          * Return the multipart files as Map of field name to MultipartFile instance.
304          */

305         public Map JavaDoc getMultipartFiles() {
306             return multipartFiles;
307         }
308
309         /**
310          * Return the multipart parameters as Map of field name to form field String value.
311          */

312         public Map JavaDoc getMultipartParameters() {
313             return multipartParameters;
314         }
315     }
316
317 }
318
Popular Tags