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