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