001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.core.misc.upload;
066:
067: import com.jcorporate.expresso.core.misc.StringUtil;
068: import org.apache.struts.upload.FormFile;
069:
070: import javax.activation.DataSource;
071: import java.io.ByteArrayInputStream;
072: import java.io.ByteArrayOutputStream;
073: import java.io.File;
074: import java.io.FileInputStream;
075: import java.io.FileNotFoundException;
076: import java.io.FileOutputStream;
077: import java.io.IOException;
078: import java.io.InputStream;
079: import java.io.OutputStream;
080: import java.io.UnsupportedEncodingException;
081:
082: /**
083: * <p> This class represents a file that was received by Turbine using
084: * <code>multipart/form-data</code> POST request.
085: * <p/>
086: * <p> After retrieving an instance of this class from the {@link
087: * org.apache.turbine.util.ParameterParser ParameterParser} (see
088: * {@link org.apache.turbine.util.ParameterParser#getFileItem(String)
089: * ParameterParser.getFileItem(String)} and {@link
090: * org.apache.turbine.util.ParameterParser#getFileItems(String)
091: * ParameterParser.getFileItems(String)}) you can use it to acces the
092: * data that was sent by the browser. You may either request all
093: * contents of file at once using {@link #get()} or request an {@link
094: * java.io.InputStream InputStream} with {@link #getStream()} and
095: * process the file without attempting to load it into memory, which
096: * may come handy with large files.
097: *
098: * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
099: * @version $Id: FileItem.java,v 1.8 2004/11/17 20:48:13 lhamel Exp $
100: */
101: public class FileItem implements FormFile, DataSource {
102:
103: /**
104: * The maximal size of request that will have it's elements stored
105: * in memory.
106: */
107: public static final int DEFAULT_UPLOAD_SIZE_THRESHOLD = 10240;
108:
109: /**
110: * The original filename in the user's filesystem.
111: */
112: protected String fileName;
113:
114: /**
115: * The content type passed by the browser or <code>null</code> if
116: * not defined.
117: */
118: protected String contentType;
119:
120: /**
121: * Cached contents of the file.
122: */
123: protected byte[] content;
124:
125: /**
126: * Temporary storage location.
127: */
128: protected File storeLocation = null;
129:
130: /**
131: * Temporary storage for in-memory files.
132: */
133: protected ByteArrayOutputStream byteStream;
134:
135: /**
136: * Constructs a new <code>FileItem</code>.
137: * <p/>
138: * <p>Use {@link #newInstance(String,String,String,int)} to
139: * instantiate <code>FileItems</code>.
140: *
141: * @param fileName The original filename in the user's filesystem.
142: * @param contentType The content type passed by the browser or
143: * <code>null</code> if not defined.
144: */
145: protected FileItem(String fileName, String contentType) {
146: this .fileName = fileName;
147: this .contentType = contentType;
148: }
149:
150: /**
151: * Returns the original filename in the user's filesystem.
152: *
153: * @return The original filename in the user's filesystem.
154: */
155: public String getFileName() {
156: return fileName;
157: }
158:
159: /**
160: * Returns the content type passed by the browser or
161: * <code>null</code> if not defined.
162: *
163: * @return The content type passed by the browser or
164: * <code>null</code> if not defined.
165: */
166: public String getContentType() {
167: return contentType;
168: }
169:
170: /**
171: * Provides a hint if the file contents will be read from memory.
172: *
173: * @return <code>True</code> if the file contents will be read
174: * from memory.
175: */
176: public boolean inMemory() {
177: return (content != null || byteStream != null);
178: }
179:
180: /**
181: * Returns the size of the file.
182: *
183: * @return The size of the file.
184: */
185: public long getSize() {
186: if (storeLocation != null) {
187: return storeLocation.length();
188: } else if (byteStream != null) {
189: return byteStream.size();
190: } else {
191: return content.length;
192: }
193: }
194:
195: /**
196: * Returns the contents of the file as an array of bytes. If the
197: * contents of the file were not yet cached int the memory, they
198: * will be loaded from the disk storage and chached.
199: *
200: * @return The contents of the file as an array of bytes.
201: */
202: public byte[] get() {
203: if (content == null) {
204: if (storeLocation != null) {
205: content = new byte[(int) getSize()];
206:
207: try {
208: FileInputStream fis = new FileInputStream(
209: storeLocation);
210: fis.read(content);
211: } catch (Exception e) {
212: content = null;
213: }
214: } else {
215: content = byteStream.toByteArray();
216: byteStream = null;
217: }
218: }
219:
220: return content;
221: }
222:
223: /**
224: * Returns the contents of the file as a String, using default
225: * encoding. This method uses {@link #get()} to retrieve the
226: * contents of the file.
227: *
228: * @return The contents of the file.
229: */
230: public String getString() {
231: return new String(get());
232: }
233:
234: /**
235: * Returns the contents of the file as a String, using specified
236: * encoding. This method uses {@link #get()} to retireve the
237: * contents of the file.<br>
238: *
239: * @param encoding The encoding to use.
240: * @return The contents of the file.
241: */
242: public String getString(String encoding)
243: throws UnsupportedEncodingException {
244: return new String(get(), encoding);
245: }
246:
247: /**
248: * Returns an {@link java.io.InputStream InputStream} that can be
249: * used to retrieve the contents of the file.
250: *
251: * @return An {@link java.io.InputStream InputStream} that can be
252: * used to retrieve the contents of the file.
253: * @throws Exception A generic exception.
254: */
255: public InputStream getStream() throws Exception {
256: if (content == null) {
257: if (storeLocation != null) {
258: try {
259: return new FileInputStream(storeLocation);
260: } catch (FileNotFoundException e) {
261: throw new Exception(
262: "FileItem: stored item was lost");
263: }
264: } else {
265: content = byteStream.toByteArray();
266: byteStream = null;
267: }
268: }
269:
270: return new ByteArrayInputStream(content);
271: }
272:
273: /**
274: * Returns the {@link java.io.File} objects for the FileItems's
275: * data temporary location on the disk. Note that for
276: * <code>FileItems</code> that have their data stored in memory
277: * this method will return <code>null</code>. When handling large
278: * files, you can use {@link java.io.File#renameTo(File)} to
279: * move the file to new location without copying the data, if the
280: * source and destination locations reside within the same logical
281: * volume.
282: *
283: * @return A File.
284: */
285: public File getStoreLocation() {
286: return storeLocation;
287: }
288:
289: /**
290: * Returns an {@link java.io.OutputStream OutputStream} that can
291: * be used for storing the contensts of the file.
292: *
293: * @return an {@link java.io.OutputStream OutputStream} that can be
294: * used for storing the contensts of the file.
295: */
296: public OutputStream getOutputStream() throws IOException {
297: if (storeLocation == null) {
298: return byteStream;
299: } else {
300: return new FileOutputStream(storeLocation);
301: }
302: }
303:
304: /**
305: * Instantiates a FileItem. It uses <code>requestSize</code> to
306: * decide what temporary storage approach the new item should
307: * take. The largest request that will have its items cached in
308: * memory can be configured in
309: * <code>TurbineResources.properties</code> in the entry named
310: * <code>file.upload.size.threshold</code>
311: *
312: * @param path A String.
313: * @param name The original filename in the user's filesystem.
314: * @param contentType The content type passed by the browser or
315: * <code>null</code> if not defined.
316: * @param requestSize The total size of the POST request this item
317: * belongs to.
318: * @param storeAsFile Set to true if you want it stored as a local file.
319: * @return A FileItem.
320: */
321: public static FileItem newInstance(String path, String name,
322: String contentType, int requestSize, boolean storeAsFile) {
323: FileItem item = new FileItem(name, contentType);
324:
325: if (storeAsFile) {
326:
327: /* if we need to stash it in a file */
328: try {
329:
330: // NextNumber myNext = new NextNumber();
331: // myNext.setDBName("default");
332: // Temporary filename becomes <path>/upload<seq-num>-<orig name>
333: name = StringUtil.replace(name, "\\", "/");
334:
335: File tmpFile = new File(name);
336:
337: // String fileName = path + "upload" + myNext.getNext("UPFILE")
338: // + "-" + tmpFile.getName();
339: File tempDir = new File(path);
340: tempDir.mkdirs();
341:
342: //New method use SDK's version to create a temp file with
343: //the appropriate prefix and suffix
344: item.storeLocation = File.createTempFile("upload", "-"
345: + tmpFile.getName(), tempDir);
346:
347: // item.storeLocation = new File(fileName);
348: } catch (IOException de) {
349: throw new IllegalArgumentException(
350: "Unable to create upload temp file "
351: + de.getMessage());
352: }
353: } else {
354: item.byteStream = new ByteArrayOutputStream();
355: }
356:
357: return item;
358: }
359:
360: /** Methods required by the Struts FormFile interface */
361: /**
362: * Set the content type for this file
363: *
364: * @param contentType The content type
365: */
366: public void setContentType(String contentType) {
367: this .contentType = contentType;
368: }
369:
370: /**
371: * Get the size of this file
372: *
373: * @return An int representing the size of the file in bytes
374: */
375: public int getFileSize() {
376: return new Long(getSize()).intValue();
377: }
378:
379: /**
380: * Set the file size
381: *
382: * @param filesize An int reprsenting the size of the file in bytes
383: */
384: public void setFileSize(int filesize) {
385:
386: /* Ignore this */
387: }
388:
389: /**
390: * Set the filename of this file
391: *
392: * @param newFileName The name of the file
393: */
394: public void setFileName(String newFileName) {
395: fileName = newFileName;
396: }
397:
398: /**
399: * Get the data in byte array for for this file. Note that this can be
400: * a very hazardous method, files can be large enough to cause
401: * OutOfMemoryErrors. Short of being deprecated, it's strongly recommended
402: * that you use {@link #getInputStream() getInputStream} to get the file
403: * data.
404: *
405: * @return An array of bytes representing the data contained
406: * in the form file
407: * @throws FileNotFoundException If some sort of file representation
408: * cannot be found for the FormFile
409: * @throws IOException If there is some sort of IOException
410: */
411: public byte[] getFileData() throws FileNotFoundException,
412: IOException {
413: byte[] b = null;
414: getInputStream().read(b);
415:
416: return b;
417: }
418:
419: /**
420: * Get an InputStream that represents this file. This is the preferred
421: * method of getting file data.
422: *
423: * @return an InputStream object.
424: * @throws FileNotFoundException If some sort of file representation
425: * cannot be found for the FormFile
426: * @throws IOException If there is some sort of IOException
427: */
428: public InputStream getInputStream() throws FileNotFoundException,
429: IOException {
430: return new FileInputStream(getFileName());
431: }
432:
433: /**
434: * Destroy all content for this form file.
435: * Implementations should remove any temporary
436: * files or any temporary file data stored somewhere
437: */
438: public void destroy() {
439: File theFile = new File(getFileName());
440: theFile.delete();
441: }
442:
443: /**
444: * Returns the name of the FileItem
445: *
446: * @return java.lang.String
447: */
448: public String getName() {
449: return this.fileName;
450: }
451: }
|