| package org.apache.turbine.util.upload; |
| |
| /* ==================================================================== |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2001-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Apache" and "Apache Software Foundation" and |
| * "Apache Turbine" must not be used to endorse or promote products |
| * derived from this software without prior written permission. For |
| * written permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * "Apache Turbine", nor may "Apache" appear in their name, without |
| * prior written permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import javax.activation.DataSource; |
| |
| import org.apache.turbine.services.uniqueid.TurbineUniqueId; |
| import org.apache.turbine.services.upload.TurbineUpload; |
| |
| /** |
| * <p> This class represents a file that was received by Turbine using |
| * <code>multipart/form-data</code> POST request. |
| * |
| * <p> After retrieving an instance of this class from the {@link |
| * org.apache.turbine.util.ParameterParser ParameterParser} (see |
| * {@link org.apache.turbine.util.ParameterParser#getFileItem(String) |
| * ParameterParser.getFileItem(String)} and {@link |
| * org.apache.turbine.util.ParameterParser#getFileItems(String) |
| * ParameterParser.getFileItems(String)}) you can use it to acces the |
| * data that was sent by the browser. You may either request all |
| * contents of file at once using {@link #get()} or request an {@link |
| * java.io.InputStream InputStream} with {@link #getStream()} and |
| * process the file without attempting to load it into memory, which |
| * may come handy with large files. |
| * |
| * Implements the javax.activation.DataSource interface (which allows |
| * for example the adding of a FileItem as an attachment to a multipart |
| * email). |
| * |
| * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a> |
| * @author <a href="mailto:sean@informage.net">Sean Legassick</a> |
| * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> |
| * @version $Id$ |
| * @deprecated use commons-fileupload instead |
| */ |
| public class FileItem implements DataSource |
| { |
| /** |
| * The maximal size of request that will have it's elements stored |
| * in memory. |
| */ |
| public static final int DEFAULT_UPLOAD_SIZE_THRESHOLD = 10240; |
| |
| /** The original filename in the user's filesystem. */ |
| protected String fileName; |
| |
| /** |
| * The content type passed by the browser or <code>null</code> if |
| * not defined. |
| */ |
| protected String contentType; |
| |
| /** Cached contents of the file. */ |
| protected byte[] content; |
| |
| /** Temporary storage location. */ |
| protected File storeLocation; |
| |
| /** Temporary storage for in-memory files. */ |
| protected ByteArrayOutputStream byteStream; |
| |
| /** |
| * Constructs a new <code>FileItem</code>. |
| * |
| * <p>Use {@link #newInstance(String,String,String,int)} to |
| * instantiate <code>FileItems</code>. |
| * |
| * @param fileName The original filename in the user's filesystem. |
| * @param contentType The content type passed by the browser or |
| * <code>null</code> if not defined. |
| */ |
| protected FileItem(String fileName, String contentType) |
| { |
| this.fileName = fileName; |
| this.contentType = contentType; |
| } |
| |
| /** |
| * Returns the original filename in the user's filesystem. |
| * (implements DataSource method) |
| * |
| * @return The original filename in the user's filesystem. |
| */ |
| public String getName() |
| { |
| return getFileName(); |
| } |
| |
| /** |
| * Returns the original filename in the user's filesystem. |
| * |
| * @return The original filename in the user's filesystem. |
| */ |
| public String getFileName() |
| { |
| return fileName; |
| } |
| |
| /** |
| * Returns the content type passed by the browser or |
| * <code>null</code> if not defined. (implements |
| * DataSource method). |
| * |
| * @return The content type passed by the browser or |
| * <code>null</code> if not defined. |
| */ |
| public String getContentType() |
| { |
| return contentType; |
| } |
| |
| /** |
| * Provides a hint if the file contents will be read from memory. |
| * |
| * @return <code>True</code> if the file contents will be read |
| * from memory. |
| */ |
| public boolean inMemory() |
| { |
| return (content != null || byteStream != null); |
| } |
| |
| /** |
| * Returns the size of the file. |
| * |
| * @return The size of the file. |
| */ |
| public long getSize() |
| { |
| if (storeLocation != null) |
| { |
| return storeLocation.length(); |
| } |
| else if (byteStream != null) |
| { |
| return byteStream.size(); |
| } |
| else |
| { |
| return content.length; |
| } |
| } |
| |
| /** |
| * Returns the contents of the file as an array of bytes. If the |
| * contents of the file were not yet cached int the memory, they |
| * will be loaded from the disk storage and chached. |
| * |
| * @return The contents of the file as an array of bytes. |
| */ |
| public byte[] get() |
| { |
| if (content == null) |
| { |
| if (storeLocation != null) |
| { |
| content = new byte[(int) getSize()]; |
| try |
| { |
| FileInputStream fis = new FileInputStream(storeLocation); |
| fis.read(content); |
| } |
| catch (Exception e) |
| { |
| content = null; |
| } |
| } |
| else |
| { |
| content = byteStream.toByteArray(); |
| byteStream = null; |
| } |
| } |
| return content; |
| } |
| |
| /** |
| * Returns the contents of the file as a String, using default |
| * encoding. This method uses {@link #get()} to retrieve the |
| * contents of the file. |
| * |
| * @return The contents of the file. |
| */ |
| public String getString() |
| { |
| return new String(get()); |
| } |
| |
| /** |
| * Returns the contents of the file as a String, using specified |
| * encoding. This method uses {@link #get()} to retireve the |
| * contents of the file.<br> |
| * |
| * @param encoding The encoding to use. |
| * @return The contents of the file. |
| * @exception UnsupportedEncodingException. |
| */ |
| public String getString(String encoding) |
| throws UnsupportedEncodingException |
| { |
| return new String(get(), encoding); |
| } |
| |
| /** |
| * Returns an {@link java.io.InputStream InputStream} that can be |
| * used to retrieve the contents of the file. (implements DataSource |
| * method) |
| * |
| * @return An {@link java.io.InputStream InputStream} that can be |
| * used to retrieve the contents of the file. |
| * @exception Exception, a generic exception. |
| */ |
| public InputStream getInputStream() |
| throws IOException |
| { |
| return getStream(); |
| } |
| |
| /** |
| * Returns an {@link java.io.InputStream InputStream} that can be |
| * used to retrieve the contents of the file. |
| * |
| * @return An {@link java.io.InputStream InputStream} that can be |
| * used to retrieve the contents of the file. |
| * @exception Exception, a generic exception. |
| */ |
| public InputStream getStream() |
| throws IOException |
| { |
| if (content == null) |
| { |
| if (storeLocation != null) |
| { |
| return new FileInputStream(storeLocation); |
| } |
| else |
| { |
| content = byteStream.toByteArray(); |
| byteStream = null; |
| } |
| } |
| return new ByteArrayInputStream(content); |
| } |
| |
| /** |
| * Returns the {@link java.io.File} objects for the FileItems's |
| * data temporary location on the disk. Note that for |
| * <code>FileItems</code> that have their data stored in memory |
| * this method will return <code>null</code>. When handling large |
| * files, you can use {@link java.io.File#renameTo(File)} to |
| * move the file to new location without copying the data, if the |
| * source and destination locations reside within the same logical |
| * volume. |
| * |
| * @return A File. |
| */ |
| public File getStoreLocation() |
| { |
| return storeLocation; |
| } |
| |
| /** |
| * Removes the file contents from the temporary storage. |
| */ |
| protected void finalize() |
| { |
| if (storeLocation != null && storeLocation.exists()) |
| { |
| storeLocation.delete(); |
| } |
| } |
| |
| /** |
| * Returns an {@link java.io.OutputStream OutputStream} that can |
| * be used for storing the contents of the file. |
| * (implements DataSource method) |
| * |
| * @return an {@link java.io.OutputStream OutputStream} that can be |
| * used for storing the contensts of the file. |
| * @exception IOException. |
| */ |
| public OutputStream getOutputStream() |
| throws IOException |
| { |
| if (storeLocation == null) |
| { |
| return byteStream; |
| } |
| else |
| { |
| return new FileOutputStream(storeLocation); |
| } |
| } |
| |
| /** |
| * Instantiates a FileItem. It uses <code>requestSize</code> to |
| * decide what temporary storage approach the new item should |
| * take. The largest request that will have its items cached in |
| * memory can be configured in |
| * <code>TurbineResources.properties</code> in the entry named |
| * <code>file.upload.size.threshold</code> |
| * |
| * @param path A String. |
| * @param name The original filename in the user's filesystem. |
| * @param contentType The content type passed by the browser or |
| * <code>null</code> if not defined. |
| * @param requestSize The total size of the POST request this item |
| * belongs to. |
| * @return A FileItem. |
| */ |
| public static FileItem newInstance(String path, |
| String name, |
| String contentType, |
| int requestSize) |
| { |
| FileItem item = new FileItem(name, contentType); |
| if (requestSize > TurbineUpload.getSizeThreshold()) |
| { |
| String instanceName = TurbineUniqueId.getInstanceId(); |
| String fileName = TurbineUniqueId.getUniqueId(); |
| fileName = instanceName + "_upload_" + fileName + ".tmp"; |
| fileName = path + "/" + fileName; |
| item.storeLocation = new File(fileName); |
| item.storeLocation.deleteOnExit(); |
| } |
| else |
| { |
| item.byteStream = new ByteArrayOutputStream(); |
| } |
| return item; |
| } |
| |
| /** |
| * A convenience method to write an uploaded |
| * file to disk. The client code is not concerned |
| * whether or not the file is stored in memory, |
| * or on disk in a temporary location. They just |
| * want to write the uploaded file to disk. |
| * |
| * @param String full path to location where uploaded |
| * should be stored. |
| */ |
| public void write(String file) throws Exception |
| { |
| if (inMemory()) |
| { |
| FileOutputStream fout = null; |
| try |
| { |
| fout = new FileOutputStream(file); |
| fout.write(get()); |
| } |
| finally |
| { |
| if (fout != null) |
| { |
| fout.close(); |
| } |
| } |
| } |
| else if (storeLocation != null) |
| { |
| /* |
| * The uploaded file is being stored on disk |
| * in a temporary location so move it to the |
| * desired file. |
| */ |
| if (storeLocation.renameTo(new File(file)) == false) |
| { |
| BufferedInputStream in = null; |
| BufferedOutputStream out = null; |
| try |
| { |
| in = new BufferedInputStream( |
| new FileInputStream(storeLocation)); |
| out = new BufferedOutputStream(new FileOutputStream(file)); |
| byte[] bytes = new byte[2048]; |
| int s = 0; |
| while ((s = in.read(bytes)) != -1) |
| { |
| out.write(bytes, 0, s); |
| } |
| } |
| finally |
| { |
| try |
| { |
| in.close(); |
| } |
| catch (Exception e) |
| { |
| // ignore |
| } |
| try |
| { |
| out.close(); |
| } |
| catch (Exception e) |
| { |
| // ignore |
| } |
| } |
| } |
| } |
| else |
| { |
| /* |
| * For whatever reason we cannot write the |
| * file to disk. |
| */ |
| throw new Exception("Cannot write uploaded file to disk!"); |
| } |
| } |
| } |