KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tomcat > util > http > fileupload > DefaultFileItem


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.tomcat.util.http.fileupload;
20
21
22 import java.io.BufferedInputStream JavaDoc;
23 import java.io.BufferedOutputStream JavaDoc;
24 import java.io.ByteArrayInputStream JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.FileInputStream JavaDoc;
27 import java.io.FileOutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.OutputStream JavaDoc;
31 import java.io.UnsupportedEncodingException JavaDoc;
32
33
34 /**
35  * <p> The default implementation of the
36  * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} interface.
37  *
38  * <p> After retrieving an instance of this class from a {@link
39  * org.apache.tomcat.util.http.fileupload.DiskFileUpload DiskFileUpload} instance (see
40  * {@link org.apache.tomcat.util.http.fileupload.DiskFileUpload
41  * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may
42  * either request all contents of file at once using {@link #get()} or
43  * request an {@link java.io.InputStream InputStream} with
44  * {@link #getInputStream()} and process the file without attempting to load
45  * it into memory, which may come handy with large files.
46  *
47  * @author <a HREF="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
48  * @author <a HREF="mailto:sean@informage.net">Sean Legassick</a>
49  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
50  * @author <a HREF="mailto:jmcnally@apache.org">John McNally</a>
51  * @author <a HREF="mailto:martinc@apache.org">Martin Cooper</a>
52  * @author Sean C. Sullivan
53  *
54  * @version $Id: DefaultFileItem.java 467222 2006-10-24 03:17:11Z markt $
55  */

56 public class DefaultFileItem
57     implements FileItem
58 {
59
60     // ----------------------------------------------------------- Data members
61

62
63     /**
64      * Counter used in unique identifier generation.
65      */

66     private static int counter = 0;
67
68
69     /**
70      * The name of the form field as provided by the browser.
71      */

72     private String JavaDoc fieldName;
73
74
75     /**
76      * The content type passed by the browser, or <code>null</code> if
77      * not defined.
78      */

79     private String JavaDoc contentType;
80
81
82     /**
83      * Whether or not this item is a simple form field.
84      */

85     private boolean isFormField;
86
87
88     /**
89      * The original filename in the user's filesystem.
90      */

91     private String JavaDoc fileName;
92
93
94     /**
95      * The threshold above which uploads will be stored on disk.
96      */

97     private int sizeThreshold;
98
99
100     /**
101      * The directory in which uploaded files will be stored, if stored on disk.
102      */

103     private File JavaDoc repository;
104
105
106     /**
107      * Cached contents of the file.
108      */

109     private byte[] cachedContent;
110
111
112     /**
113      * Output stream for this item.
114      */

115     private DeferredFileOutputStream dfos;
116
117
118     // ----------------------------------------------------------- Constructors
119

120
121     /**
122      * Constructs a new <code>DefaultFileItem</code> instance.
123      *
124      * @param fieldName The name of the form field.
125      * @param contentType The content type passed by the browser or
126      * <code>null</code> if not specified.
127      * @param isFormField Whether or not this item is a plain form field, as
128      * opposed to a file upload.
129      * @param fileName The original filename in the user's filesystem, or
130      * <code>null</code> if not specified.
131      * @param sizeThreshold The threshold, in bytes, below which items will be
132      * retained in memory and above which they will be
133      * stored as a file.
134      * @param repository The data repository, which is the directory in
135      * which files will be created, should the item size
136      * exceed the threshold.
137      */

138     DefaultFileItem(String JavaDoc fieldName, String JavaDoc contentType, boolean isFormField,
139                     String JavaDoc fileName, int sizeThreshold, File JavaDoc repository)
140     {
141         this.fieldName = fieldName;
142         this.contentType = contentType;
143         this.isFormField = isFormField;
144         this.fileName = fileName;
145         this.sizeThreshold = sizeThreshold;
146         this.repository = repository;
147     }
148
149
150     // ------------------------------- Methods from javax.activation.DataSource
151

152
153     /**
154      * Returns an {@link java.io.InputStream InputStream} that can be
155      * used to retrieve the contents of the file.
156      *
157      * @return An {@link java.io.InputStream InputStream} that can be
158      * used to retrieve the contents of the file.
159      *
160      * @exception IOException if an error occurs.
161      */

162     public InputStream JavaDoc getInputStream()
163         throws IOException JavaDoc
164     {
165         if (!dfos.isInMemory())
166         {
167             return new FileInputStream JavaDoc(dfos.getFile());
168         }
169
170         if (cachedContent == null)
171         {
172             cachedContent = dfos.getData();
173         }
174         return new ByteArrayInputStream JavaDoc(cachedContent);
175     }
176
177
178     /**
179      * Returns the content type passed by the browser or <code>null</code> if
180      * not defined.
181      *
182      * @return The content type passed by the browser or <code>null</code> if
183      * not defined.
184      */

185     public String JavaDoc getContentType()
186     {
187         return contentType;
188     }
189
190
191     /**
192      * Returns the original filename in the client's filesystem.
193      *
194      * @return The original filename in the client's filesystem.
195      */

196     public String JavaDoc getName()
197     {
198         return fileName;
199     }
200
201
202     // ------------------------------------------------------- FileItem methods
203

204
205     /**
206      * Provides a hint as to whether or not the file contents will be read
207      * from memory.
208      *
209      * @return <code>true</code> if the file contents will be read
210      * from memory; <code>false</code> otherwise.
211      */

212     public boolean isInMemory()
213     {
214         return (dfos.isInMemory());
215     }
216
217
218     /**
219      * Returns the size of the file.
220      *
221      * @return The size of the file, in bytes.
222      */

223     public long getSize()
224     {
225         if (cachedContent != null)
226         {
227             return cachedContent.length;
228         }
229         else if (dfos.isInMemory())
230         {
231             return dfos.getData().length;
232         }
233         else
234         {
235             return dfos.getFile().length();
236         }
237     }
238
239
240     /**
241      * Returns the contents of the file as an array of bytes. If the
242      * contents of the file were not yet cached in memory, they will be
243      * loaded from the disk storage and cached.
244      *
245      * @return The contents of the file as an array of bytes.
246      */

247     public byte[] get()
248     {
249         if (dfos.isInMemory())
250         {
251             if (cachedContent == null)
252             {
253                 cachedContent = dfos.getData();
254             }
255             return cachedContent;
256         }
257
258         byte[] fileData = new byte[(int) getSize()];
259         FileInputStream JavaDoc fis = null;
260
261         try
262         {
263             fis = new FileInputStream JavaDoc(dfos.getFile());
264             fis.read(fileData);
265         }
266         catch (IOException JavaDoc e)
267         {
268             fileData = null;
269         }
270         finally
271         {
272             if (fis != null)
273             {
274                 try
275                 {
276                     fis.close();
277                 }
278                 catch (IOException JavaDoc e)
279                 {
280                     // ignore
281
}
282             }
283         }
284
285         return fileData;
286     }
287
288
289     /**
290      * Returns the contents of the file as a String, using the specified
291      * encoding. This method uses {@link #get()} to retrieve the
292      * contents of the file.
293      *
294      * @param encoding The character encoding to use.
295      *
296      * @return The contents of the file, as a string.
297      *
298      * @exception UnsupportedEncodingException if the requested character
299      * encoding is not available.
300      */

301     public String JavaDoc getString(String JavaDoc encoding)
302         throws UnsupportedEncodingException JavaDoc
303     {
304         return new String JavaDoc(get(), encoding);
305     }
306
307
308     /**
309      * Returns the contents of the file as a String, using the default
310      * character encoding. This method uses {@link #get()} to retrieve the
311      * contents of the file.
312      *
313      * @return The contents of the file, as a string.
314      */

315     public String JavaDoc getString()
316     {
317         return new String JavaDoc(get());
318     }
319
320
321     /**
322      * A convenience method to write an uploaded item to disk. The client code
323      * is not concerned with whether or not the item is stored in memory, or on
324      * disk in a temporary location. They just want to write the uploaded item
325      * to a file.
326      * <p>
327      * This implementation first attempts to rename the uploaded item to the
328      * specified destination file, if the item was originally written to disk.
329      * Otherwise, the data will be copied to the specified file.
330      * <p>
331      * This method is only guaranteed to work <em>once</em>, the first time it
332      * is invoked for a particular item. This is because, in the event that the
333      * method renames a temporary file, that file will no longer be available
334      * to copy or rename again at a later time.
335      *
336      * @param file The <code>File</code> into which the uploaded item should
337      * be stored.
338      *
339      * @exception Exception if an error occurs.
340      */

341     public void write(File JavaDoc file) throws Exception JavaDoc
342     {
343         if (isInMemory())
344         {
345             FileOutputStream JavaDoc fout = null;
346             try
347             {
348                 fout = new FileOutputStream JavaDoc(file);
349                 fout.write(get());
350             }
351             finally
352             {
353                 if (fout != null)
354                 {
355                     fout.close();
356                 }
357             }
358         }
359         else
360         {
361             File JavaDoc outputFile = getStoreLocation();
362             if (outputFile != null)
363             {
364                 /*
365                  * The uploaded file is being stored on disk
366                  * in a temporary location so move it to the
367                  * desired file.
368                  */

369                 if (!outputFile.renameTo(file))
370                 {
371                     BufferedInputStream JavaDoc in = null;
372                     BufferedOutputStream JavaDoc out = null;
373                     try
374                     {
375                         in = new BufferedInputStream JavaDoc(
376                             new FileInputStream JavaDoc(outputFile));
377                         out = new BufferedOutputStream JavaDoc(
378                                 new FileOutputStream JavaDoc(file));
379                         byte[] bytes = new byte[2048];
380                         int s = 0;
381                         while ((s = in.read(bytes)) != -1)
382                         {
383                             out.write(bytes, 0, s);
384                         }
385                     }
386                     finally
387                     {
388                         try
389                         {
390                             in.close();
391                         }
392                         catch (IOException JavaDoc e)
393                         {
394                             // ignore
395
}
396                         try
397                         {
398                             out.close();
399                         }
400                         catch (IOException JavaDoc e)
401                         {
402                             // ignore
403
}
404                     }
405                 }
406             }
407             else
408             {
409                 /*
410                  * For whatever reason we cannot write the
411                  * file to disk.
412                  */

413                 throw new FileUploadException(
414                     "Cannot write uploaded file to disk!");
415             }
416         }
417     }
418
419
420     /**
421      * Deletes the underlying storage for a file item, including deleting any
422      * associated temporary disk file. Although this storage will be deleted
423      * automatically when the <code>FileItem</code> instance is garbage
424      * collected, this method can be used to ensure that this is done at an
425      * earlier time, thus preserving system resources.
426      */

427     public void delete()
428     {
429         cachedContent = null;
430         File JavaDoc outputFile = getStoreLocation();
431         if (outputFile != null && outputFile.exists())
432         {
433             outputFile.delete();
434         }
435     }
436
437
438     /**
439      * Returns the name of the field in the multipart form corresponding to
440      * this file item.
441      *
442      * @return The name of the form field.
443      *
444      * @see #setFieldName(java.lang.String)
445      *
446      */

447     public String JavaDoc getFieldName()
448     {
449         return fieldName;
450     }
451
452
453     /**
454      * Sets the field name used to reference this file item.
455      *
456      * @param fieldName The name of the form field.
457      *
458      * @see #getFieldName()
459      *
460      */

461     public void setFieldName(String JavaDoc fieldName)
462     {
463         this.fieldName = fieldName;
464     }
465
466
467     /**
468      * Determines whether or not a <code>FileItem</code> instance represents
469      * a simple form field.
470      *
471      * @return <code>true</code> if the instance represents a simple form
472      * field; <code>false</code> if it represents an uploaded file.
473      *
474      * @see #setFormField(boolean)
475      *
476      */

477     public boolean isFormField()
478     {
479         return isFormField;
480     }
481
482
483     /**
484      * Specifies whether or not a <code>FileItem</code> instance represents
485      * a simple form field.
486      *
487      * @param state <code>true</code> if the instance represents a simple form
488      * field; <code>false</code> if it represents an uploaded file.
489      *
490      * @see #isFormField()
491      *
492      */

493     public void setFormField(boolean state)
494     {
495         isFormField = state;
496     }
497
498
499     /**
500      * Returns an {@link java.io.OutputStream OutputStream} that can
501      * be used for storing the contents of the file.
502      *
503      * @return An {@link java.io.OutputStream OutputStream} that can be used
504      * for storing the contensts of the file.
505      *
506      * @exception IOException if an error occurs.
507      */

508     public OutputStream JavaDoc getOutputStream()
509         throws IOException JavaDoc
510     {
511         if (dfos == null)
512         {
513             File JavaDoc outputFile = getTempFile();
514             dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
515         }
516         return dfos;
517     }
518
519
520     // --------------------------------------------------------- Public methods
521

522
523     /**
524      * Returns the {@link java.io.File} object for the <code>FileItem</code>'s
525      * data's temporary location on the disk. Note that for
526      * <code>FileItem</code>s that have their data stored in memory,
527      * this method will return <code>null</code>. When handling large
528      * files, you can use {@link java.io.File#renameTo(java.io.File)} to
529      * move the file to new location without copying the data, if the
530      * source and destination locations reside within the same logical
531      * volume.
532      *
533      * @return The data file, or <code>null</code> if the data is stored in
534      * memory.
535      */

536     public File JavaDoc getStoreLocation()
537     {
538         return dfos.getFile();
539     }
540
541
542     // ------------------------------------------------------ Protected methods
543

544
545     /**
546      * Removes the file contents from the temporary storage.
547      */

548     protected void finalize()
549     {
550         File JavaDoc outputFile = dfos.getFile();
551
552         if (outputFile != null && outputFile.exists())
553         {
554             outputFile.delete();
555         }
556     }
557
558
559     /**
560      * Creates and returns a {@link java.io.File File} representing a uniquely
561      * named temporary file in the configured repository path.
562      *
563      * @return The {@link java.io.File File} to be used for temporary storage.
564      */

565     protected File JavaDoc getTempFile()
566     {
567         File JavaDoc tempDir = repository;
568         if (tempDir == null)
569         {
570             tempDir = new File JavaDoc(System.getProperty("java.io.tmpdir"));
571         }
572
573         String JavaDoc fileName = "upload_" + getUniqueId() + ".tmp";
574
575         File JavaDoc f = new File JavaDoc(tempDir, fileName);
576         f.deleteOnExit();
577         return f;
578     }
579
580
581     // -------------------------------------------------------- Private methods
582

583
584     /**
585      * Returns an identifier that is unique within the class loader used to
586      * load this class, but does not have random-like apearance.
587      *
588      * @return A String with the non-random looking instance identifier.
589      */

590     private static String JavaDoc getUniqueId()
591     {
592         int current;
593         synchronized (DefaultFileItem.class)
594         {
595             current = counter++;
596         }
597         String JavaDoc id = Integer.toString(current);
598
599         // If you manage to get more than 100 million of ids, you'll
600
// start getting ids longer than 8 characters.
601
if (current < 100000000)
602         {
603             id = ("00000000" + id).substring(id.length());
604         }
605         return id;
606     }
607
608 }
609
Popular Tags