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 }