KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > fileupload > DefaultFileItem


1 /*
2  * $Header: /home/cvs/jakarta-commons/fileupload/src/java/org/apache/commons/fileupload/DefaultFileItem.java,v 1.21 2003/06/24 05:45:15 martinc Exp $
3  * $Revision: 1.21 $
4  * $Date: 2003/06/24 05:45:15 $
5  *
6  * ====================================================================
7  *
8  * The Apache Software License, Version 1.1
9  *
10  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
11  * reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright
18  * notice, this list of conditions and the following disclaimer.
19  *
20  * 2. Redistributions in binary form must reproduce the above copyright
21  * notice, this list of conditions and the following disclaimer in
22  * the documentation and/or other materials provided with the
23  * distribution.
24  *
25  * 3. The end-user documentation included with the redistribution, if
26  * any, must include the following acknowlegement:
27  * "This product includes software developed by the
28  * Apache Software Foundation (http://www.apache.org/)."
29  * Alternately, this acknowlegement may appear in the software itself,
30  * if and wherever such third-party acknowlegements normally appear.
31  *
32  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
33  * Foundation" must not be used to endorse or promote products derived
34  * from this software without prior written permission. For written
35  * permission, please contact apache@apache.org.
36  *
37  * 5. Products derived from this software may not be called "Apache"
38  * nor may "Apache" appear in their names without prior written
39  * permission of the Apache Group.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52  * SUCH DAMAGE.
53  * ====================================================================
54  *
55  * This software consists of voluntary contributions made by many
56  * individuals on behalf of the Apache Software Foundation. For more
57  * information on the Apache Software Foundation, please see
58  * <http://www.apache.org/>.
59  *
60  */

61
62
63 package org.apache.commons.fileupload;
64
65
66 import java.io.BufferedInputStream JavaDoc;
67 import java.io.BufferedOutputStream JavaDoc;
68 import java.io.ByteArrayInputStream JavaDoc;
69 import java.io.File JavaDoc;
70 import java.io.FileInputStream JavaDoc;
71 import java.io.FileOutputStream JavaDoc;
72 import java.io.IOException JavaDoc;
73 import java.io.InputStream JavaDoc;
74 import java.io.OutputStream JavaDoc;
75 import java.io.UnsupportedEncodingException JavaDoc;
76
77
78 /**
79  * <p> The default implementation of the
80  * {@link org.apache.commons.fileupload.FileItem FileItem} interface.
81  *
82  * <p> After retrieving an instance of this class from a {@link
83  * org.apache.commons.fileupload.DiskFileUpload DiskFileUpload} instance (see
84  * {@link org.apache.commons.fileupload.DiskFileUpload
85  * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may
86  * either request all contents of file at once using {@link #get()} or
87  * request an {@link java.io.InputStream InputStream} with
88  * {@link #getInputStream()} and process the file without attempting to load
89  * it into memory, which may come handy with large files.
90  *
91  * @author <a HREF="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
92  * @author <a HREF="mailto:sean@informage.net">Sean Legassick</a>
93  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
94  * @author <a HREF="mailto:jmcnally@apache.org">John McNally</a>
95  * @author <a HREF="mailto:martinc@apache.org">Martin Cooper</a>
96  * @author Sean C. Sullivan
97  *
98  * @version $Id: DefaultFileItem.java,v 1.21 2003/06/24 05:45:15 martinc Exp $
99  */

100 public class DefaultFileItem
101     implements FileItem
102 {
103
104     // ----------------------------------------------------------- Data members
105

106
107     /**
108      * Counter used in unique identifier generation.
109      */

110     private static int counter = 0;
111
112
113     /**
114      * The name of the form field as provided by the browser.
115      */

116     private String JavaDoc fieldName;
117
118
119     /**
120      * The content type passed by the browser, or <code>null</code> if
121      * not defined.
122      */

123     private String JavaDoc contentType;
124
125
126     /**
127      * Whether or not this item is a simple form field.
128      */

129     private boolean isFormField;
130
131
132     /**
133      * The original filename in the user's filesystem.
134      */

135     private String JavaDoc fileName;
136
137
138     /**
139      * The threshold above which uploads will be stored on disk.
140      */

141     private int sizeThreshold;
142
143
144     /**
145      * The directory in which uploaded files will be stored, if stored on disk.
146      */

147     private File JavaDoc repository;
148
149
150     /**
151      * Cached contents of the file.
152      */

153     private byte[] cachedContent;
154
155
156     /**
157      * Output stream for this item.
158      */

159     private DeferredFileOutputStream dfos;
160
161
162     // ----------------------------------------------------------- Constructors
163

164
165     /**
166      * Constructs a new <code>DefaultFileItem</code> instance.
167      *
168      * @param fieldName The name of the form field.
169      * @param contentType The content type passed by the browser or
170      * <code>null</code> if not specified.
171      * @param isFormField Whether or not this item is a plain form field, as
172      * opposed to a file upload.
173      * @param fileName The original filename in the user's filesystem, or
174      * <code>null</code> if not specified.
175      * @param sizeThreshold The threshold, in bytes, below which items will be
176      * retained in memory and above which they will be
177      * stored as a file.
178      * @param repository The data repository, which is the directory in
179      * which files will be created, should the item size
180      * exceed the threshold.
181      */

182     DefaultFileItem(String JavaDoc fieldName, String JavaDoc contentType, boolean isFormField,
183                     String JavaDoc fileName, int sizeThreshold, File JavaDoc repository)
184     {
185         this.fieldName = fieldName;
186         this.contentType = contentType;
187         this.isFormField = isFormField;
188         this.fileName = fileName;
189         this.sizeThreshold = sizeThreshold;
190         this.repository = repository;
191     }
192
193
194     // ------------------------------- Methods from javax.activation.DataSource
195

196
197     /**
198      * Returns an {@link java.io.InputStream InputStream} that can be
199      * used to retrieve the contents of the file.
200      *
201      * @return An {@link java.io.InputStream InputStream} that can be
202      * used to retrieve the contents of the file.
203      *
204      * @exception IOException if an error occurs.
205      */

206     public InputStream JavaDoc getInputStream()
207         throws IOException JavaDoc
208     {
209         if (!dfos.isInMemory())
210         {
211             return new FileInputStream JavaDoc(dfos.getFile());
212         }
213
214         if (cachedContent == null)
215         {
216             cachedContent = dfos.getData();
217         }
218         return new ByteArrayInputStream JavaDoc(cachedContent);
219     }
220
221
222     /**
223      * Returns the content type passed by the browser or <code>null</code> if
224      * not defined.
225      *
226      * @return The content type passed by the browser or <code>null</code> if
227      * not defined.
228      */

229     public String JavaDoc getContentType()
230     {
231         return contentType;
232     }
233
234
235     /**
236      * Returns the original filename in the client's filesystem.
237      *
238      * @return The original filename in the client's filesystem.
239      */

240     public String JavaDoc getName()
241     {
242         return fileName;
243     }
244
245
246     // ------------------------------------------------------- FileItem methods
247

248
249     /**
250      * Provides a hint as to whether or not the file contents will be read
251      * from memory.
252      *
253      * @return <code>true</code> if the file contents will be read
254      * from memory; <code>false</code> otherwise.
255      */

256     public boolean isInMemory()
257     {
258         return (dfos.isInMemory());
259     }
260
261
262     /**
263      * Returns the size of the file.
264      *
265      * @return The size of the file, in bytes.
266      */

267     public long getSize()
268     {
269         if (cachedContent != null)
270         {
271             return cachedContent.length;
272         }
273         else if (dfos.isInMemory())
274         {
275             return dfos.getData().length;
276         }
277         else
278         {
279             return dfos.getFile().length();
280         }
281     }
282
283
284     /**
285      * Returns the contents of the file as an array of bytes. If the
286      * contents of the file were not yet cached in memory, they will be
287      * loaded from the disk storage and cached.
288      *
289      * @return The contents of the file as an array of bytes.
290      */

291     public byte[] get()
292     {
293         if (dfos.isInMemory())
294         {
295             if (cachedContent == null)
296             {
297                 cachedContent = dfos.getData();
298             }
299             return cachedContent;
300         }
301
302         byte[] fileData = new byte[(int) getSize()];
303         FileInputStream JavaDoc fis = null;
304
305         try
306         {
307             fis = new FileInputStream JavaDoc(dfos.getFile());
308             fis.read(fileData);
309         }
310         catch (IOException JavaDoc e)
311         {
312             fileData = null;
313         }
314         finally
315         {
316             if (fis != null)
317             {
318                 try
319                 {
320                     fis.close();
321                 }
322                 catch (IOException JavaDoc e)
323                 {
324                     // ignore
325
}
326             }
327         }
328
329         return fileData;
330     }
331
332
333     /**
334      * Returns the contents of the file as a String, using the specified
335      * encoding. This method uses {@link #get()} to retrieve the
336      * contents of the file.
337      *
338      * @param encoding The character encoding to use.
339      *
340      * @return The contents of the file, as a string.
341      *
342      * @exception UnsupportedEncodingException if the requested character
343      * encoding is not available.
344      */

345     public String JavaDoc getString(String JavaDoc encoding)
346         throws UnsupportedEncodingException JavaDoc
347     {
348         return new String JavaDoc(get(), encoding);
349     }
350
351
352     /**
353      * Returns the contents of the file as a String, using the default
354      * character encoding. This method uses {@link #get()} to retrieve the
355      * contents of the file.
356      *
357      * @return The contents of the file, as a string.
358      */

359     public String JavaDoc getString()
360     {
361         return new String JavaDoc(get());
362     }
363
364
365     /**
366      * A convenience method to write an uploaded item to disk. The client code
367      * is not concerned with whether or not the item is stored in memory, or on
368      * disk in a temporary location. They just want to write the uploaded item
369      * to a file.
370      * <p>
371      * This implementation first attempts to rename the uploaded item to the
372      * specified destination file, if the item was originally written to disk.
373      * Otherwise, the data will be copied to the specified file.
374      * <p>
375      * This method is only guaranteed to work <em>once</em>, the first time it
376      * is invoked for a particular item. This is because, in the event that the
377      * method renames a temporary file, that file will no longer be available
378      * to copy or rename again at a later time.
379      *
380      * @param file The <code>File</code> into which the uploaded item should
381      * be stored.
382      *
383      * @exception Exception if an error occurs.
384      */

385     public void write(File JavaDoc file) throws Exception JavaDoc
386     {
387         if (isInMemory())
388         {
389             FileOutputStream JavaDoc fout = null;
390             try
391             {
392                 fout = new FileOutputStream JavaDoc(file);
393                 fout.write(get());
394             }
395             finally
396             {
397                 if (fout != null)
398                 {
399                     fout.close();
400                 }
401             }
402         }
403         else
404         {
405             File JavaDoc outputFile = getStoreLocation();
406             if (outputFile != null)
407             {
408                 /*
409                  * The uploaded file is being stored on disk
410                  * in a temporary location so move it to the
411                  * desired file.
412                  */

413                 if (!outputFile.renameTo(file))
414                 {
415                     BufferedInputStream JavaDoc in = null;
416                     BufferedOutputStream JavaDoc out = null;
417                     try
418                     {
419                         in = new BufferedInputStream JavaDoc(
420                             new FileInputStream JavaDoc(outputFile));
421                         out = new BufferedOutputStream JavaDoc(
422                                 new FileOutputStream JavaDoc(file));
423                         byte[] bytes = new byte[2048];
424                         int s = 0;
425                         while ((s = in.read(bytes)) != -1)
426                         {
427                             out.write(bytes, 0, s);
428                         }
429                     }
430                     finally
431                     {
432                         try
433                         {
434                             in.close();
435                         }
436                         catch (IOException JavaDoc e)
437                         {
438                             // ignore
439
}
440                         try
441                         {
442                             out.close();
443                         }
444                         catch (IOException JavaDoc e)
445                         {
446                             // ignore
447
}
448                     }
449                 }
450             }
451             else
452             {
453                 /*
454                  * For whatever reason we cannot write the
455                  * file to disk.
456                  */

457                 throw new FileUploadException(
458                     "Cannot write uploaded file to disk!");
459             }
460         }
461     }
462
463
464     /**
465      * Deletes the underlying storage for a file item, including deleting any
466      * associated temporary disk file. Although this storage will be deleted
467      * automatically when the <code>FileItem</code> instance is garbage
468      * collected, this method can be used to ensure that this is done at an
469      * earlier time, thus preserving system resources.
470      */

471     public void delete()
472     {
473         cachedContent = null;
474         File JavaDoc outputFile = getStoreLocation();
475         if (outputFile != null && outputFile.exists())
476         {
477             outputFile.delete();
478         }
479     }
480
481
482     /**
483      * Returns the name of the field in the multipart form corresponding to
484      * this file item.
485      *
486      * @return The name of the form field.
487      *
488      * @see #setFieldName(java.lang.String)
489      *
490      */

491     public String JavaDoc getFieldName()
492     {
493         return fieldName;
494     }
495
496
497     /**
498      * Sets the field name used to reference this file item.
499      *
500      * @param fieldName The name of the form field.
501      *
502      * @see #getFieldName()
503      *
504      */

505     public void setFieldName(String JavaDoc fieldName)
506     {
507         this.fieldName = fieldName;
508     }
509
510
511     /**
512      * Determines whether or not a <code>FileItem</code> instance represents
513      * a simple form field.
514      *
515      * @return <code>true</code> if the instance represents a simple form
516      * field; <code>false</code> if it represents an uploaded file.
517      *
518      * @see #setFormField(boolean)
519      *
520      */

521     public boolean isFormField()
522     {
523         return isFormField;
524     }
525
526
527     /**
528      * Specifies whether or not a <code>FileItem</code> instance represents
529      * a simple form field.
530      *
531      * @param state <code>true</code> if the instance represents a simple form
532      * field; <code>false</code> if it represents an uploaded file.
533      *
534      * @see #isFormField()
535      *
536      */

537     public void setFormField(boolean state)
538     {
539         isFormField = state;
540     }
541
542
543     /**
544      * Returns an {@link java.io.OutputStream OutputStream} that can
545      * be used for storing the contents of the file.
546      *
547      * @return An {@link java.io.OutputStream OutputStream} that can be used
548      * for storing the contensts of the file.
549      *
550      * @exception IOException if an error occurs.
551      */

552     public OutputStream JavaDoc getOutputStream()
553         throws IOException JavaDoc
554     {
555         if (dfos == null)
556         {
557             File JavaDoc outputFile = getTempFile();
558             dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
559         }
560         return dfos;
561     }
562
563
564     // --------------------------------------------------------- Public methods
565

566
567     /**
568      * Returns the {@link java.io.File} object for the <code>FileItem</code>'s
569      * data's temporary location on the disk. Note that for
570      * <code>FileItem</code>s that have their data stored in memory,
571      * this method will return <code>null</code>. When handling large
572      * files, you can use {@link java.io.File#renameTo(java.io.File)} to
573      * move the file to new location without copying the data, if the
574      * source and destination locations reside within the same logical
575      * volume.
576      *
577      * @return The data file, or <code>null</code> if the data is stored in
578      * memory.
579      */

580     public File JavaDoc getStoreLocation()
581     {
582         return dfos.getFile();
583     }
584
585
586     // ------------------------------------------------------ Protected methods
587

588
589     /**
590      * Removes the file contents from the temporary storage.
591      */

592     protected void finalize()
593     {
594         File JavaDoc outputFile = dfos.getFile();
595
596         if (outputFile != null && outputFile.exists())
597         {
598             outputFile.delete();
599         }
600     }
601
602
603     /**
604      * Creates and returns a {@link java.io.File File} representing a uniquely
605      * named temporary file in the configured repository path.
606      *
607      * @return The {@link java.io.File File} to be used for temporary storage.
608      */

609     protected File JavaDoc getTempFile()
610     {
611         File JavaDoc tempDir = repository;
612         if (tempDir == null)
613         {
614             tempDir = new File JavaDoc(System.getProperty("java.io.tmpdir"));
615         }
616
617         String JavaDoc fileName = "upload_" + getUniqueId() + ".tmp";
618
619         File JavaDoc f = new File JavaDoc(tempDir, fileName);
620         f.deleteOnExit();
621         return f;
622     }
623
624
625     // -------------------------------------------------------- Private methods
626

627
628     /**
629      * Returns an identifier that is unique within the class loader used to
630      * load this class, but does not have random-like apearance.
631      *
632      * @return A String with the non-random looking instance identifier.
633      */

634     private static String JavaDoc getUniqueId()
635     {
636         int current;
637         synchronized (DefaultFileItem.class)
638         {
639             current = counter++;
640         }
641         String JavaDoc id = Integer.toString(current);
642
643         // If you manage to get more than 100 million of ids, you'll
644
// start getting ids longer than 8 characters.
645
if (current < 100000000)
646         {
647             id = ("00000000" + id).substring(id.length());
648         }
649         return id;
650     }
651
652 }
653
Popular Tags