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