001    /*
002     * Copyright 2012 UnboundID Corp.
003     *
004     * This program is free software; you can redistribute it and/or modify
005     * it under the terms of the GNU General Public License (GPLv2 only)
006     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007     * as published by the Free Software Foundation.
008     *
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, see <http://www.gnu.org/licenses>.
016     */
017    
018    package com.unboundid.scim.marshal;
019    
020    import java.io.FilterInputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.util.concurrent.atomic.AtomicLong;
024    
025    
026    
027    /**
028     * This class is a wrapper around an input stream that allows us to determine
029     * how many bytes have been read from the stream.
030     */
031    public class BulkInputStreamWrapper extends FilterInputStream
032    {
033      // The number of bytes read from the stream.
034      private final AtomicLong bytesRead;
035    
036    
037    
038      /**
039       * Creates a new instance of this input stream that wraps the provided
040       * stream.
041       *
042       * @param  s  The input stream to be wrapped.
043       */
044      public BulkInputStreamWrapper(final InputStream s)
045      {
046        super(s);
047        bytesRead  = new AtomicLong(0L);
048      }
049    
050    
051    
052      /**
053       * Reads the next byte of data from the input stream. The value byte is
054       * returned as an <code>int</code> in the range <code>0</code> to
055       * <code>255</code>. If no byte is available because the end of the stream has
056       * been reached, the value <code>-1</code> is returned. This method blocks
057       * until input data is available, the end of the stream is detected, or an
058       * exception is thrown.
059       * <p/>
060       * <p> A subclass must provide an implementation of this method.
061       *
062       * @return the next byte of data, or <code>-1</code> if the end of the stream
063       *         is reached.
064       *
065       * @throws java.io.IOException if an I/O error occurs.
066       */
067      @Override
068      public int read() throws IOException
069      {
070        int c = in.read();
071        if (c != -1)
072        {
073          bytesRead.incrementAndGet();
074        }
075    
076        return c;
077      }
078    
079    
080    
081      /**
082       * Reads some number of bytes from the input stream and stores them into the
083       * buffer array <code>b</code>. The number of bytes actually read is returned
084       * as an integer.  This method blocks until input data is available, end of
085       * file is detected, or an exception is thrown.
086       * <p/>
087       * <p> If the length of <code>b</code> is zero, then no bytes are read and
088       * <code>0</code> is returned; otherwise, there is an attempt to read at least
089       * one byte. If no byte is available because the stream is at the end of the
090       * file, the value <code>-1</code> is returned; otherwise, at least one byte
091       * is read and stored into <code>b</code>.
092       * <p/>
093       * <p> The first byte read is stored into element <code>b[0]</code>, the next
094       * one into <code>b[1]</code>, and so on. The number of bytes read is, at
095       * most, equal to the length of <code>b</code>. Let <i>k</i> be the number of
096       * bytes actually read; these bytes will be stored in elements
097       * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>, leaving
098       * elements <code>b[</code><i>k</i><code>]</code> through
099       * <code>b[b.length-1]</code> unaffected.
100       * <p/>
101       * <p> The <code>read(b)</code> method for class <code>InputStream</code>
102       * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre>
103       *
104       * @param b the buffer into which the data is read.
105       *
106       * @return the total number of bytes read into the buffer, or <code>-1</code>
107       *         is there is no more data because the end of the stream has been
108       *         reached.
109       *
110       * @throws java.io.IOException  If the first byte cannot be read for any
111       *                              reason other than the end of the file, if the
112       *                              input stream has been closed, or if some other
113       *                              I/O error occurs.
114       * @see java.io.InputStream#read(byte[], int, int)
115       */
116      @Override
117      public int read(final byte[] b) throws IOException
118      {
119        int n = in.read(b);
120        if (n != -1)
121        {
122          bytesRead.addAndGet(n);
123        }
124    
125        return n;
126      }
127    
128    
129    
130      /**
131       * Reads up to <code>len</code> bytes of data from the input stream into an
132       * array of bytes.  An attempt is made to read as many as <code>len</code>
133       * bytes, but a smaller number may be read. The number of bytes actually read
134       * is returned as an integer.
135       * <p/>
136       * <p> This method blocks until input data is available, end of file is
137       * detected, or an exception is thrown.
138       * <p/>
139       * <p> If <code>len</code> is zero, then no bytes are read and <code>0</code>
140       * is returned; otherwise, there is an attempt to read at least one byte. If
141       * no byte is available because the stream is at end of file, the value
142       * <code>-1</code> is returned; otherwise, at least one byte is read and
143       * stored into <code>b</code>.
144       * <p/>
145       * <p> The first byte read is stored into element <code>b[off]</code>, the
146       * next one into <code>b[off+1]</code>, and so on. The number of bytes read
147       * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of bytes
148       * actually read; these bytes will be stored in elements <code>b[off]</code>
149       * through <code>b[off+</code><i>k</i><code>-1]</code>, leaving elements
150       * <code>b[off+</code><i>k</i><code>]</code> through <code>b[off+len-1]</code>
151       * unaffected.
152       * <p/>
153       * <p> In every case, elements <code>b[0]</code> through <code>b[off]</code>
154       * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code> are
155       * unaffected.
156       * <p/>
157       * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method for
158       * class <code>InputStream</code> simply calls the method <code>read()</code>
159       * repeatedly. If the first such call results in an <code>IOException</code>,
160       * that exception is returned from the call to the <code>read(b,</code>
161       * <code>off,</code> <code>len)</code> method.  If any subsequent call to
162       * <code>read()</code> results in a <code>IOException</code>, the exception is
163       * caught and treated as if it were end of file; the bytes read up to that
164       * point are stored into <code>b</code> and the number of bytes read before
165       * the exception occurred is returned. The default implementation of this
166       * method blocks until the requested amount of input data <code>len</code> has
167       * been read, end of file is detected, or an exception is thrown. Subclasses
168       * are encouraged to provide a more efficient implementation of this method.
169       *
170       * @param b   the buffer into which the data is read.
171       * @param off the start offset in array <code>b</code> at which the data is
172       *            written.
173       * @param len the maximum number of bytes to read.
174       *
175       * @return the total number of bytes read into the buffer, or <code>-1</code>
176       *         if there is no more data because the end of the stream has been
177       *         reached.
178       *
179       * @throws java.io.IOException       If the first byte cannot be read for any
180       *                                   reason other than end of file, or if the
181       *                                   input stream has been closed, or if some
182       *                                   other I/O error occurs.
183       * @see java.io.InputStream#read()
184       */
185      @Override
186      public int read(final byte[] b, final int off, final int len)
187          throws IOException
188      {
189        int n = in.read(b, off, len);
190        if (n != -1)
191        {
192          bytesRead.addAndGet(n);
193        }
194    
195        return n;
196      }
197    
198    
199    
200      /**
201       * Skips over and discards <code>n</code> bytes of data from this input
202       * stream.
203       * The <code>skip</code> method may, for a variety of reasons, end up skipping
204       * over some smaller number of bytes, possibly <code>0</code>. This may result
205       * from any of a number of conditions; reaching end of file before
206       * <code>n</code> bytes have been skipped is only one possibility. The actual
207       * number of bytes skipped is returned.  If <code>n</code> is negative, no
208       * bytes are skipped.
209       * <p/>
210       *
211       * @param n the number of bytes to be skipped.
212       *
213       * @return the actual number of bytes skipped.
214       *
215       * @throws java.io.IOException if the stream does not support seek, or if some
216       *                             other I/O error occurs.
217       */
218      @Override
219      public long skip(final long n) throws IOException
220      {
221        long skipped = in.skip(n);
222        bytesRead.addAndGet(skipped);
223    
224        return n;
225      }
226    
227    
228    
229      /**
230       * Retrieves the number of bytes read through this input stream.
231       *
232       * @return  The number of bytes read through this input stream.
233       */
234      public long getBytesRead()
235      {
236        return bytesRead.get();
237      }
238    }