001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.tomcat.util.http.fileupload;
019:
020: import java.io.ByteArrayOutputStream;
021: import java.io.File;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.io.OutputStream;
025:
026: /**
027: * <p>An output stream which will retain data in memory until a specified
028: * threshold is reached, and only then commit it to disk. If the stream is
029: * closed before the threshold is reached, the data will not be written to
030: * disk at all.</p>
031: *
032: * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
033: *
034: * @version $Id: DeferredFileOutputStream.java 467222 2006-10-24 03:17:11Z markt $
035: */
036: public class DeferredFileOutputStream extends ThresholdingOutputStream {
037:
038: // ----------------------------------------------------------- Data members
039:
040: /**
041: * The output stream to which data will be written prior to the theshold
042: * being reached.
043: */
044: private ByteArrayOutputStream memoryOutputStream;
045:
046: /**
047: * The output stream to which data will be written after the theshold is
048: * reached.
049: */
050: private FileOutputStream diskOutputStream;
051:
052: /**
053: * The output stream to which data will be written at any given time. This
054: * will always be one of <code>memoryOutputStream</code> or
055: * <code>diskOutputStream</code>.
056: */
057: private OutputStream currentOutputStream;
058:
059: /**
060: * The file to which output will be directed if the threshold is exceeded.
061: */
062: private File outputFile;
063:
064: // ----------------------------------------------------------- Constructors
065:
066: /**
067: * Constructs an instance of this class which will trigger an event at the
068: * specified threshold, and save data to a file beyond that point.
069: *
070: * @param threshold The number of bytes at which to trigger an event.
071: * @param outputFile The file to which data is saved beyond the threshold.
072: */
073: public DeferredFileOutputStream(int threshold, File outputFile) {
074: super (threshold);
075: this .outputFile = outputFile;
076:
077: memoryOutputStream = new ByteArrayOutputStream(threshold);
078: currentOutputStream = memoryOutputStream;
079: }
080:
081: // --------------------------------------- ThresholdingOutputStream methods
082:
083: /**
084: * Returns the current output stream. This may be memory based or disk
085: * based, depending on the current state with respect to the threshold.
086: *
087: * @return The underlying output stream.
088: *
089: * @exception IOException if an error occurs.
090: */
091: protected OutputStream getStream() throws IOException {
092: return currentOutputStream;
093: }
094:
095: /**
096: * Switches the underlying output stream from a memory based stream to one
097: * that is backed by disk. This is the point at which we realise that too
098: * much data is being written to keep in memory, so we elect to switch to
099: * disk-based storage.
100: *
101: * @exception IOException if an error occurs.
102: */
103: protected void thresholdReached() throws IOException {
104: byte[] data = memoryOutputStream.toByteArray();
105: FileOutputStream fos = new FileOutputStream(outputFile);
106: fos.write(data);
107: diskOutputStream = fos;
108: currentOutputStream = fos;
109: memoryOutputStream = null;
110: }
111:
112: // --------------------------------------------------------- Public methods
113:
114: /**
115: * Determines whether or not the data for this output stream has been
116: * retained in memory.
117: *
118: * @return <code>true</code> if the data is available in memory;
119: * <code>false</code> otherwise.
120: */
121: public boolean isInMemory() {
122: return (!isThresholdExceeded());
123: }
124:
125: /**
126: * Returns the data for this output stream as an array of bytes, assuming
127: * that the data has been retained in memory. If the data was written to
128: * disk, this method returns <code>null</code>.
129: *
130: * @return The data for this output stream, or <code>null</code> if no such
131: * data is available.
132: */
133: public byte[] getData() {
134: if (memoryOutputStream != null) {
135: return memoryOutputStream.toByteArray();
136: }
137: return null;
138: }
139:
140: /**
141: * Returns the data for this output stream as a <code>File</code>, assuming
142: * that the data was written to disk. If the data was retained in memory,
143: * this method returns <code>null</code>.
144: *
145: * @return The file for this output stream, or <code>null</code> if no such
146: * file exists.
147: */
148: public File getFile() {
149: return outputFile;
150: }
151: }
|