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 }