View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/util/MultipartRequest.java,v 1.20 2006/03/25 15:39:26 hkollmann Exp $
3    * $Revision: 1.20 $
4    * $Date: 2006/03/25 15:39:26 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.util;
25  
26  import org.apache.commons.fileupload.DiskFileUpload;
27  import org.apache.commons.fileupload.FileItem;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import java.io.File;
32  import java.io.IOException;
33  import java.io.InputStream;
34  
35  import java.util.Enumeration;
36  import java.util.Hashtable;
37  import java.util.Iterator;
38  import java.util.List;
39  import java.util.Vector;
40  
41  import javax.servlet.http.HttpServletRequest;
42  import org.dbforms.util.external.FileUtil;
43  
44  
45  /***
46   * A utility class to handle <code>multipart/form-data</code> requests, the
47   * kind of requests that support file uploads. This class emulates the interface
48   * of <code>HttpServletRequest</code>, making it familiar to use. It uses a
49   * "push" model where any incoming files are read and saved directly to disk in
50   * the constructor. If you wish to have more flexibility, e.g. write the files
51   * to a database, use the "pull" model <code>MultipartParser</code> instead.
52   * <p>
53   * This class can receive arbitrarily large files (up to an artificial limit you
54   * can set), and fairly efficiently too. It cannot handle nested data (multipart
55   * content within multipart content) or internationalized content (such as non
56   * Latin-1 filenames).
57   * </p>
58   * <p>
59   * See the included <a href="upload.war">upload.war </a> for an example of how
60   * to use this class.
61   * <p>
62   * The full file upload specification is contained in experimental RFC 1867,
63   * available at <a href="http://www.ietf.org/rfc/rfc1867.txt"
64   * http://www.ietf.org/rfc/rfc1867.txt </a>.
65   * </p>
66   * <p>
67   * PLEASE NOTE: this class uses Multipart Support Classes by Jason Hunter.
68   * Copyright (C) 1998 by Jason Hunter. All rights reserved.
69   * Use of this class is limited. Please see the LICENSE for more information.
70   * Make sure that you project meets the requierements defined by Jason Hunter
71   * respective O'reilly!
72   * </p>
73   *
74   * @see MultipartParser
75   *
76   * @author Jason Hunter
77   * @author Geoff Soutter
78   * @author Joe Peer - _changed_ it for use in DbForms (i apologize)
79   */
80  public class MultipartRequest {
81     private static Log logCat = LogFactory.getLog(MultipartRequest.class); // logging category
82     private Hashtable  files = new Hashtable(); // name - UploadedFile
83  
84     // for this class
85     //private File dir;
86     private Hashtable parameters = new Hashtable(); // name - Vector of values
87  
88     private String fileName2SystemFileName(String filename) {
89        String filenm = "";
90        if ('/' != File.separatorChar) {
91           filenm = filename.replace('/', File.separatorChar);
92        }
93        if ('//' != File.separatorChar) {
94           filenm = filename.replace('//', File.separatorChar);
95        }
96        return filenm;
97     }
98  
99  
100    /***
101     * Constructs a new MultipartRequest to handle the specified request,
102     * {saving any uploaded files to the given directory}, and limiting the
103     * upload size to the specified length. If the content is too large, an
104     * IOException is thrown. This constructor actually parses the
105     * <tt>multipart/form-data</tt> and throws an IOException if there's any
106     * problem reading or parsing the request.
107     *
108     * @param request
109     *            the servlet request.
110     * @param maxPostSize
111     *            the maximum size of the POST content.
112     * @exception IOException
113     *                if the uploaded content is larger than
114     *                <tt>maxPostSize</tt> or there's a problem reading or
115     *                parsing the request.
116     */
117    public MultipartRequest(HttpServletRequest request,
118                            int                maxPostSize)
119                     throws IOException {
120       // Sanity check values
121       if (request == null) {
122          throw new IllegalArgumentException("request cannot be null");
123       }
124 
125       //    Create a new file upload handler
126       DiskFileUpload upload = new DiskFileUpload();
127 
128       //    Set upload parameters
129       upload.setSizeMax(maxPostSize);
130 
131       String tmpDir = System.getProperty("java.io.tmpdir");
132       upload.setRepositoryPath(tmpDir);
133 
134       //    Parse the request
135       try {
136          List     items = upload.parseRequest(request);
137          Iterator iter = items.iterator();
138 
139          while (iter.hasNext()) {
140             FileItem item = (FileItem) iter.next();
141             String   name = item.getFieldName();
142 
143             if (item.isFormField()) {
144                String value = item.getString();
145 
146                // plain parameters get allways into parameters structure
147                Vector existingValues = (Vector) parameters.get(name);
148 
149                if (existingValues == null) {
150                   existingValues = new Vector();
151                   parameters.put(name, existingValues);
152                }
153 
154                existingValues.addElement(value);
155             } else {
156                String fileName = item.getName();
157 
158                if (!Util.isNull(fileName)) {
159                   // 2004-08-05-HKK/Dziugas Baltrunas: 
160                   // FileItem always returns the full pathname!
161                   fileName = FileUtil.filename(fileName2SystemFileName(fileName));
162 
163                   // The part actually contained a file
164                   // #changes by joe peer:
165                   // we must delay storing the file-inputstream (into
166                   // database, filesystem or whatever)
167                   // until we know exactly what should happen with it
168                   FileHolder fileHolder = new FileHolder(fileName, item);
169                   files.put(name, fileHolder);
170                   logCat.info("buffered and now added as " + name
171                               + " the following fileHolder:"
172                               + fileHolder.getFileName());
173 
174                   // #changes by joe peer:
175                   // if a file parameter is not null it gets into the
176                   // parameters structures as well
177                   // this is important to provide a simple access to
178                   // request (no distinction between files and plain
179                   // params)
180                   Vector existingValues = (Vector) parameters.get(name);
181 
182                   if (existingValues == null) {
183                      existingValues = new Vector();
184                      parameters.put(name, existingValues);
185                   }
186 
187                   existingValues.addElement(fileName);
188                }
189             }
190          }
191       } catch (Exception e) {
192          logCat.error("MultipartRequest", e);
193       }
194    }
195 
196    /***
197     * Returns the content type of the specified file (as supplied by the client
198     * browser), or null if the file was not included in the upload.
199     *
200     * @param name
201     *            the file name.
202     * @return the content type of the file.
203     */
204    public String getContentType(String name) {
205       try {
206          //#changed by joe peer
207          //UploadedFile file = (UploadedFile)files.get(name);
208          FileHolder filePart = (FileHolder) files.get(name);
209 
210          return filePart.getContentType(); // may be null
211       } catch (Exception e) {
212          return null;
213       }
214    }
215 
216 
217    /***
218     * Returns a FilePart object for the specified file this method was added by
219     * joe peer
220     *
221     * @param name
222     *            the file name.
223     * @return a FilePart object for the named file.
224     */
225    public FileHolder getFileHolder(String name) {
226       try {
227          return (FileHolder) files.get(name);
228       } catch (Exception e) {
229          return null;
230       }
231    }
232 
233 
234    /***
235     * Returns a InputStream object for the specified file saved on the server's
236     * filesystem, or null if the file was not included in the upload.
237     *
238     * @param name
239     *            the file name.
240     * @return a InputStream object for the named file.
241     */
242    public InputStream getFileInputStream(String name) {
243       try {
244          //#changed by joe peer
245          //UploadedFile file = (UploadedFile)files.get(name);
246          FileHolder filePart = (FileHolder) files.get(name);
247 
248          return filePart.getInputStreamFromBuffer(); // may be null
249       } catch (Exception e) {
250          return null;
251       }
252    }
253 
254 
255    /***
256     * Returns the names of all the uploaded files as an Enumeration of Strings.
257     * It returns an empty Enumeration if there are no uploaded files. Each file
258     * name is the name specified by the form, not by the user.
259     *
260     * @return the names of all the uploaded files as an Enumeration of Strings.
261     */
262    public Enumeration getFileNames() {
263       return files.keys();
264    }
265 
266 
267    /***
268     * Returns the filesystem name of the specified file, or null if the file
269     * was not included in the upload. A filesystem name is the name specified
270     * by the user. It is also the name under which the file is actually saved.
271     *
272     * @param name
273     *            the file name.
274     * @return the filesystem name of the file.
275     */
276    public String getFilesystemName(String name) {
277       try {
278          //#changed by joe peer
279          //UploadedFile file = (UploadedFile)files.get(name);
280          FileHolder filePart = (FileHolder) files.get(name);
281 
282          return filePart.getFileName(); // may be null
283       } catch (Exception e) {
284          return null;
285       }
286    }
287 
288 
289    /***
290     * Returns the value of the named parameter as a String, or null if the
291     * parameter was not sent or was sent without a value. The value is
292     * guaranteed to be in its normal, decoded form. If the parameter has
293     * multiple values, only the last one is returned (for backward
294     * compatibility). For parameters with multiple values, it's possible the
295     * last "value" may be null.
296     *
297     * @param name
298     *            the parameter name.
299     * @return the parameter value.
300     */
301    public String getParameter(String name) {
302       try {
303          Vector values = (Vector) parameters.get(name);
304 
305          if ((values == null) || (values.size() == 0)) {
306             return null;
307          }
308 
309          String value = (String) values.elementAt(0);
310 
311          return value;
312       } catch (Exception e) {
313          return null;
314       }
315    }
316 
317 
318    /***
319     * Returns the names of all the parameters as an Enumeration of Strings. It
320     * returns an empty Enumeration if there are no parameters.
321     *
322     * @return the names of all the parameters as an Enumeration of Strings.
323     */
324    public Enumeration getParameterNames() {
325       return parameters.keys();
326    }
327 
328 
329    /***
330     * Returns the values of the named parameter as a String array, or null if
331     * the parameter was not sent. The array has one entry for each parameter
332     * field sent. If any field was sent without a value that entry is stored in
333     * the array as a null. The values are guaranteed to be in their normal,
334     * decoded form. A single value is returned as a one-element array.
335     *
336     * @param name
337     *            the parameter name.
338     * @return the parameter values.
339     */
340    public String[] getParameterValues(String name) {
341       try {
342          Vector values = (Vector) parameters.get(name);
343 
344          if ((values == null) || (values.size() == 0)) {
345             return null;
346          }
347 
348          String[] valuesArray = new String[values.size()];
349          values.copyInto(valuesArray);
350 
351          return valuesArray;
352       } catch (Exception e) {
353          return null;
354       }
355    }
356 }