Home | History | Annotate | Download | only in output
      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