View Javadoc

1   /*
2    * $Id: JakartaMultiPartRequest.java 439747 2006-09-03 09:22:46Z mrdon $
3    *
4    * Copyright 2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts2.dispatcher.multipart;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.Enumeration;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import javax.servlet.http.HttpServletRequest;
31  
32  import org.apache.commons.fileupload.FileItem;
33  import org.apache.commons.fileupload.FileUploadException;
34  import org.apache.commons.fileupload.RequestContext;
35  import org.apache.commons.fileupload.disk.DiskFileItem;
36  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
37  import org.apache.commons.fileupload.servlet.ServletFileUpload;
38  
39  /***
40   * Multipart form data request adapter for Jakarta Commons Fileupload package.
41   *
42   */
43  public class JakartaMultiPartRequest extends MultiPartRequest {
44      // maps parameter name -> List of FileItem objects
45      private Map<String,List<FileItem>> files = new HashMap<String,List<FileItem>>();
46      // maps parameter name -> List of param values
47      private Map<String,List<String>> params = new HashMap<String,List<String>>();
48      // any errors while processing this request
49      private List<String> errors = new ArrayList<String>();
50  
51      /***
52       * Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's
53       * multipart classes (see class description).
54       *
55       * @param maxSize        maximum size post allowed
56       * @param saveDir        the directory to save off the file
57       * @param servletRequest the request containing the multipart
58       * @throws java.io.IOException  is thrown if encoding fails.
59       */
60      public JakartaMultiPartRequest(HttpServletRequest servletRequest, String saveDir, int maxSize)
61              throws IOException {
62          DiskFileItemFactory fac = new DiskFileItemFactory();
63          fac.setSizeThreshold(0);
64          if (saveDir != null) {
65              fac.setRepository(new File(saveDir));
66          }
67  
68          // Parse the request
69          try {
70              ServletFileUpload upload = new ServletFileUpload(fac);
71              List items = upload.parseRequest(createRequestContext(servletRequest));
72  
73              for (int i = 0; i < items.size(); i++) {
74                  FileItem item = (FileItem) items.get(i);
75                  if (log.isDebugEnabled()) log.debug("Found item " + item.getFieldName());
76                  if (item.isFormField()) {
77                      log.debug("Item is a normal form field");
78                      List<String> values;
79                      if (params.get(item.getFieldName()) != null) {
80                          values = params.get(item.getFieldName());
81                      } else {
82                          values = new ArrayList<String>();
83                      }
84  
85                      // note: see http://jira.opensymphony.com/browse/WW-633
86                      // basically, in some cases the charset may be null, so
87                      // we're just going to try to "other" method (no idea if this
88                      // will work)
89                      String charset = servletRequest.getCharacterEncoding();
90                      if (charset != null) {
91                          values.add(item.getString(charset));
92                      } else {
93                          values.add(item.getString());
94                      }
95                      params.put(item.getFieldName(), values);
96                  } else {
97                      log.debug("Item is a file upload");
98  
99                      List<FileItem> values;
100                     if (files.get(item.getFieldName()) != null) {
101                         values = files.get(item.getFieldName());
102                     } else {
103                         values = new ArrayList<FileItem>();
104                     }
105 
106                     values.add(item);
107                     files.put(item.getFieldName(), values);
108                 }
109             }
110         } catch (FileUploadException e) {
111             log.error(e);
112             errors.add(e.getMessage());
113         }
114     }
115 
116     /* (non-Javadoc)
117      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileParameterNames()
118      */
119     public Enumeration<String> getFileParameterNames() {
120         return Collections.enumeration(files.keySet());
121     }
122 
123     /* (non-Javadoc)
124      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getContentType(java.lang.String)
125      */
126     public String[] getContentType(String fieldName) {
127         List items = (List) files.get(fieldName);
128 
129         if (items == null) {
130             return null;
131         }
132 
133         List<String> contentTypes = new ArrayList<String>(items.size());
134         for (int i = 0; i < items.size(); i++) {
135             FileItem fileItem = (FileItem) items.get(i);
136             contentTypes.add(fileItem.getContentType());
137         }
138 
139         return (String[]) contentTypes.toArray(new String[contentTypes.size()]);
140     }
141 
142     /* (non-Javadoc)
143      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String)
144      */
145     public File[] getFile(String fieldName) {
146         List items = (List) files.get(fieldName);
147 
148         if (items == null) {
149             return null;
150         }
151 
152         List<File> fileList = new ArrayList<File>(items.size());
153         for (int i = 0; i < items.size(); i++) {
154             DiskFileItem fileItem = (DiskFileItem) items.get(i);
155             fileList.add(fileItem.getStoreLocation());
156         }
157 
158         return (File[]) fileList.toArray(new File[fileList.size()]);
159     }
160 
161     /* (non-Javadoc)
162      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileNames(java.lang.String)
163      */
164     public String[] getFileNames(String fieldName) {
165         List<FileItem> items = files.get(fieldName);
166 
167         if (items == null) {
168             return null;
169         }
170 
171         List<String> fileNames = new ArrayList<String>(items.size());
172         for (int i = 0; i < items.size(); i++) {
173             DiskFileItem fileItem = (DiskFileItem) items.get(i);
174             fileNames.add(getCanonicalName(fileItem.getName()));
175         }
176 
177         return (String[]) fileNames.toArray(new String[fileNames.size()]);
178     }
179 
180     /* (non-Javadoc)
181      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFilesystemName(java.lang.String)
182      */
183     public String[] getFilesystemName(String fieldName) {
184         List items = (List) files.get(fieldName);
185 
186         if (items == null) {
187             return null;
188         }
189 
190         List<String> fileNames = new ArrayList<String>(items.size());
191         for (int i = 0; i < items.size(); i++) {
192             DiskFileItem fileItem = (DiskFileItem) items.get(i);
193             fileNames.add(fileItem.getStoreLocation().getName());
194         }
195 
196         return (String[]) fileNames.toArray(new String[fileNames.size()]);
197     }
198 
199     /* (non-Javadoc)
200      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String)
201      */
202     public String getParameter(String name) {
203         List v = (List) params.get(name);
204         if (v != null && v.size() > 0) {
205             return (String) v.get(0);
206         }
207 
208         return null;
209     }
210 
211     /* (non-Javadoc)
212      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterNames()
213      */
214     public Enumeration<String> getParameterNames() {
215         return Collections.enumeration(params.keySet());
216     }
217 
218     /* (non-Javadoc)
219      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterValues(java.lang.String)
220      */
221     public String[] getParameterValues(String name) {
222         List<String> v = params.get(name);
223         if (v != null && v.size() > 0) {
224             return (String[]) v.toArray(new String[v.size()]);
225         }
226 
227         return null;
228     }
229 
230     /* (non-Javadoc)
231      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
232      */
233     public List getErrors() {
234         return errors;
235     }
236 
237     /***
238      * Returns the canonical name of the given file.
239      *
240      * @param filename  the given file
241      * @return the canonical name of the given file
242      */
243     private String getCanonicalName(String filename) {
244         int forwardSlash = filename.lastIndexOf("/");
245         int backwardSlash = filename.lastIndexOf("//");
246         if (forwardSlash != -1 && forwardSlash > backwardSlash) {
247             filename = filename.substring(forwardSlash + 1, filename.length());
248         } else if (backwardSlash != -1 && backwardSlash >= forwardSlash) {
249             filename = filename.substring(backwardSlash + 1, filename.length());
250         }
251 
252         return filename;
253     }
254 
255     /***
256      * Creates a RequestContext needed by Jakarta Commons Upload.
257      *
258      * @param req  the request.
259      * @return a new request context.
260      */
261     private RequestContext createRequestContext(final HttpServletRequest req) {
262         return new RequestContext() {
263             public String getCharacterEncoding() {
264                 return req.getCharacterEncoding();
265             }
266 
267             public String getContentType() {
268                 return req.getContentType();
269             }
270 
271             public int getContentLength() {
272                 return req.getContentLength();
273             }
274 
275             public InputStream getInputStream() throws IOException {
276                 return req.getInputStream();
277             }
278         };
279     }
280 
281 }