001/* 002 * Copyright 2012-2016 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 018package com.unboundid.scim.marshal; 019 020import java.io.FilterInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import 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 */ 031public 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 * 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 * 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 * 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 * 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 * 136 * <p> This method blocks until input data is available, end of file is 137 * detected, or an exception is thrown. 138 *= 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 * 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 * 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 * 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 * 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}