View Javadoc

1   /*
2    * $Id: MultiPartRequestWrapper.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.lang.reflect.Constructor;
22  import java.lang.reflect.InvocationTargetException;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Enumeration;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.Map;
29  import java.util.Vector;
30  
31  import javax.servlet.http.HttpServletRequest;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.struts2.StrutsConstants;
36  import org.apache.struts2.config.Settings;
37  import org.apache.struts2.dispatcher.StrutsRequestWrapper;
38  import org.apache.struts2.util.ClassLoaderUtils;
39  
40  
41  /***
42   * Parses a multipart request and provides a wrapper around the request. The parsing implementation used
43   * depends on the <tt>struts.multipart.parser</tt> setting. It should be set to a class which
44   * extends {@link org.apache.struts2.dispatcher.multipart.MultiPartRequest}. <p>
45   * <p/>
46   * Struts ships with three implementations,
47   * {@link org.apache.struts2.dispatcher.multipart.PellMultiPartRequest}, and
48   * {@link org.apache.struts2.dispatcher.multipart.CosMultiPartRequest} and
49   * {@link org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest}. The Jakarta implementation
50   * is the default. The <tt>struts.multipart.parser</tt> property should be set to <tt>jakarta</tt> for the
51   * Jakarta implementation, <tt>pell</tt> for the Pell implementation and <tt>cos</tt> for the Jason Hunter
52   * implementation. <p>
53   * <p/>
54   * The files are uploaded when the object is instantiated. If there are any errors they are logged using
55   * {@link #addError(String)}. An action handling a multipart form should first check {@link #hasErrors()}
56   * before doing any other processing. <p>
57   *
58   */
59  public class MultiPartRequestWrapper extends StrutsRequestWrapper {
60      protected static final Log log = LogFactory.getLog(MultiPartRequestWrapper.class);
61  
62      Collection errors;
63      MultiPartRequest multi;
64  
65      /***
66       * Instantiates the appropriate MultiPartRequest parser implementation and processes the data.
67       *
68       * @param request the servlet request object
69       * @param saveDir directory to save the file(s) to
70       * @param maxSize maximum file size allowed
71       */
72      public MultiPartRequestWrapper(HttpServletRequest request, String saveDir, int maxSize) {
73          super(request);
74  
75          if (request instanceof MultiPartRequest) {
76              multi = (MultiPartRequest) request;
77          } else {
78              String parser = Settings.get(StrutsConstants.STRUTS_MULTIPART_PARSER);
79  
80              // If it's not set, use Jakarta
81              if (parser.equals("")) {
82                  log.warn("Property struts.multipart.parser not set." +
83                          " Using org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest");
84                  parser = "org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest";
85              }
86              // legacy support for old style property values
87              else if (parser.equals("pell")) {
88                  parser = "org.apache.struts2.dispatcher.multipart.PellMultiPartRequest";
89              } else if (parser.equals("cos")) {
90                  parser = "org.apache.struts2.dispatcher.multipart.CosMultiPartRequest";
91              } else if (parser.equals("jakarta")) {
92                  parser = "org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest";
93              }
94  
95              try {
96                  Class baseClazz = org.apache.struts2.dispatcher.multipart.MultiPartRequest.class;
97  
98                  Class clazz = ClassLoaderUtils.loadClass(parser, MultiPartRequestWrapper.class);
99  
100                 // make sure it extends MultiPartRequest
101                 if (!baseClazz.isAssignableFrom(clazz)) {
102                     addError("Class '" + parser + "' does not extend MultiPartRequest");
103 
104                     return;
105                 }
106 
107                 // get the constructor
108                 Constructor ctor = clazz.getDeclaredConstructor(new Class[]{
109                         ClassLoaderUtils.loadClass("javax.servlet.http.HttpServletRequest", MultiPartRequestWrapper.class),
110                         java.lang.String.class, int.class
111                 });
112 
113                 // build the parameter list
114                 Object[] parms = new Object[]{
115                         request, saveDir, new Integer(maxSize)
116                 };
117 
118                 // instantiate it
119                 multi = (MultiPartRequest) ctor.newInstance(parms);
120                 for (Iterator iter = multi.getErrors().iterator(); iter.hasNext();) {
121                     String error = (String) iter.next();
122                     addError(error);
123                 }
124             } catch (ClassNotFoundException e) {
125                 addError("Class: " + parser + " not found.");
126             } catch (NoSuchMethodException e) {
127                 addError("Constructor error for " + parser + ": " + e);
128             } catch (InstantiationException e) {
129                 addError("Error instantiating " + parser + ": " + e);
130             } catch (IllegalAccessException e) {
131                 addError("Access errror for " + parser + ": " + e);
132             } catch (InvocationTargetException e) {
133                 // This is a wrapper for any exceptions thrown by the constructor called from newInstance
134                 addError(e.getTargetException().toString());
135             }
136         }
137     }
138 
139     /***
140      * Get an enumeration of the parameter names for uploaded files
141      *
142      * @return enumeration of parameter names for uploaded files
143      */
144     public Enumeration<String> getFileParameterNames() {
145         if (multi == null) {
146             return null;
147         }
148 
149         return multi.getFileParameterNames();
150     }
151 
152     /***
153      * Get an array of content encoding for the specified input field name or <tt>null</tt> if
154      * no content type was specified.
155      *
156      * @param name input field name
157      * @return an array of content encoding for the specified input field name
158      */
159     public String[] getContentTypes(String name) {
160         if (multi == null) {
161             return null;
162         }
163 
164         return multi.getContentType(name);
165     }
166 
167     /***
168      * Get a {@link java.io.File[]} for the given input field name.
169      *
170      * @param fieldName input field name
171      * @return a File[] object for files associated with the specified input field name
172      */
173     public File[] getFiles(String fieldName) {
174         if (multi == null) {
175             return null;
176         }
177 
178         return multi.getFile(fieldName);
179     }
180 
181     /***
182      * Get a String array of the file names for uploaded files
183      *
184      * @return a String[] of file names for uploaded files
185      */
186     public String[] getFileNames(String fieldName) {
187         if (multi == null) {
188             return null;
189         }
190 
191         return multi.getFileNames(fieldName);
192     }
193 
194     /***
195      * Get the filename(s) of the file(s) uploaded for the given input field name.
196      * Returns <tt>null</tt> if the file is not found.
197      *
198      * @param fieldName input field name
199      * @return the filename(s) of the file(s) uploaded for the given input field name or
200      *         <tt>null</tt> if name not found.
201      */
202     public String[] getFileSystemNames(String fieldName) {
203         if (multi == null) {
204             return null;
205         }
206 
207         return multi.getFilesystemName(fieldName);
208     }
209 
210     /***
211      * @see javax.servlet.http.HttpServletRequest#getParameter(String)
212      */
213     public String getParameter(String name) {
214         return ((multi == null) || (multi.getParameter(name) == null)) ? super.getParameter(name) : multi.getParameter(name);
215     }
216 
217     /***
218      * @see javax.servlet.http.HttpServletRequest#getParameterMap()
219      */
220     public Map getParameterMap() {
221         Map map = new HashMap();
222         Enumeration enumeration = getParameterNames();
223 
224         while (enumeration.hasMoreElements()) {
225             String name = (String) enumeration.nextElement();
226             map.put(name, this.getParameterValues(name));
227         }
228 
229         return map;
230     }
231 
232     /***
233      * @see javax.servlet.http.HttpServletRequest#getParameterNames()
234      */
235     public Enumeration getParameterNames() {
236         if (multi == null) {
237             return super.getParameterNames();
238         } else {
239             return mergeParams(multi.getParameterNames(), super.getParameterNames());
240         }
241     }
242 
243     /***
244      * @see javax.servlet.http.HttpServletRequest#getParameterValues(String)
245      */
246     public String[] getParameterValues(String name) {
247         return ((multi == null) || (multi.getParameterValues(name) == null)) ? super.getParameterValues(name) : multi.getParameterValues(name);
248     }
249 
250     /***
251      * Returns <tt>true</tt> if any errors occured when parsing the HTTP multipart request, <tt>false</tt> otherwise.
252      *
253      * @return <tt>true</tt> if any errors occured when parsing the HTTP multipart request, <tt>false</tt> otherwise.
254      */
255     public boolean hasErrors() {
256         if ((errors == null) || errors.isEmpty()) {
257             return false;
258         } else {
259             return true;
260         }
261     }
262 
263     /***
264      * Returns a collection of any errors generated when parsing the multipart request.
265      *
266      * @return the error Collection.
267      */
268     public Collection getErrors() {
269         return errors;
270     }
271 
272     /***
273      * Adds an error message.
274      *
275      * @param anErrorMessage the error message to report.
276      */
277     protected void addError(String anErrorMessage) {
278         if (errors == null) {
279             errors = new ArrayList();
280         }
281 
282         errors.add(anErrorMessage);
283     }
284 
285     /***
286      * Merges 2 enumeration of parameters as one.
287      *
288      * @param params1 the first enumeration.
289      * @param params2 the second enumeration.
290      * @return a single Enumeration of all elements from both Enumerations.
291      */
292     protected Enumeration mergeParams(Enumeration params1, Enumeration params2) {
293         Vector temp = new Vector();
294 
295         while (params1.hasMoreElements()) {
296             temp.add(params1.nextElement());
297         }
298 
299         while (params2.hasMoreElements()) {
300             temp.add(params2.nextElement());
301         }
302 
303         return temp.elements();
304     }
305 }