View Javadoc

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