All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.s3.internal.RepeatableInputStream Maven / Gradle / Ivy

Go to download

The Amazon Web Services SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).

The newest version!
/*
 * Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Portions copyright 2006-2009 James Murty. Please see LICENSE.txt
 * for applicable license terms and NOTICE.txt for applicable notices.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package com.amazonaws.services.s3.internal;

import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * A repeatable input stream wrapper for any input stream. This input stream
 * relies on buffered data to repeat, and can therefore only be repeated when
 * less data has been read than this buffer can hold.
 * 

* Note: Always use a {@link RepeatableFileInputStream} instead of this * class if you are sourcing data from a file, as the file-based repeatable * input stream can be repeated without any limitations. */ public class RepeatableInputStream extends InputStream { private static final Log log = LogFactory.getLog(RepeatableInputStream.class); private InputStream is = null; private int bufferSize = 0; private int bufferOffset = 0; private long bytesReadPastMark = 0; private byte[] buffer = null; private boolean hasWarnedBufferOverflow = false; /** * Creates a repeatable input stream based on another input stream. * * @param inputStream * The input stream to wrap. The data read from the wrapped input * stream is buffered as it is read, up to the buffer limit * specified. * @param bufferSize * The number of bytes buffered by this class. */ public RepeatableInputStream(InputStream inputStream, int bufferSize) { if (inputStream == null) { throw new IllegalArgumentException("InputStream cannot be null"); } this.is = inputStream; this.bufferSize = bufferSize; this.buffer = new byte[this.bufferSize]; if (log.isDebugEnabled()) { log.debug("Underlying input stream will be repeatable up to " + this.buffer.length + " bytes"); } } /** * Resets the input stream to the beginning by pointing the buffer offset to * the beginning of the available data buffer. * * @throws IOException * When the available buffer size has been exceeded, in which * case the input stream data cannot be repeated. */ public void reset() throws IOException { if (bytesReadPastMark <= bufferSize) { if (log.isDebugEnabled()) { log.debug("Reset after reading " + bytesReadPastMark + " bytes."); } bufferOffset = 0; } else { throw new IOException( "Input stream cannot be reset as " + this.bytesReadPastMark + " bytes have been written, exceeding the available buffer size of " + this.bufferSize); } } /** * @see java.io.InputStream#markSupported() */ public boolean markSupported() { return true; } /** * This method can only be used while less data has been read from the input * stream than fits into the buffer. The readLimit parameter is ignored * entirely. */ public synchronized void mark(int readlimit) { if (log.isDebugEnabled()) { log.debug("Input stream marked at " + bytesReadPastMark + " bytes"); } if (bytesReadPastMark <= bufferSize && buffer != null) { /* * Clear buffer of already-read data to make more space. It's safe * to cast bytesReadPastMark to an int because it is known to be * less than bufferSize, which is an int. */ byte[] newBuffer = new byte[this.bufferSize]; System.arraycopy(buffer, bufferOffset, newBuffer, 0, (int)(bytesReadPastMark - bufferOffset)); this.buffer = newBuffer; this.bytesReadPastMark -= bufferOffset; this.bufferOffset = 0; } else { // If mark is called after the buffer was already exceeded, create a new buffer. this.bufferOffset = 0; this.bytesReadPastMark = 0; this.buffer = new byte[this.bufferSize]; } } /** * @see java.io.InputStream#available() */ public int available() throws IOException { return is.available(); } /** * @see java.io.InputStream#close() */ public void close() throws IOException { is.close(); } /** * @see java.io.InputStream#read(byte[], int, int) */ public int read(byte[] out, int outOffset, int outLength) throws IOException { // Check whether we already have buffered data. if (bufferOffset < bytesReadPastMark && buffer != null) { // Data is being repeated, so read from buffer instead of wrapped input stream. int bytesFromBuffer = outLength; if (bufferOffset + bytesFromBuffer > bytesReadPastMark) { bytesFromBuffer = (int) bytesReadPastMark - bufferOffset; } // Write to output. System.arraycopy(buffer, bufferOffset, out, outOffset, bytesFromBuffer); bufferOffset += bytesFromBuffer; return bytesFromBuffer; } // Read data from input stream. int count = is.read(out, outOffset, outLength); if (count <= 0) { return count; } // Fill the buffer with data, as long as we won't exceed its capacity. if (bytesReadPastMark + count <= bufferSize) { System.arraycopy(out, outOffset, buffer, (int) bytesReadPastMark, count); bufferOffset += count; } else { // We have exceeded the buffer capacity, after which point it is of no use. Free the memory. if (! hasWarnedBufferOverflow) { if (log.isDebugEnabled()) { log.debug("Buffer size " + bufferSize + " has been exceeded and the input stream " + "will not be repeatable until the next mark. Freeing buffer memory"); } hasWarnedBufferOverflow = true; } buffer = null; } bytesReadPastMark += count; return count; } /** * @see java.io.InputStream#read() */ public int read() throws IOException { byte[] tmp = new byte[1]; int count = read(tmp); if (count != -1) { int unsignedByte = (int) tmp[0] & 0xFF; return unsignedByte; } else { return count; } } public InputStream getWrappedInputStream() { return is; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy