FileDocCategorySizeDatePackage
FileChannelImpl.javaAPI DocAndroid 1.5 API22611Wed May 06 22:41:04 BST 2009org.apache.harmony.nio.internal

FileChannelImpl

public abstract class FileChannelImpl extends FileChannel

Fields Summary
private static final org.apache.harmony.luni.platform.IFileSystem
fileSystem
private static final int
ALLOC_GRANULARITY
private final int
handle
private final LockManager
lockManager
private final Object
repositioningLock
private final Object
stream
Constructors Summary
public FileChannelImpl(Object stream, int handle)


    /*
     * Create a new file channel implementation class that wraps the given file
     * handle and operates in the specified mode.
     * 
     */
         
        super();
        this.handle = handle;
        this.stream = stream;
    
Methods Summary
protected java.nio.channels.FileLockbasicLock(long position, long size, boolean shared, boolean wait)

        if ((position < 0) || (size < 0)) {
            // nio.0A=Lock position and size must be non-negative.
            throw new IllegalArgumentException(
                    Messages.getString("nio.0A"));  //$NON-NLS-1$
        }
        int lockType = shared ? IFileSystem.SHARED_LOCK_TYPE
                : IFileSystem.EXCLUSIVE_LOCK_TYPE;
        FileLock pendingLock = new FileLockImpl(this, position, size, shared);
        lockManager.addLock(pendingLock);

        if (fileSystem.lock(handle, position, size, lockType, wait)) {
            return pendingLock;
        }

        // Lock acquisition failed
        lockManager.removeLock(pendingLock);
        return null;
    
public voidforce(boolean metadata)

        openCheck();
        // Forcing data-only on a read-only file is a no-op.
        if (metadata) {
            fileSystem.fflush(handle, metadata);
        }
    
public intgetHandle()

        return handle;
    
protected voidimplCloseChannel()

        if (stream instanceof Closeable) {
            ((Closeable) stream).close();
        }
    
private longkernelTransfer(int l, java.io.FileDescriptor fd, long position, long count)

        boolean completed = false;
        try {
            begin();
            long ret = fileSystem.transfer(l, fd, position, count);
            completed = true;
            return ret;
        } finally {
            end(completed);
        }
    
public final java.nio.channels.FileLocklock(long position, long size, boolean shared)

        openCheck();
        FileLock resultLock = null;
        {
            boolean completed = false;
            try {
                begin();
                resultLock = basicLock(position, size, shared, true);
                completed = true;
            } finally {
                end(completed);
            }
        }
        return resultLock;
    
public abstract java.nio.MappedByteBuffermap(MapMode mode, long position, long size)

protected final java.nio.MappedByteBuffermapImpl(int mapMode, long position, long size)

        if (position + size > size()) {
            fileSystem.truncate(handle, position + size);
        }
        long alignment = position - position % ALLOC_GRANULARITY;
        int offset = (int) (position - alignment);
        PlatformAddress address = PlatformAddressFactory.allocMap(handle, alignment, size
                + offset, mapMode);
        MappedByteBuffer buffer = null;
        try {
            buffer = MappedByteBufferFactory.getBuffer(address, mapMode, size,
                    offset);
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
        return buffer;
    
protected final voidopenCheck()

        if (!isOpen()) {
            throw new ClosedChannelException();
        }
    
public longposition()

        openCheck();
        return fileSystem.seek(handle, 0L, IFileSystem.SEEK_CUR);
    
public java.nio.channels.FileChannelposition(long newPosition)

        openCheck();
        if (newPosition < 0) {
            // nio.0B=New position must be non-negative.
            throw new IllegalArgumentException(
                    Messages.getString("nio.0B"));  //$NON-NLS-1$
        }        

        synchronized (repositioningLock) {
            fileSystem.seek(handle, newPosition, IFileSystem.SEEK_SET);
        }
        return this;
    
public intread(java.nio.ByteBuffer buffer, long position)

        if (null == buffer){
            throw new NullPointerException();
        }
        if (position < 0){
            throw new IllegalArgumentException();
        }
        openCheck();
        if (!buffer.hasRemaining()){
            return 0;
        }
        synchronized (repositioningLock) {
            int bytesRead = 0;
            long preReadPosition = position();
            position(position);
            try {
                bytesRead = read(buffer);
            } finally {
                position(preReadPosition);
            }
            return bytesRead;
        }
    
public intread(java.nio.ByteBuffer buffer)

        openCheck();
        if (!buffer.hasRemaining()){
            return 0;
        }
        boolean completed = false;
        int bytesRead = 0;
        synchronized (repositioningLock) {
            if (buffer.isDirect()) {
                DirectBuffer directBuffer = (DirectBuffer) buffer;
                int address = directBuffer.getEffectiveAddress().toInt();
                try {
                    begin();
                    /*
                     * if (bytesRead <= EOF) delt by read completed = false;
                     */
                    bytesRead = (int) fileSystem.readDirect(handle, address,
                            buffer.position(), buffer.remaining());
                    completed = true;
                } finally {
                    end(completed && bytesRead >= 0);
                }
            } else {
                try {
                    begin();
                    /*
                     * if (bytesRead <= EOF) delt by read completed = false;
                     */
                    bytesRead = (int) fileSystem.read(handle, buffer.array(),
                            buffer.arrayOffset() + buffer.position(), buffer
                                    .remaining());
                    completed = true;
                } finally {
                    end(completed && bytesRead >= 0);
                }
            }
            if (bytesRead > 0) {
                buffer.position(buffer.position() + bytesRead);
            }
        }
        return bytesRead;
    
public longread(java.nio.ByteBuffer[] buffers, int offset, int length)

        int count = 0;
        if (offset < 0 || length < 0 || offset + length > buffers.length) {
            throw new IndexOutOfBoundsException();
        }
        openCheck();
        for (int i = offset; i < offset + length; i++) {
            count += buffers[i].remaining();
        }
        if (0 == count) {
            return 0;
        }
        if (size() == 0) {
            return -1;
        }
        ByteBuffer[] directBuffers = new ByteBuffer[length];
        int[] handles = new int[length];
        int[] offsets = new int[length];
        int[] lengths = new int[length];
        for (int i = 0; i < length; i++) {
            ByteBuffer buffer = buffers[i + offset];
            if (!buffer.isDirect()) {
                buffer = ByteBuffer.allocateDirect(buffer.remaining());
                directBuffers[i] = buffer;
                offsets[i] = 0;
            } else {
                offsets[i] = buffer.position();
            }
            handles[i] = ((DirectBuffer) buffer).getEffectiveAddress().toInt();
            lengths[i] = buffer.remaining();
        }
        long bytesRead = 0;
        {
            boolean completed = false;
            try {
                begin();
                synchronized (repositioningLock) {
                    bytesRead = fileSystem.readv(handle, handles, offsets,
                            lengths, length);

                }
                completed = true;
                /*
                 * if (bytesRead < EOF) //delt by readv? completed = false;
                 */
            } finally {
                end(completed);
            }
        }
        int end = offset + length;
        long bytesRemaining = bytesRead;
        for (int i = offset; i < end && bytesRemaining > 0; i++) {
            if (buffers[i].isDirect()) {
                if (lengths[i] < bytesRemaining) {
                    int pos = buffers[i].limit();
                    buffers[i].position(pos);
                    bytesRemaining -= lengths[i];
                } else {
                    int pos = (int) bytesRemaining;
                    buffers[i].position(pos);
                    break;
                }
            } else {
                ByteBuffer buf = directBuffers[i - offset];
                if (bytesRemaining < buf.remaining()){
                    // this is the last step.                  
                    int pos = buf.position();
                    buffers[i].put(buf);
                    buffers[i].position(pos + (int)bytesRemaining);
                    bytesRemaining = 0;
                } else {
                    bytesRemaining -= buf.remaining();
                    buffers[i].put(buf);
                }                
            }
        }
        return bytesRead;
    
voidrelease(java.nio.channels.FileLock lock)

        openCheck();
        fileSystem.unlock(handle, lock.position(), lock.size());
        lockManager.removeLock(lock);
    
public longsize()

        openCheck();
        synchronized (repositioningLock) {
            long currentPosition = fileSystem.seek(handle, 0L,
                    IFileSystem.SEEK_CUR);
            long endOfFilePosition = fileSystem.seek(handle, 0L,
                    IFileSystem.SEEK_END);
            fileSystem.seek(handle, currentPosition, IFileSystem.SEEK_SET);
            return endOfFilePosition;
        }
    
public longtransferFrom(java.nio.channels.ReadableByteChannel src, long position, long count)

        openCheck();
        if (!src.isOpen()) {
            throw new ClosedChannelException();
        }
        if (position < 0 || count < 0 || position > Integer.MAX_VALUE
                || count > Integer.MAX_VALUE) {
            throw new IllegalArgumentException();
        }
        if(position > size()) {
            return 0;
        }
        
        ByteBuffer buffer = null;
        // BEGIN android-changed
        try {
            if (src instanceof FileChannel) {
                FileChannel fileSrc = (FileChannel) src;
                long size = fileSrc.size();
                long filePosition = fileSrc.position();
                count = Math.min(count, size - filePosition);
                buffer = fileSrc.map(MapMode.READ_ONLY, filePosition, count);
                fileSrc.position(filePosition + count);
            } else {
                buffer = ByteBuffer.allocateDirect((int) count);
                src.read(buffer);
                buffer.flip();
            }
            return write(buffer, position);
        } finally {
            // unmap the buffer
            if (buffer != null) {
                // all children of FileChannelImpl currently returns
                // an instance of DirectBuffer from map() method
               ((DirectBuffer) buffer).free();
            }
        }
        // END android-changed
    
public longtransferTo(long position, long count, java.nio.channels.WritableByteChannel target)

        openCheck();
        if (!target.isOpen()) {
            throw new ClosedChannelException();
        }
        if (target instanceof ReadOnlyFileChannel) {
            throw new NonWritableChannelException();
        }
        if (position < 0 || count < 0 || position > Integer.MAX_VALUE
                || count > Integer.MAX_VALUE) {
            throw new IllegalArgumentException();
        }
        
        if (count == 0 || position >= size()) {
            return 0;
        }
        ByteBuffer buffer = null;
        count = Math.min(count, size() - position);
        if (target instanceof SocketChannelImpl) {
            // only socket can be transfered by system call
            return kernelTransfer(handle, ((SocketChannelImpl) target).getFD(),
                    position, count);
        }
        // BEGIN android-changed
        try {
            buffer = map(MapMode.READ_ONLY, position, count);
            return target.write(buffer);
        } finally {
            // unmap the buffer
            if (buffer != null) {
                // all children of FileChannelImpl currently returns
                // an instance of DirectBuffer from map() method
                ((DirectBuffer) buffer).free();
            }
        }
        // END android-changed
    
public java.nio.channels.FileChanneltruncate(long size)

        openCheck();
        if (size < 0) {
            throw new IllegalArgumentException();
        }
        if (size < size()) {
            synchronized (repositioningLock) {
                long position = position();
                fileSystem.truncate(handle, size);
                /*
                 * FIXME: currently the port library always modifies the
                 * position to given size. not sure it is a bug or intended
                 * behaviour, so I always reset the position to proper value as
                 * Java Spec.
                 */
                position(position > size ? size : position);
            }
        }
        return this;
    
public final java.nio.channels.FileLocktryLock(long position, long size, boolean shared)

        openCheck();
        return basicLock(position, size, shared, false);
    
public intwrite(java.nio.ByteBuffer buffer, long position)

        if (null == buffer){
            throw new NullPointerException();
        }
        if (position < 0){
            throw new IllegalArgumentException();
        }
        openCheck();
        if (!buffer.hasRemaining()){
            return 0;
        }
        int bytesWritten = 0;
        synchronized (repositioningLock) {
            long preWritePosition = position();
            position(position);
            try {
                bytesWritten = writeImpl(buffer);
            } finally {
                position(preWritePosition);
            }
        }
        return bytesWritten;
    
public intwrite(java.nio.ByteBuffer buffer)

        openCheck();
        return writeImpl(buffer);
    
public longwrite(java.nio.ByteBuffer[] buffers, int offset, int length)

        if (offset < 0 || length < 0 || (offset + length) > buffers.length) {
            throw new IndexOutOfBoundsException();
        }
        openCheck();
        int count = 0;
        for (int i = offset; i < offset + length; i++) {
            count += buffers[i].remaining();
        }
        if (0 == count) {
            return 0;
        }
        int[] handles = new int[length];
        int[] offsets = new int[length];
        int[] lengths = new int[length];
        // BEGIN android-changed
        // list of allocated direct ByteBuffers to prevent them from being GC-ed
        DirectBuffer[] allocatedBufs = new DirectBuffer[length];

        for (int i = 0; i < length; i++) {
            ByteBuffer buffer = buffers[i + offset];
            if (!buffer.isDirect()) {
                ByteBuffer directBuffer = ByteBuffer.allocateDirect(buffer
                        .remaining());
                directBuffer.put(buffer);
                directBuffer.flip();
                buffer = directBuffer;
                allocatedBufs[i] = (DirectBuffer) directBuffer;
                offsets[i] = 0;
            } else {
                offsets[i] = buffer.position();
                allocatedBufs[i] = null;
            }
            handles[i] = ((DirectBuffer) buffer).getEffectiveAddress().toInt();
            lengths[i] = buffer.remaining();
        }
        // END android-changed

        long bytesWritten = 0;
        boolean completed = false;
        synchronized (repositioningLock) {
            try {
                begin();
                bytesWritten = fileSystem.writev(handle, handles, offsets,
                        lengths, length);
                completed = true;
            } finally {
                end(completed);
                // BEGIN android-added
                // free temporary direct buffers
                for (int i = 0; i < length; ++i) {
                    if (allocatedBufs[i] != null) {
                        allocatedBufs[i].free();
                    }
                }
                // END android-added
            }
        }

        long bytesRemaining = bytesWritten;
        for (int i = offset; i < length + offset; i++) {
            if (bytesRemaining > buffers[i].remaining()) {
                int pos = buffers[i].limit();
                buffers[i].position(pos);
                bytesRemaining -= buffers[i].remaining();
            } else {
                int pos = buffers[i].position() + (int) bytesRemaining;
                buffers[i].position(pos);
                break;
            }
        }
        return bytesWritten;
    
private intwriteImpl(java.nio.ByteBuffer buffer)

        int bytesWritten;
        boolean completed = false;
        synchronized (repositioningLock) {
            if (buffer.isDirect()) {
                DirectBuffer directBuffer = (DirectBuffer) buffer;
                int address = directBuffer.getEffectiveAddress().toInt();
                try {
                    begin();
                    bytesWritten = (int) fileSystem.writeDirect(handle,
                            address, buffer.position(), buffer.remaining());
                    completed = true;
                } finally {
                    end(completed);
                }
            } else {
                try {
                    begin();
                    bytesWritten = (int) fileSystem.write(handle, buffer
                            .array(), buffer.arrayOffset() + buffer.position(),
                            buffer.remaining());
                    completed = true;
                } finally {
                    end(completed);
                }
            }
            if (bytesWritten > 0) {
                buffer.position(buffer.position() + bytesWritten);
            }
        }
        return bytesWritten;