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 (at) apache.org">Martin Cooper</a> 38 * 39 * @version $Id: ThresholdingOutputStream.java 540714 2007-05-22 19:39:44Z niallp $ 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 thresholdExceeded = true; 221 thresholdReached(); 222 } 223 } 224 225 /** 226 * Resets the byteCount to zero. You can call this from 227 * {@link #thresholdReached()} if you want the event to be triggered again. 228 */ 229 protected void resetByteCount() 230 { 231 this.thresholdExceeded = false; 232 this.written = 0; 233 } 234 235 // ------------------------------------------------------- Abstract methods 236 237 238 /** 239 * Returns the underlying output stream, to which the corresponding 240 * <code>OutputStream</code> methods in this class will ultimately delegate. 241 * 242 * @return The underlying output stream. 243 * 244 * @exception IOException if an error occurs. 245 */ 246 protected abstract OutputStream getStream() throws IOException; 247 248 249 /** 250 * Indicates that the configured threshold has been reached, and that a 251 * subclass should take whatever action necessary on this event. This may 252 * include changing the underlying output stream. 253 * 254 * @exception IOException if an error occurs. 255 */ 256 protected abstract void thresholdReached() throws IOException; 257 } 258