com.bertramlabs.plugins.karman.nfs.NfsFileInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of karman-nfs Show documentation
Show all versions of karman-nfs Show documentation
Karman Storage Provider interface for NFS Shares
/**
* Copyright 2016-2017 EMC Corporation. All Rights Reserved.
*
* 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://www.apache.org/licenses/LICENSE-2.0.txt
*
* 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.bertramlabs.plugins.karman.nfs;
import com.emc.ecs.nfsclient.nfs.NfsReadResponse;
import com.emc.ecs.nfsclient.nfs.io.*;
import java.io.IOException;
import java.io.InputStream;
/**
* The NFS equivalent of java.io.FileInputStream
.
*
* @author seibed
*/
public class NfsFileInputStream extends InputStream {
/**
* Constant for output.
*/
public static final int EOF = -1;
/**
* The underlying file.
*/
private NfsFile, ?> _file;
/**
* Current read position in the file, in bytes.
*/
private long _offset;
/**
* The byte buffer, used to hold data from the file during reading.
*/
private final byte[] _bytes;
/**
* The total number of bytes in the buffer.
*/
private int _bytesInBuffer = 0;
/**
* Current reading position in the buffer.
*/
private int _currentBufferPosition = 0;
/**
*
* true
if all data in the file has been returned and read,
*
* false
otherwise.
*
*/
private boolean _isEof = false;
/**
* Flag to prevent operations after closing.
*/
private boolean _closed = false;
/**
* Creates a NfsFileInputStream
by opening a connection to an
* actual NFS file, using the specified offset
and
* maximumBufferSize
.
*
* If the named file does not exist, is a directory rather than a regular
* file, or for some other reason cannot be opened for reading then a
* FileNotFoundException
is thrown.
*
*
* @param nfsFile
* The NFS file instance to be read.
* @param offset
* The offset at which reading should start, in bytes.
* @param maximumBufferSize
* The maximum buffer size to use in bytes.
* @throws IOException
* If the file does not exist, is a directory rather than a
* regular file, or for some other reason cannot be opened for
* reading.
*/
public NfsFileInputStream(NfsFile, ?> nfsFile, long offset, int maximumBufferSize) throws IOException {
// Validate the offset.
if (offset < 0) {
throw new IllegalArgumentException("Cannot start reading before offset 0: " + offset);
}
// Validate the maximum buffer size.
if (maximumBufferSize <= 0) {
throw new IllegalArgumentException("Cannot have a maximum buffer size <= 0: " + maximumBufferSize);
}
// Validate the file.
if (!nfsFile.canRead()) {
throw new IllegalArgumentException("The file must be readable by the client: " + nfsFile.getAbsolutePath());
}
_file = nfsFile;
_offset = offset;
maximumBufferSize = Math.min(maximumBufferSize,
(int) Math.min(_file.fsinfo().getFsInfo().rtmax, Integer.MAX_VALUE));
_bytes = makeBytes(maximumBufferSize);
}
/**
* Creates a NfsFileInputStream
by opening a connection to an
* actual NFS file, starting to read at offset 0 and using the specified
* maximum buffer size.
*
* If the named file does not exist, is a directory rather than a regular
* file, or for some other reason cannot be opened for reading then a
* FileNotFoundException
is thrown.
*
*
* @param nfsFile
* The NFS file instance to be read.
* @param maximumBufferSize
* The maximum buffer size to use in bytes.
* @throws IOException
* If the file does not exist, is a directory rather than a
* regular file, or for some other reason cannot be opened for
* reading.
*/
public NfsFileInputStream(NfsFile, ?> nfsFile, int maximumBufferSize) throws IOException {
this(nfsFile, 0, maximumBufferSize);
}
/**
* Creates a NfsFileInputStream
by opening a connection to an
* actual NFS file, starting to read at offset 0 and using the preferred
* buffer size as the maximums. This constructor will generally give you the
* best performance.
*
* If the named file does not exist, is a directory rather than a regular
* file, or for some other reason cannot be opened for reading then a
* FileNotFoundException
is thrown.
*
*
* @param nfsFile
* The NFS file instance to be read.
* @throws IOException
* If the file does not exist, is a directory rather than a
* regular file, or for some other reason cannot be opened for
* reading.
*/
public NfsFileInputStream(NfsFile, ?> nfsFile) throws IOException {
this(nfsFile, (int) Math.min(nfsFile.fsinfo().getFsInfo().rtpref, Integer.MAX_VALUE));
}
/**
* @param maximumBufferSize
* @return the byte array
* @throws IOException
*/
private byte[] makeBytes(int maximumBufferSize) throws IOException {
int bufferSize = Math.min((int) Math.min(_file.length() - _offset, Integer.MAX_VALUE), maximumBufferSize);
if (bufferSize == 0) {
_isEof = true;
}
return new byte[bufferSize];
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#available()
*/
public int available() throws IOException {
checkForClosed();
return (int) Math.min(_file.length() - _offset + bytesLeftInBuffer(), Integer.MAX_VALUE);
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#close()
*/
public void close() throws IOException {
_closed = true;
super.close();
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#mark(int)
*/
public synchronized void mark(int readlimit) {
super.mark(readlimit);
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#markSupported()
*/
public boolean markSupported() {
return false;
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read()
*/
public int read() throws IOException {
byte[] b = new byte[1];
int bytesRead = read(b, 0, 1);
if (bytesRead == EOF) {
return EOF;
} else {
//byte type in Java is from -128 to +127 and we are supposed to return 0-255
return b[0] & 0xFF;
}
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read(byte[])
*/
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read(byte[], int, int)
*/
public int read(byte[] b, int off, int len) throws IOException {
checkForClosed();
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (len < 0) || ((off + len) > b.length)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
loadBytesAsNeeded();
int bytesImmediatelyAvailable = bytesLeftInBuffer();
if (len <= bytesImmediatelyAvailable) {
System.arraycopy(_bytes, _currentBufferPosition, b, off, len);
_currentBufferPosition += len;
return len;
}
int bytesRead = EOF;
if (bytesImmediatelyAvailable > 0) {
bytesRead = read(b, off, bytesImmediatelyAvailable);
if (bytesRead != EOF) {
int furtherBytesRead = read(b, off + bytesRead, len - bytesRead);
if (furtherBytesRead != EOF) {
bytesRead += furtherBytesRead;
}
}
}
return bytesRead;
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#reset()
*/
public synchronized void reset() throws IOException {
checkForClosed();
super.reset();
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#skip(long)
*/
public long skip(long bytesToSkip) throws IOException {
checkForClosed();
long bytesSkipped = 0;
while (bytesToSkip > bytesLeftInBuffer()) {
bytesSkipped += bytesLeftInBuffer();
bytesToSkip -= bytesLeftInBuffer();
_currentBufferPosition = _bytesInBuffer;
if (_isEof) {
break;
}
loadBytesAsNeeded();
}
if ((bytesToSkip > 0) && (bytesToSkip <= bytesLeftInBuffer())) {
_currentBufferPosition += (int) bytesToSkip;
bytesSkipped += (int) bytesToSkip;
}
return bytesSkipped;
}
/**
* @return The number of unread bytes in the buffer.
*/
private int bytesLeftInBuffer() {
return _bytesInBuffer - _currentBufferPosition;
}
/**
* Convenience function.
*
* @throws IOException
* If the stream has been closed.
*/
private void checkForClosed() throws IOException {
if (_closed) {
throw new IOException("This stream has been closed.");
}
}
/**
* If the buffer has no more bytes to be read, and there are bytes available in the file, load more bytes.
*
* @throws IOException
*/
private void loadBytesAsNeeded() throws IOException {
if (available() <= 0) {
_isEof = true;
}
while ((!_isEof) && (bytesLeftInBuffer() <= 0)) {
_currentBufferPosition = 0;
NfsReadResponse response = _file.read(_offset, _bytes.length, _bytes, _currentBufferPosition);
_bytesInBuffer = response.getBytesRead();
_offset += _bytesInBuffer;
_isEof = response.isEof();
}
}
}