View Javadoc

1   package org.apache.turbine.util.upload;
2   
3   /*
4    * Copyright 2001-2005 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  
19  import java.io.BufferedInputStream;
20  import java.io.BufferedOutputStream;
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.io.UnsupportedEncodingException;
30  import javax.activation.DataSource;
31  
32  import org.apache.turbine.services.uniqueid.TurbineUniqueId;
33  import org.apache.turbine.services.upload.TurbineUpload;
34  
35  /***
36   * <p> This class represents a file that was received by Turbine using
37   * <code>multipart/form-data</code> POST request.
38   *
39   * <p> After retrieving an instance of this class from the {@link
40   * org.apache.turbine.util.ParameterParser ParameterParser} (see
41   * {@link org.apache.turbine.util.ParameterParser#getFileItem(String)
42   * ParameterParser.getFileItem(String)} and {@link
43   * org.apache.turbine.util.ParameterParser#getFileItems(String)
44   * ParameterParser.getFileItems(String)}) you can use it to acces the
45   * data that was sent by the browser.  You may either request all
46   * contents of file at once using {@link #get()} or request an {@link
47   * java.io.InputStream InputStream} with {@link #getStream()} and
48   * process the file without attempting to load it into memory, which
49   * may come handy with large files.
50   *
51   * Implements the javax.activation.DataSource interface (which allows
52   * for example the adding of a FileItem as an attachment to a multipart
53   * email).
54   *
55   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
56   * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
57   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
58   * @version $Id: FileItem.java 264148 2005-08-29 14:21:04Z henning $
59   * @deprecated use commons-fileupload instead
60   */
61  public class FileItem implements DataSource
62  {
63      /***
64       * The maximal size of request that will have it's elements stored
65       * in memory.
66       */
67      public static final int DEFAULT_UPLOAD_SIZE_THRESHOLD = 10240;
68  
69      /*** The original filename in the user's filesystem. */
70      protected String fileName;
71  
72      /***
73       * The content type passed by the browser or <code>null</code> if
74       * not defined.
75       */
76      protected String contentType;
77  
78      /*** Cached contents of the file. */
79      protected byte[] content;
80  
81      /*** Temporary storage location. */
82      protected File storeLocation;
83  
84      /*** Temporary storage for in-memory files. */
85      protected ByteArrayOutputStream byteStream;
86  
87      /***
88       * Constructs a new <code>FileItem</code>.
89       *
90       * <p>Use {@link #newInstance(String,String,String,int)} to
91       * instantiate <code>FileItems</code>.
92       *
93       * @param fileName The original filename in the user's filesystem.
94       * @param contentType The content type passed by the browser or
95       * <code>null</code> if not defined.
96       */
97      protected FileItem(String fileName, String contentType)
98      {
99          this.fileName = fileName;
100         this.contentType = contentType;
101     }
102 
103     /***
104      * Returns the original filename in the user's filesystem.
105      * (implements DataSource method)
106      *
107      * @return The original filename in the user's filesystem.
108      */
109     public String getName()
110     {
111         return getFileName();
112     }
113 
114     /***
115      * Returns the original filename in the user's filesystem.
116      *
117      * @return The original filename in the user's filesystem.
118      */
119     public String getFileName()
120     {
121         return fileName;
122     }
123 
124     /***
125      * Returns the content type passed by the browser or
126      * <code>null</code> if not defined. (implements
127      * DataSource method).
128      *
129      * @return The content type passed by the browser or
130      * <code>null</code> if not defined.
131      */
132     public String getContentType()
133     {
134         return contentType;
135     }
136 
137     /***
138      * Provides a hint if the file contents will be read from memory.
139      *
140      * @return <code>True</code> if the file contents will be read
141      * from memory.
142      */
143     public boolean inMemory()
144     {
145         return (content != null || byteStream != null);
146     }
147 
148     /***
149      * Returns the size of the file.
150      *
151      * @return The size of the file.
152      */
153     public long getSize()
154     {
155         if (storeLocation != null)
156         {
157             return storeLocation.length();
158         }
159         else if (byteStream != null)
160         {
161             return byteStream.size();
162         }
163         else
164         {
165             return content.length;
166         }
167     }
168 
169     /***
170      * Returns the contents of the file as an array of bytes.  If the
171      * contents of the file were not yet cached int the memory, they
172      * will be loaded from the disk storage and chached.
173      *
174      * @return The contents of the file as an array of bytes.
175      */
176     public byte[] get()
177     {
178         if (content == null)
179         {
180             if (storeLocation != null)
181             {
182                 content = new byte[(int) getSize()];
183                 try
184                 {
185                     FileInputStream fis = new FileInputStream(storeLocation);
186                     fis.read(content);
187                 }
188                 catch (Exception e)
189                 {
190                     content = null;
191                 }
192             }
193             else
194             {
195                 content = byteStream.toByteArray();
196                 byteStream = null;
197             }
198         }
199         return content;
200     }
201 
202     /***
203      * Returns the contents of the file as a String, using default
204      * encoding.  This method uses {@link #get()} to retrieve the
205      * contents of the file.
206      *
207      * @return The contents of the file.
208      */
209     public String getString()
210     {
211         return new String(get());
212     }
213 
214     /***
215      * Returns the contents of the file as a String, using specified
216      * encoding.  This method uses {@link #get()} to retireve the
217      * contents of the file.<br>
218      *
219      * @param encoding The encoding to use.
220      * @return The contents of the file.
221      * @exception UnsupportedEncodingException.
222      */
223     public String getString(String encoding)
224             throws UnsupportedEncodingException
225     {
226         return new String(get(), encoding);
227     }
228 
229     /***
230      * Returns an {@link java.io.InputStream InputStream} that can be
231      * used to retrieve the contents of the file. (implements DataSource
232      * method)
233      *
234      * @return An {@link java.io.InputStream InputStream} that can be
235      * used to retrieve the contents of the file.
236      * @exception Exception, a generic exception.
237      */
238     public InputStream getInputStream()
239             throws IOException
240     {
241         return getStream();
242     }
243 
244     /***
245      * Returns an {@link java.io.InputStream InputStream} that can be
246      * used to retrieve the contents of the file.
247      *
248      * @return An {@link java.io.InputStream InputStream} that can be
249      * used to retrieve the contents of the file.
250      * @exception Exception, a generic exception.
251      */
252     public InputStream getStream()
253             throws IOException
254     {
255         if (content == null)
256         {
257             if (storeLocation != null)
258             {
259                 return new FileInputStream(storeLocation);
260             }
261             else
262             {
263                 content = byteStream.toByteArray();
264                 byteStream = null;
265             }
266         }
267         return new ByteArrayInputStream(content);
268     }
269 
270     /***
271      * Returns the {@link java.io.File} objects for the FileItems's
272      * data temporary location on the disk.  Note that for
273      * <code>FileItems</code> that have their data stored in memory
274      * this method will return <code>null</code>.  When handling large
275      * files, you can use {@link java.io.File#renameTo(File)} to
276      * move the file to new location without copying the data, if the
277      * source and destination locations reside within the same logical
278      * volume.
279      *
280      * @return A File.
281      */
282     public File getStoreLocation()
283     {
284         return storeLocation;
285     }
286 
287     /***
288      * Removes the file contents from the temporary storage.
289      */
290     protected void finalize()
291     {
292         if (storeLocation != null && storeLocation.exists())
293         {
294             storeLocation.delete();
295         }
296     }
297 
298     /***
299      * Returns an {@link java.io.OutputStream OutputStream} that can
300      * be used for storing the contents of the file.
301      * (implements DataSource method)
302      *
303      * @return an {@link java.io.OutputStream OutputStream} that can be
304      * used for storing the contensts of the file.
305      * @exception IOException.
306      */
307     public OutputStream getOutputStream()
308             throws IOException
309     {
310         if (storeLocation == null)
311         {
312             return byteStream;
313         }
314         else
315         {
316             return new FileOutputStream(storeLocation);
317         }
318     }
319 
320     /***
321      * Instantiates a FileItem.  It uses <code>requestSize</code> to
322      * decide what temporary storage approach the new item should
323      * take.  The largest request that will have its items cached in
324      * memory can be configured in
325      * <code>TurbineResources.properties</code> in the entry named
326      * <code>file.upload.size.threshold</code>
327      *
328      * @param path A String.
329      * @param name The original filename in the user's filesystem.
330      * @param contentType The content type passed by the browser or
331      * <code>null</code> if not defined.
332      * @param requestSize The total size of the POST request this item
333      * belongs to.
334      * @return A FileItem.
335      */
336     public static FileItem newInstance(String path,
337                                        String name,
338                                        String contentType,
339                                        int requestSize)
340     {
341         FileItem item = new FileItem(name, contentType);
342         if (requestSize > TurbineUpload.getSizeThreshold())
343         {
344             String instanceName = TurbineUniqueId.getInstanceId();
345             String fileName = TurbineUniqueId.getUniqueId();
346             fileName = instanceName + "_upload_" + fileName + ".tmp";
347             fileName = path + "/" + fileName;
348             item.storeLocation = new File(fileName);
349             item.storeLocation.deleteOnExit();
350         }
351         else
352         {
353             item.byteStream = new ByteArrayOutputStream();
354         }
355         return item;
356     }
357 
358     /***
359      * A convenience method to write an uploaded
360      * file to disk. The client code is not concerned
361      * whether or not the file is stored in memory,
362      * or on disk in a temporary location. They just
363      * want to write the uploaded file to disk.
364      *
365      * @param String full path to location where uploaded
366      *               should be stored.
367      */
368     public void write(String file) throws Exception
369     {
370         if (inMemory())
371         {
372             FileOutputStream fout = null;
373             try
374             {
375                 fout = new FileOutputStream(file);
376                 fout.write(get());
377             }
378             finally
379             {
380                 if (fout != null)
381                 {
382                     fout.close();
383                 }
384             }
385         }
386         else if (storeLocation != null)
387         {
388             /*
389              * The uploaded file is being stored on disk
390              * in a temporary location so move it to the
391              * desired file.
392              */
393             if (storeLocation.renameTo(new File(file)) == false)
394             {
395                 BufferedInputStream in = null;
396                 BufferedOutputStream out = null;
397                 try
398                 {
399                     in = new BufferedInputStream(
400                             new FileInputStream(storeLocation));
401                     out = new BufferedOutputStream(new FileOutputStream(file));
402                     byte[] bytes = new byte[2048];
403                     int s = 0;
404                     while ((s = in.read(bytes)) != -1)
405                     {
406                         out.write(bytes, 0, s);
407                     }
408                 }
409                 finally
410                 {
411                     try
412                     {
413                         in.close();
414                     }
415                     catch (Exception e)
416                     {
417                         // ignore
418                     }
419                     try
420                     {
421                         out.close();
422                     }
423                     catch (Exception e)
424                     {
425                         // ignore
426                     }
427                 }
428             }
429         }
430         else
431         {
432             /*
433              * For whatever reason we cannot write the
434              * file to disk.
435              */
436             throw new Exception("Cannot write uploaded file to disk!");
437         }
438     }
439 }