1 package org.apache.turbine.util.upload;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
390
391
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
418 }
419 try
420 {
421 out.close();
422 }
423 catch (Exception e)
424 {
425
426 }
427 }
428 }
429 }
430 else
431 {
432
433
434
435
436 throw new Exception("Cannot write uploaded file to disk!");
437 }
438 }
439 }