PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/main/java/org/gmr/web/multipart/GFileUploadSupport.java

http://gmultipart.googlecode.com/
Java | 303 lines | 129 code | 30 blank | 144 comment | 19 complexity | ea62d545e6942a021f391ae22d7ea910 MD5 | raw file
  1. /*
  2. * Copyright 2002-2008 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. package org.gmr.web.multipart;
  17. import java.io.UnsupportedEncodingException;
  18. import java.util.Collection;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. import org.apache.commons.fileupload.FileItem;
  23. import org.apache.commons.fileupload.FileItemFactory;
  24. import org.apache.commons.fileupload.FileUpload;
  25. import org.apache.commons.logging.Log;
  26. import org.apache.commons.logging.LogFactory;
  27. import org.springframework.util.LinkedMultiValueMap;
  28. import org.springframework.util.MultiValueMap;
  29. import org.springframework.util.StringUtils;
  30. import org.springframework.web.multipart.MultipartFile;
  31. import org.springframework.web.util.WebUtils;
  32. /**
  33. * <p>
  34. * Important Note: This src is modifed version of {@link org.springframework.web.multipart.CommonsFileUploadSupport} to
  35. * make it work in GAE.
  36. *
  37. * Base class for multipart resolvers that use Jakarta Commons FileUpload 1.1 or higher.
  38. *
  39. * <p>
  40. * Provides common configuration properties and parsing functionality for multipart requests, using a Map of Spring
  41. * GMultipartFile instances as representation of uploaded files and a String-based parameter Map as representation of
  42. * uploaded form fields.
  43. *
  44. * <p>
  45. * Subclasses implement concrete resolution strategies for Servlet environments: see GMultipartResolver. This base class
  46. * is not tied to those APIs, factoring out common functionality.
  47. *
  48. * @author kernel164
  49. * @author Juergen Hoeller
  50. * @see GMultipartFile
  51. * @see GMultipartResolver
  52. */
  53. public abstract class GFileUploadSupport {
  54. protected final Log logger = LogFactory.getLog(getClass());
  55. private final GFileItemFactory fileItemFactory;
  56. private final FileUpload fileUpload;
  57. /**
  58. * Instantiate a new GFileUploadSupport with its corresponding FileItemFactory and FileUpload instances.
  59. *
  60. * @see #newFileItemFactory
  61. * @see #newFileUpload
  62. */
  63. public GFileUploadSupport() {
  64. this.fileItemFactory = newFileItemFactory();
  65. this.fileUpload = newFileUpload(getFileItemFactory());
  66. }
  67. /**
  68. * Return the underlying <code>GFileItemFactory</code> instance. There is
  69. * hardly any need to access this.
  70. *
  71. * @return the underlying GFileItemFactory instance
  72. */
  73. public GFileItemFactory getFileItemFactory() {
  74. return this.fileItemFactory;
  75. }
  76. /**
  77. * Return the underlying <code>org.apache.commons.fileupload.FileUpload</code> instance. There is hardly any need to
  78. * access this.
  79. *
  80. * @return the underlying FileUpload instance
  81. */
  82. public FileUpload getFileUpload() {
  83. return this.fileUpload;
  84. }
  85. /**
  86. * Set the maximum allowed size (in bytes) before uploads are refused. -1 indicates no limit (the default).
  87. * Sets the maximum in memory thresold limit to max upload size.
  88. *
  89. * @param maxUploadSize the maximum upload size allowed
  90. * @see org.apache.commons.fileupload.FileUploadBase#setSizeMax
  91. * @see org.apache.commons.fileupload.FileItemFactory#setSizeThreshold
  92. */
  93. public void setMaxUploadSize(int maxUploadSize) {
  94. this.fileUpload.setSizeMax(maxUploadSize);
  95. this.fileItemFactory.setSizeThreshold(maxUploadSize);
  96. }
  97. /**
  98. * Set the default character encoding to use for parsing requests, to be applied to headers of individual parts and
  99. * to form fields. Default is ISO-8859-1, according to the Servlet spec.
  100. * <p>
  101. * If the request specifies a character encoding itself, the request encoding will override this setting. This also
  102. * allows for generically overriding the character encoding in a filter that invokes the
  103. * <code>ServletRequest.setCharacterEncoding</code> method.
  104. *
  105. * @param defaultEncoding the character encoding to use
  106. * @see javax.servlet.ServletRequest#getCharacterEncoding
  107. * @see javax.servlet.ServletRequest#setCharacterEncoding
  108. * @see WebUtils#DEFAULT_CHARACTER_ENCODING
  109. * @see org.apache.commons.fileupload.FileUploadBase#setHeaderEncoding
  110. */
  111. public void setDefaultEncoding(String defaultEncoding) {
  112. this.fileUpload.setHeaderEncoding(defaultEncoding);
  113. }
  114. /**
  115. * Returns the default encoding.
  116. *
  117. * @return the default encoding.
  118. */
  119. protected String getDefaultEncoding() {
  120. String encoding = getFileUpload().getHeaderEncoding();
  121. if (encoding == null) {
  122. encoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
  123. }
  124. return encoding;
  125. }
  126. /**
  127. * Factory method for a Commons GFileItemFactory instance.
  128. *
  129. * <p> Default implementation returns a standard GFileItemFactory. Can be overridden to use a custom subclass, e.g.
  130. * for testing purposes.
  131. *
  132. * @return the new DiskFileItemFactory instance
  133. */
  134. protected GFileItemFactory newFileItemFactory() {
  135. return new GFileItemFactory();
  136. }
  137. /**
  138. * Factory method for a Commons FileUpload instance.
  139. * <p>
  140. * <b>To be implemented by subclasses.</b>
  141. *
  142. * @param fileItemFactory the Commons FileItemFactory to build upon
  143. * @return the Commons FileUpload instance
  144. */
  145. protected abstract FileUpload newFileUpload(FileItemFactory fileItemFactory);
  146. /**
  147. * Determine an appropriate FileUpload instance for the given encoding.
  148. * <p>
  149. * Default implementation returns the shared FileUpload instance if the encoding matches, else creates a new
  150. * FileUpload instance with the same configuration other than the desired encoding.
  151. *
  152. * @param encoding the character encoding to use
  153. * @return an appropriate FileUpload instance.
  154. */
  155. protected FileUpload prepareFileUpload(String encoding) {
  156. FileUpload fileUpload = getFileUpload();
  157. FileUpload actualFileUpload = fileUpload;
  158. // Use new temporary FileUpload instance if the request specifies
  159. // its own encoding that does not match the default encoding.
  160. if (encoding != null && !encoding.equals(fileUpload.getHeaderEncoding())) {
  161. actualFileUpload = newFileUpload(getFileItemFactory());
  162. actualFileUpload.setSizeMax(fileUpload.getSizeMax());
  163. actualFileUpload.setHeaderEncoding(encoding);
  164. }
  165. return actualFileUpload;
  166. }
  167. /**
  168. * Parse the given List of Commons FileItems into a Spring MultipartParsingResult, containing Spring MultipartFile
  169. * instances and a Map of multipart parameter.
  170. *
  171. * @param fileItems the Commons FileIterms to parse
  172. * @param encoding the encoding to use for form fields
  173. * @return the Spring MultipartParsingResult
  174. * @see GMultipartFile#CommonsMultipartFile(org.apache.commons.fileupload.FileItem)
  175. */
  176. protected MultipartParsingResult parseFileItems(List<FileItem> fileItems, String encoding) {
  177. MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();
  178. Map<String, String[]> multipartParameters = new HashMap<String, String[]>();
  179. Map<String, String> multipartParameterContentTypes = new HashMap<String, String>();
  180. // Extract multipart files and multipart parameters.
  181. for (FileItem fileItem : fileItems) {
  182. if (fileItem.isFormField()) {
  183. String value = null;
  184. if (encoding != null) {
  185. try {
  186. value = fileItem.getString(encoding);
  187. } catch (UnsupportedEncodingException ex) {
  188. if (logger.isWarnEnabled()) {
  189. logger.warn("Could not decode multipart item '" + fileItem.getFieldName() + "' with encoding '" + encoding + "': using platform default");
  190. }
  191. value = fileItem.getString();
  192. }
  193. } else {
  194. value = fileItem.getString();
  195. }
  196. String[] curParam = multipartParameters.get(fileItem.getFieldName());
  197. if (curParam == null) {
  198. // simple form field
  199. multipartParameters.put(fileItem.getFieldName(), new String[] { value });
  200. } else {
  201. // array of simple form fields
  202. String[] newParam = StringUtils.addStringToArray(curParam, value);
  203. multipartParameters.put(fileItem.getFieldName(), newParam);
  204. }
  205. multipartParameterContentTypes.put(fileItem.getFieldName(), fileItem.getContentType());
  206. } else {
  207. // multipart file field
  208. GMultipartFile file = new GMultipartFile(fileItem);
  209. multipartFiles.add(file.getName(), file);
  210. if (logger.isDebugEnabled()) {
  211. logger.debug("Found multipart file [" + file.getName() + "] of size " + file.getSize() +
  212. " bytes with original filename [" + file.getOriginalFilename() + "], stored " +
  213. file.getStorageDescription());
  214. }
  215. }
  216. }
  217. return new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes);
  218. }
  219. /**
  220. * Cleanup the Spring MultipartFiles created during multipart parsing.
  221. * <p>
  222. * Deletes the underlying Commons FileItem instances.
  223. *
  224. * @param multipartFiles Collection of MultipartFile instances
  225. * @see org.apache.commons.fileupload.FileItem#delete()
  226. */
  227. protected void cleanupFileItems(Collection<MultipartFile> multipartFiles) {
  228. for (MultipartFile file : multipartFiles) {
  229. if (file instanceof GMultipartFile) {
  230. GMultipartFile cmf = (GMultipartFile) file;
  231. cmf.getFileItem().delete();
  232. if (logger.isDebugEnabled()) {
  233. logger.debug("Cleaning up multipart file [" + cmf.getName() + "] with original filename [" + cmf.getOriginalFilename() + "], stored " + cmf.getStorageDescription());
  234. }
  235. }
  236. }
  237. }
  238. /**
  239. * Holder for a Map of Spring MultipartFiles and a Map of multipart parameters.
  240. */
  241. protected static class MultipartParsingResult {
  242. private final MultiValueMap<String, MultipartFile> multipartFiles;
  243. private final Map<String, String[]> multipartParameters;
  244. private final Map<String, String> multipartParameterContentTypes;
  245. /**
  246. * Create a new MultipartParsingResult.
  247. *
  248. * @param mpFiles Map of field name to MultipartFile instance
  249. * @param mpParams Map of field name to form field String value
  250. */
  251. public MultipartParsingResult(MultiValueMap<String, MultipartFile> mpFiles, Map<String, String[]> mpParams,
  252. Map<String, String> mpParamContentTypes) {
  253. this.multipartFiles = mpFiles;
  254. this.multipartParameters = mpParams;
  255. this.multipartParameterContentTypes = mpParamContentTypes;
  256. }
  257. /**
  258. * Return the multipart files as Map of field name to MultipartFile instance.
  259. */
  260. public MultiValueMap<String, MultipartFile> getMultipartFiles() {
  261. return this.multipartFiles;
  262. }
  263. /**
  264. * Return the multipart parameters as Map of field name to form field String value.
  265. */
  266. public Map<String, String[]> getMultipartParameters() {
  267. return this.multipartParameters;
  268. }
  269. public Map<String, String> getMultipartParameterContentTypes() {
  270. return this.multipartParameterContentTypes;
  271. }
  272. }
  273. }