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 /**
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 736890 2009-01-23 02:02:22Z niallp $
040 */
041 public abstract class ThresholdingOutputStream
042 extends OutputStream
043 {
044
045 // ----------------------------------------------------------- Data members
046
047
048 /**
049 * The threshold at which the event will be triggered.
050 */
051 private final int threshold;
052
053
054 /**
055 * The number of bytes written to the output stream.
056 */
057 private long written;
058
059
060 /**
061 * Whether or not the configured threshold has been exceeded.
062 */
063 private boolean thresholdExceeded;
064
065
066 // ----------------------------------------------------------- Constructors
067
068
069 /**
070 * Constructs an instance of this class which will trigger an event at the
071 * specified threshold.
072 *
073 * @param threshold The number of bytes at which to trigger an event.
074 */
075 public ThresholdingOutputStream(int threshold)
076 {
077 this.threshold = threshold;
078 }
079
080
081 // --------------------------------------------------- OutputStream methods
082
083
084 /**
085 * Writes the specified byte to this output stream.
086 *
087 * @param b The byte to be written.
088 *
089 * @exception IOException if an error occurs.
090 */
091 @Override
092 public void write(int b) throws IOException
093 {
094 checkThreshold(1);
095 getStream().write(b);
096 written++;
097 }
098
099
100 /**
101 * Writes <code>b.length</code> bytes from the specified byte array to this
102 * output stream.
103 *
104 * @param b The array of bytes to be written.
105 *
106 * @exception IOException if an error occurs.
107 */
108 @Override
109 public void write(byte b[]) throws IOException
110 {
111 checkThreshold(b.length);
112 getStream().write(b);
113 written += b.length;
114 }
115
116
117 /**
118 * Writes <code>len</code> bytes from the specified byte array starting at
119 * offset <code>off</code> to this output stream.
120 *
121 * @param b The byte array from which the data will be written.
122 * @param off The start offset in the byte array.
123 * @param len The number of bytes to write.
124 *
125 * @exception IOException if an error occurs.
126 */
127 @Override
128 public void write(byte b[], int off, int len) throws IOException
129 {
130 checkThreshold(len);
131 getStream().write(b, off, len);
132 written += len;
133 }
134
135
136 /**
137 * Flushes this output stream and forces any buffered output bytes to be
138 * written out.
139 *
140 * @exception IOException if an error occurs.
141 */
142 @Override
143 public void flush() throws IOException
144 {
145 getStream().flush();
146 }
147
148
149 /**
150 * Closes this output stream and releases any system resources associated
151 * with this stream.
152 *
153 * @exception IOException if an error occurs.
154 */
155 @Override
156 public void close() throws IOException
157 {
158 try
159 {
160 flush();
161 }
162 catch (IOException ignored)
163 {
164 // ignore
165 }
166 getStream().close();
167 }
168
169
170 // --------------------------------------------------------- Public methods
171
172
173 /**
174 * Returns the threshold, in bytes, at which an event will be triggered.
175 *
176 * @return The threshold point, in bytes.
177 */
178 public int getThreshold()
179 {
180 return threshold;
181 }
182
183
184 /**
185 * Returns the number of bytes that have been written to this output stream.
186 *
187 * @return The number of bytes written.
188 */
189 public long getByteCount()
190 {
191 return written;
192 }
193
194
195 /**
196 * Determines whether or not the configured threshold has been exceeded for
197 * this output stream.
198 *
199 * @return <code>true</code> if the threshold has been reached;
200 * <code>false</code> otherwise.
201 */
202 public boolean isThresholdExceeded()
203 {
204 return (written > threshold);
205 }
206
207
208 // ------------------------------------------------------ Protected methods
209
210
211 /**
212 * Checks to see if writing the specified number of bytes would cause the
213 * configured threshold to be exceeded. If so, triggers an event to allow
214 * a concrete implementation to take action on this.
215 *
216 * @param count The number of bytes about to be written to the underlying
217 * output stream.
218 *
219 * @exception IOException if an error occurs.
220 */
221 protected void checkThreshold(int count) throws IOException
222 {
223 if (!thresholdExceeded && (written + count > threshold))
224 {
225 thresholdExceeded = true;
226 thresholdReached();
227 }
228 }
229
230 /**
231 * Resets the byteCount to zero. You can call this from
232 * {@link #thresholdReached()} if you want the event to be triggered again.
233 */
234 protected void resetByteCount()
235 {
236 this.thresholdExceeded = false;
237 this.written = 0;
238 }
239
240 // ------------------------------------------------------- Abstract methods
241
242
243 /**
244 * Returns the underlying output stream, to which the corresponding
245 * <code>OutputStream</code> methods in this class will ultimately delegate.
246 *
247 * @return The underlying output stream.
248 *
249 * @exception IOException if an error occurs.
250 */
251 protected abstract OutputStream getStream() throws IOException;
252
253
254 /**
255 * Indicates that the configured threshold has been reached, and that a
256 * subclass should take whatever action necessary on this event. This may
257 * include changing the underlying output stream.
258 *
259 * @exception IOException if an error occurs.
260 */
261 protected abstract void thresholdReached() throws IOException;
262 }