1 package org.apache.turbine.util.upload;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.BufferedInputStream;
58 import java.io.BufferedOutputStream;
59 import java.io.ByteArrayInputStream;
60 import java.io.ByteArrayOutputStream;
61 import java.io.File;
62 import java.io.FileInputStream;
63 import java.io.FileOutputStream;
64 import java.io.IOException;
65 import java.io.InputStream;
66 import java.io.OutputStream;
67 import java.io.UnsupportedEncodingException;
68 import javax.activation.DataSource;
69 import org.apache.turbine.services.uniqueid.TurbineUniqueId;
70 import org.apache.turbine.services.upload.TurbineUpload;
71
72 /***
73 * <p> This class represents a file that was received by Turbine using
74 * <code>multipart/form-data</code> POST request.
75 *
76 * <p> After retrieving an instance of this class from the {@link
77 * org.apache.turbine.util.ParameterParser ParameterParser} (see
78 * {@link org.apache.turbine.util.ParameterParser#getFileItem(String)
79 * ParameterParser.getFileItem(String)} and {@link
80 * org.apache.turbine.util.ParameterParser#getFileItems(String)
81 * ParameterParser.getFileItems(String)}) you can use it to acces the
82 * data that was sent by the browser. You may either request all
83 * contents of file at once using {@link #get()} or request an {@link
84 * java.io.InputStream InputStream} with {@link #getStream()} and
85 * process the file without attempting to load it into memory, which
86 * may come handy with large files.
87 *
88 * Implements the javax.activation.DataSource interface (which allows
89 * for example the adding of a FileItem as an attachment to a multipart
90 * email).
91 *
92 * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
93 * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
94 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
95 * @version $Id: FileItem.java,v 1.6 2002/07/11 16:53:19 mpoeschl Exp $
96 */
97 public class FileItem implements DataSource
98 {
99 /***
100 * The maximal size of request that will have it's elements stored
101 * in memory.
102 */
103 public static final int DEFAULT_UPLOAD_SIZE_THRESHOLD = 10240;
104
105 /*** The original filename in the user's filesystem. */
106 protected String fileName;
107
108 /***
109 * The content type passed by the browser or <code>null</code> if
110 * not defined.
111 */
112 protected String contentType;
113
114 /*** Cached contents of the file. */
115 protected byte[] content;
116
117 /*** Temporary storage location. */
118 protected File storeLocation;
119
120 /*** Temporary storage for in-memory files. */
121 protected ByteArrayOutputStream byteStream;
122
123
124 /***
125 * Constructs a new <code>FileItem</code>.
126 *
127 * <p>Use {@link #newInstance(String,String,String,int)} to
128 * instantiate <code>FileItems</code>.
129 *
130 * @param fileName The original filename in the user's filesystem.
131 * @param contentType The content type passed by the browser or
132 * <code>null</code> if not defined.
133 */
134 protected FileItem(String fileName, String contentType)
135 {
136 this.fileName = fileName;
137 this.contentType = contentType;
138 }
139
140 /***
141 * Returns the original filename in the user's filesystem.
142 * (implements DataSource method)
143 *
144 * @return The original filename in the user's filesystem.
145 */
146 public String getName()
147 {
148 return getFileName();
149 }
150
151 /***
152 * Returns the original filename in the user's filesystem.
153 *
154 * @return The original filename in the user's filesystem.
155 */
156 public String getFileName()
157 {
158 return fileName;
159 }
160
161 /***
162 * Returns the content type passed by the browser or
163 * <code>null</code> if not defined. (implements
164 * DataSource method).
165 *
166 * @return The content type passed by the browser or
167 * <code>null</code> if not defined.
168 */
169 public String getContentType()
170 {
171 return contentType;
172 }
173
174 /***
175 * Provides a hint if the file contents will be read from memory.
176 *
177 * @return <code>True</code> if the file contents will be read
178 * from memory.
179 */
180 public boolean inMemory()
181 {
182 return (content != null || byteStream != null);
183 }
184
185 /***
186 * Returns the size of the file.
187 *
188 * @return The size of the file.
189 */
190 public long getSize()
191 {
192 if (storeLocation != null)
193 {
194 return storeLocation.length();
195 }
196 else if (byteStream != null)
197 {
198 return byteStream.size();
199 }
200 else
201 {
202 return content.length;
203 }
204 }
205
206 /***
207 * Returns the contents of the file as an array of bytes. If the
208 * contents of the file were not yet cached int the memory, they
209 * will be loaded from the disk storage and chached.
210 *
211 * @return The contents of the file as an array of bytes.
212 */
213 public byte[] get()
214 {
215 if (content == null)
216 {
217 if (storeLocation != null)
218 {
219 content = new byte[(int) getSize()];
220 try
221 {
222 FileInputStream fis = new FileInputStream(storeLocation);
223 fis.read(content);
224 }
225 catch (Exception e)
226 {
227 content = null;
228 }
229 }
230 else
231 {
232 content = byteStream.toByteArray();
233 byteStream = null;
234 }
235 }
236 return content;
237 }
238
239 /***
240 * Returns the contents of the file as a String, using default
241 * encoding. This method uses {@link #get()} to retrieve the
242 * contents of the file.
243 *
244 * @return The contents of the file.
245 */
246 public String getString()
247 {
248 return new String(get());
249 }
250
251 /***
252 * Returns the contents of the file as a String, using specified
253 * encoding. This method uses {@link #get()} to retireve the
254 * contents of the file.<br>
255 *
256 * @param encoding The encoding to use.
257 * @return The contents of the file.
258 * @exception UnsupportedEncodingException.
259 */
260 public String getString( String encoding )
261 throws UnsupportedEncodingException
262 {
263 return new String(get(), encoding);
264 }
265
266 /***
267 * Returns an {@link java.io.InputStream InputStream} that can be
268 * used to retrieve the contents of the file. (implements DataSource
269 * method)
270 *
271 * @return An {@link java.io.InputStream InputStream} that can be
272 * used to retrieve the contents of the file.
273 * @exception Exception, a generic exception.
274 */
275 public InputStream getInputStream()
276 throws IOException
277 {
278 return getStream();
279 }
280
281 /***
282 * Returns an {@link java.io.InputStream InputStream} that can be
283 * used to retrieve the contents of the file.
284 *
285 * @return An {@link java.io.InputStream InputStream} that can be
286 * used to retrieve the contents of the file.
287 * @exception Exception, a generic exception.
288 */
289 public InputStream getStream()
290 throws IOException
291 {
292 if (content == null)
293 {
294 if (storeLocation != null)
295 {
296 return new FileInputStream(storeLocation);
297 }
298 else
299 {
300 content = byteStream.toByteArray();
301 byteStream = null;
302 }
303 }
304 return new ByteArrayInputStream(content);
305 }
306
307 /***
308 * Returns the {@link java.io.File} objects for the FileItems's
309 * data temporary location on the disk. Note that for
310 * <code>FileItems</code> that have their data stored in memory
311 * this method will return <code>null</code>. When handling large
312 * files, you can use {@link java.io.File#renameTo(File)} to
313 * move the file to new location without copying the data, if the
314 * source and destination locations reside within the same logical
315 * volume.
316 *
317 * @return A File.
318 */
319 public File getStoreLocation()
320 {
321 return storeLocation;
322 }
323
324 /***
325 * Removes the file contents from the temporary storage.
326 */
327 protected void finalize()
328 {
329 if (storeLocation != null && storeLocation.exists())
330 {
331 storeLocation.delete();
332 }
333 }
334
335 /***
336 * Returns an {@link java.io.OutputStream OutputStream} that can
337 * be used for storing the contents of the file.
338 * (implements DataSource method)
339 *
340 * @return an {@link java.io.OutputStream OutputStream} that can be
341 * used for storing the contensts of the file.
342 * @exception IOException.
343 */
344 public OutputStream getOutputStream()
345 throws IOException
346 {
347 if (storeLocation == null)
348 {
349 return byteStream;
350 }
351 else
352 {
353 return new FileOutputStream(storeLocation);
354 }
355 }
356
357 /***
358 * Instantiates a FileItem. It uses <code>requestSize</code> to
359 * decide what temporary storage approach the new item should
360 * take. The largest request that will have its items cached in
361 * memory can be configured in
362 * <code>TurbineResources.properties</code> in the entry named
363 * <code>file.upload.size.threshold</code>
364 *
365 * @param path A String.
366 * @param name The original filename in the user's filesystem.
367 * @param contentType The content type passed by the browser or
368 * <code>null</code> if not defined.
369 * @param requestSize The total size of the POST request this item
370 * belongs to.
371 * @return A FileItem.
372 */
373 public static FileItem newInstance(String path,
374 String name,
375 String contentType,
376 int requestSize)
377 {
378 FileItem item = new FileItem(name, contentType);
379 if (requestSize > TurbineUpload.getSizeThreshold())
380 {
381 String instanceName = TurbineUniqueId.getInstanceId();
382 String fileName = TurbineUniqueId.getUniqueId();
383 fileName = instanceName + "_upload_" + fileName + ".tmp";
384 fileName = path + "/" + fileName;
385 item.storeLocation = new File(fileName);
386 item.storeLocation.deleteOnExit();
387 }
388 else
389 {
390 item.byteStream = new ByteArrayOutputStream();
391 }
392 return item;
393 }
394
395 /***
396 * A convenience method to write an uploaded
397 * file to disk. The client code is not concerned
398 * whether or not the file is stored in memory,
399 * or on disk in a temporary location. They just
400 * want to write the uploaded file to disk.
401 *
402 * @param String full path to location where uploaded
403 * should be stored.
404 */
405 public void write(String file) throws Exception
406 {
407 if (inMemory())
408 {
409 FileOutputStream fout = null;
410 try
411 {
412 fout = new FileOutputStream(file);
413 fout.write(get());
414 }
415 finally
416 {
417 if (fout != null)
418 {
419 fout.close();
420 }
421 }
422 }
423 else if (storeLocation != null)
424 {
425 /*
426 * The uploaded file is being stored on disk
427 * in a temporary location so move it to the
428 * desired file.
429 */
430 if (storeLocation.renameTo(new File(file)) == false)
431 {
432 BufferedInputStream in = null;
433 BufferedOutputStream out = null;
434 try
435 {
436 in = new BufferedInputStream(
437 new FileInputStream(storeLocation));
438 out = new BufferedOutputStream(new FileOutputStream(file));
439 byte[] bytes = new byte[2048];
440 int s = 0;
441 while ((s = in.read(bytes)) != -1)
442 {
443 out.write(bytes, 0, s);
444 }
445 }
446 finally
447 {
448 try
449 {
450 in.close();
451 }
452 catch (Exception e)
453 {
454 // ignore
455 }
456 try
457 {
458 out.close();
459 }
460 catch (Exception e)
461 {
462 // ignore
463 }
464 }
465 }
466 }
467 else
468 {
469 /*
470 * For whatever reason we cannot write the
471 * file to disk.
472 */
473 throw new Exception("Cannot write uploaded file to disk!");
474 }
475 }
476 }
This page was automatically generated by Maven