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 */ 017package org.apache.wicket.util.io; 018 019import java.io.IOException; 020import java.io.OutputStream; 021 022 023/** 024 * An output stream which triggers an event when a specified number of bytes of data have been 025 * written to it. The event can be used, for example, to throw an exception if a maximum has been 026 * reached, or to switch the underlying stream type when the threshold is exceeded. 027 * <p> 028 * This class overrides all <code>OutputStream</code> methods. However, these overrides ultimately 029 * call the corresponding methods in the underlying output stream implementation. 030 * <p> 031 * NOTE: This implementation may trigger the event <em>before</em> the threshold is actually 032 * reached, since it triggers when a pending write operation would cause the threshold to be 033 * exceeded. 034 * 035 * @author <a href="mailto:martinc@apache.org">Martin Cooper</a> 036 * @version $Id$ 037 */ 038public abstract class ThresholdingOutputStream extends OutputStream 039{ 040 041 // ----------------------------------------------------------- Data members 042 043 044 /** 045 * The threshold at which the event will be triggered. 046 */ 047 private final int threshold; 048 049 050 /** 051 * The number of bytes written to the output stream. 052 */ 053 private long written; 054 055 056 /** 057 * Whether or not the configured threshold has been exceeded. 058 */ 059 private boolean thresholdExceeded; 060 061 062 // ----------------------------------------------------------- Constructors 063 064 065 /** 066 * Constructs an instance of this class which will trigger an event at the specified threshold. 067 * 068 * @param threshold 069 * The number of bytes at which to trigger an event. 070 */ 071 public ThresholdingOutputStream(final int threshold) 072 { 073 this.threshold = threshold; 074 } 075 076 077 // --------------------------------------------------- OutputStream methods 078 079 080 /** 081 * Writes the specified byte to this output stream. 082 * 083 * @param b 084 * The byte to be written. 085 * @exception IOException 086 * if an error occurs. 087 */ 088 @Override 089 public void write(final int b) throws IOException 090 { 091 checkThreshold(1); 092 getStream().write(b); 093 written++; 094 } 095 096 097 /** 098 * Writes <code>b.length</code> bytes from the specified byte array to this output stream. 099 * 100 * @param b 101 * The array of bytes to be written. 102 * @exception IOException 103 * if an error occurs. 104 */ 105 @Override 106 public void write(final byte b[]) throws IOException 107 { 108 checkThreshold(b.length); 109 getStream().write(b); 110 written += b.length; 111 } 112 113 114 /** 115 * Writes <code>len</code> bytes from the specified byte array starting at offset 116 * <code>off</code> to this output stream. 117 * 118 * @param b 119 * The byte array from which the data will be written. 120 * @param off 121 * The start offset in the byte array. 122 * @param len 123 * The number of bytes to write. 124 * @exception IOException 125 * if an error occurs. 126 */ 127 @Override 128 public void write(final byte b[], final int off, final 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 written out. 138 * 139 * @exception IOException 140 * 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 with this stream. 151 * 152 * @exception IOException 153 * 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 this output stream. 197 * 198 * @return <code>true</code> if the threshold has been reached; <code>false</code> otherwise. 199 */ 200 public boolean isThresholdExceeded() 201 { 202 return (written > threshold); 203 } 204 205 206 // ------------------------------------------------------ Protected methods 207 208 209 /** 210 * Checks to see if writing the specified number of bytes would cause the configured threshold 211 * to be exceeded. If so, triggers an event to allow a concrete implementation to take action on 212 * this. 213 * 214 * @param count 215 * The number of bytes about to be written to the underlying output stream. 216 * @exception IOException 217 * if an error occurs. 218 */ 219 protected void checkThreshold(final int count) throws IOException 220 { 221 if (!thresholdExceeded && (written + count > threshold)) 222 { 223 thresholdReached(); 224 thresholdExceeded = true; 225 } 226 } 227 228 229 // ------------------------------------------------------- Abstract methods 230 231 232 /** 233 * Returns the underlying output stream, to which the corresponding <code>OutputStream</code> 234 * methods in this class will ultimately delegate. 235 * 236 * @return The underlying output stream. 237 * @exception IOException 238 * if an error occurs. 239 */ 240 protected abstract OutputStream getStream() throws IOException; 241 242 243 /** 244 * Indicates that the configured threshold has been reached, and that a subclass should take 245 * whatever action necessary on this event. This may include changing the underlying output 246 * stream. 247 * 248 * @exception IOException 249 * if an error occurs. 250 */ 251 protected abstract void thresholdReached() throws IOException; 252}