1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.io.output;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21
22
23 /**
24 * An output stream which triggers an event when a specified number of bytes of
25 * data have been written to it. The event can be used, for example, to throw
26 * an exception if a maximum has been reached, or to switch the underlying
27 * stream type when the threshold is exceeded.
28 * <p>
29 * This class overrides all <code>OutputStream</code> methods. However, these
30 * overrides ultimately call the corresponding methods in the underlying output
31 * stream implementation.
32 * <p>
33 * NOTE: This implementation may trigger the event <em>before</em> the threshold
34 * is actually reached, since it triggers when a pending write operation would
35 * cause the threshold to be exceeded.
36 *
37 * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
38 *
39 * @version $Id: ThresholdingOutputStream.java 437680 2006-08-28 11:57:00Z scolebourne $
40 */
41 public abstract class ThresholdingOutputStream
42 extends OutputStream
43 {
44
45 // ----------------------------------------------------------- Data members
46
47
48 /**
49 * The threshold at which the event will be triggered.
50 */
51 private int threshold;
52
53
54 /**
55 * The number of bytes written to the output stream.
56 */
57 private long written;
58
59
60 /**
61 * Whether or not the configured threshold has been exceeded.
62 */
63 private boolean thresholdExceeded;
64
65
66 // ----------------------------------------------------------- Constructors
67
68
69 /**
70 * Constructs an instance of this class which will trigger an event at the
71 * specified threshold.
72 *
73 * @param threshold The number of bytes at which to trigger an event.
74 */
75 public ThresholdingOutputStream(int threshold)
76 {
77 this.threshold = threshold;
78 }
79
80
81 // --------------------------------------------------- OutputStream methods
82
83
84 /**
85 * Writes the specified byte to this output stream.
86 *
87 * @param b The byte to be written.
88 *
89 * @exception IOException if an error occurs.
90 */
91 public void write(int b) throws IOException
92 {
93 checkThreshold(1);
94 getStream().write(b);
95 written++;
96 }
97
98
99 /**
100 * Writes <code>b.length</code> bytes from the specified byte array to this
101 * output stream.
102 *
103 * @param b The array of bytes to be written.
104 *
105 * @exception IOException if an error occurs.
106 */
107 public void write(byte b[]) throws IOException
108 {
109 checkThreshold(b.length);
110 getStream().write(b);
111 written += b.length;
112 }
113
114
115 /**
116 * Writes <code>len</code> bytes from the specified byte array starting at
117 * offset <code>off</code> to this output stream.
118 *
119 * @param b The byte array from which the data will be written.
120 * @param off The start offset in the byte array.
121 * @param len The number of bytes to write.
122 *
123 * @exception IOException if an error occurs.
124 */
125 public void write(byte b[], int off, int len) throws IOException
126 {
127 checkThreshold(len);
128 getStream().write(b, off, len);
129 written += len;
130 }
131
132
133 /**
134 * Flushes this output stream and forces any buffered output bytes to be
135 * written out.
136 *
137 * @exception IOException if an error occurs.
138 */
139 public void flush() throws IOException
140 {
141 getStream().flush();
142 }
143
144
145 /**
146 * Closes this output stream and releases any system resources associated
147 * with this stream.
148 *
149 * @exception IOException if an error occurs.
150 */
151 public void close() throws IOException
152 {
153 try
154 {
155 flush();
156 }
157 catch (IOException ignored)
158 {
159 // ignore
160 }
161 getStream().close();
162 }
163
164
165 // --------------------------------------------------------- Public methods
166
167
168 /**
169 * Returns the threshold, in bytes, at which an event will be triggered.
170 *
171 * @return The threshold point, in bytes.
172 */
173 public int getThreshold()
174 {
175 return threshold;
176 }
177
178
179 /**
180 * Returns the number of bytes that have been written to this output stream.
181 *
182 * @return The number of bytes written.
183 */
184 public long getByteCount()
185 {
186 return written;
187 }
188
189
190 /**
191 * Determines whether or not the configured threshold has been exceeded for
192 * this output stream.
193 *
194 * @return <code>true</code> if the threshold has been reached;
195 * <code>false</code> otherwise.
196 */
197 public boolean isThresholdExceeded()
198 {
199 return (written > threshold);
200 }
201
202
203 // ------------------------------------------------------ Protected methods
204
205
206 /**
207 * Checks to see if writing the specified number of bytes would cause the
208 * configured threshold to be exceeded. If so, triggers an event to allow
209 * a concrete implementation to take action on this.
210 *
211 * @param count The number of bytes about to be written to the underlying
212 * output stream.
213 *
214 * @exception IOException if an error occurs.
215 */
216 protected void checkThreshold(int count) throws IOException
217 {
218 if (!thresholdExceeded && (written + count > threshold))
219 {
220 thresholdReached();
221 thresholdExceeded = true;
222 }
223 }
224
225
226 // ------------------------------------------------------- Abstract methods
227
228
229 /**
230 * Returns the underlying output stream, to which the corresponding
231 * <code>OutputStream</code> methods in this class will ultimately delegate.
232 *
233 * @return The underlying output stream.
234 *
235 * @exception IOException if an error occurs.
236 */
237 protected abstract OutputStream getStream() throws IOException;
238
239
240 /**
241 * Indicates that the configured threshold has been reached, and that a
242 * subclass should take whatever action necessary on this event. This may
243 * include changing the underlying output stream.
244 *
245 * @exception IOException if an error occurs.
246 */
247 protected abstract void thresholdReached() throws IOException;
248 }