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.IOException;
021: import java.io.OutputStream;
022:
023: /**
024: * An output stream which triggers an event when a specified number of bytes of
025: * data have been written to it. The event can be used, for example, to throw
026: * an exception if a maximum has been reached, or to switch the underlying
027: * stream type when the threshold is exceeded.
028: * <p>
029: * This class overrides all <code>OutputStream</code> methods. However, these
030: * overrides ultimately call the corresponding methods in the underlying output
031: * stream implementation.
032: * <p>
033: * NOTE: This implementation may trigger the event <em>before</em> the threshold
034: * is actually reached, since it triggers when a pending write operation would
035: * cause the threshold to be exceeded.
036: *
037: * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
038: *
039: * @version $Id: ThresholdingOutputStream.java 467222 2006-10-24 03:17:11Z markt $
040: */
041: public abstract class ThresholdingOutputStream extends OutputStream {
042:
043: // ----------------------------------------------------------- Data members
044:
045: /**
046: * The threshold at which the event will be triggered.
047: */
048: private int threshold;
049:
050: /**
051: * The number of bytes written to the output stream.
052: */
053: private long written;
054:
055: /**
056: * Whether or not the configured threshold has been exceeded.
057: */
058: private boolean thresholdExceeded;
059:
060: // ----------------------------------------------------------- Constructors
061:
062: /**
063: * Constructs an instance of this class which will trigger an event at the
064: * specified threshold.
065: *
066: * @param threshold The number of bytes at which to trigger an event.
067: */
068: public ThresholdingOutputStream(int threshold) {
069: this .threshold = threshold;
070: }
071:
072: // --------------------------------------------------- OutputStream methods
073:
074: /**
075: * Writes the specified byte to this output stream.
076: *
077: * @param b The byte to be written.
078: *
079: * @exception IOException if an error occurs.
080: */
081: public void write(int b) throws IOException {
082: checkThreshold(1);
083: getStream().write(b);
084: written++;
085: }
086:
087: /**
088: * Writes <code>b.length</code> bytes from the specified byte array to this
089: * output stream.
090: *
091: * @param b The array of bytes to be written.
092: *
093: * @exception IOException if an error occurs.
094: */
095: public void write(byte b[]) throws IOException {
096: checkThreshold(b.length);
097: getStream().write(b);
098: written += b.length;
099: }
100:
101: /**
102: * Writes <code>len</code> bytes from the specified byte array starting at
103: * offset <code>off</code> to this output stream.
104: *
105: * @param b The byte array from which the data will be written.
106: * @param off The start offset in the byte array.
107: * @param len The number of bytes to write.
108: *
109: * @exception IOException if an error occurs.
110: */
111: public void write(byte b[], int off, int len) throws IOException {
112: checkThreshold(len);
113: getStream().write(b, off, len);
114: written += len;
115: }
116:
117: /**
118: * Flushes this output stream and forces any buffered output bytes to be
119: * written out.
120: *
121: * @exception IOException if an error occurs.
122: */
123: public void flush() throws IOException {
124: getStream().flush();
125: }
126:
127: /**
128: * Closes this output stream and releases any system resources associated
129: * with this stream.
130: *
131: * @exception IOException if an error occurs.
132: */
133: public void close() throws IOException {
134: try {
135: flush();
136: } catch (IOException ignored) {
137: // ignore
138: }
139: getStream().close();
140: }
141:
142: // --------------------------------------------------------- Public methods
143:
144: /**
145: * Returns the threshold, in bytes, at which an event will be triggered.
146: *
147: * @return The threshold point, in bytes.
148: */
149: public int getThreshold() {
150: return threshold;
151: }
152:
153: /**
154: * Returns the number of bytes that have been written to this output stream.
155: *
156: * @return The number of bytes written.
157: */
158: public long getByteCount() {
159: return written;
160: }
161:
162: /**
163: * Determines whether or not the configured threshold has been exceeded for
164: * this output stream.
165: *
166: * @return <code>true</code> if the threshold has been reached;
167: * <code>false</code> otherwise.
168: */
169: public boolean isThresholdExceeded() {
170: return (written > threshold);
171: }
172:
173: // ------------------------------------------------------ Protected methods
174:
175: /**
176: * Checks to see if writing the specified number of bytes would cause the
177: * configured threshold to be exceeded. If so, triggers an event to allow
178: * a concrete implementation to take action on this.
179: *
180: * @param count The number of bytes about to be written to the underlying
181: * output stream.
182: *
183: * @exception IOException if an error occurs.
184: */
185: protected void checkThreshold(int count) throws IOException {
186: if (!thresholdExceeded && (written + count > threshold)) {
187: thresholdReached();
188: thresholdExceeded = true;
189: }
190: }
191:
192: // ------------------------------------------------------- Abstract methods
193:
194: /**
195: * Returns the underlying output stream, to which the corresponding
196: * <code>OutputStream</code> methods in this class will ultimately delegate.
197: *
198: * @return The underlying output stream.
199: *
200: * @exception IOException if an error occurs.
201: */
202: protected abstract OutputStream getStream() throws IOException;
203:
204: /**
205: * Indicates that the configured threshold has been reached, and that a
206: * subclass should take whatever action necessary on this event. This may
207: * include changing the underlying output stream.
208: *
209: * @exception IOException if an error occurs.
210: */
211: protected abstract void thresholdReached() throws IOException;
212: }
|