com.liferay.sync.engine.lan.server.file.SyncChunkedFile.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.sync.engine.lan.server.file.SyncChunkedFile.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.sync.engine.lan.server.file;

import com.liferay.sync.engine.util.OSDetector;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.stream.ChunkedInput;

import java.io.IOException;

import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;

/**
 * @author Dennis Ju
 */
public class SyncChunkedFile implements ChunkedInput<ByteBuf> {

    public SyncChunkedFile(Path path, long length, int chunkSize, long modifiedTime) throws IOException {

        this(path, 0L, length, chunkSize, modifiedTime);
    }

    public SyncChunkedFile(Path path, long offset, long length, int chunkSize, long modifiedTime)
            throws IOException {

        if (offset != 0L) {
            _fileChannel.position(offset);
        }

        _path = path;
        _offset = offset;
        _chunkSize = chunkSize;
        _modifiedTime = modifiedTime;

        _startOffset = offset;
        _endOffset = offset + length;

        if (OSDetector.isWindows()) {
            _closeAggressively = true;
        } else {
            _closeAggressively = false;
        }
    }

    @Override
    public void close() throws Exception {
        if (_fileChannel != null) {
            _fileChannel.close();
        }

        _closed = true;
    }

    @Override
    public boolean isEndOfInput() throws Exception {
        if ((_offset >= _endOffset) || _closed) {
            return true;
        }

        return false;
    }

    @Override
    public long length() {
        return _endOffset - _startOffset;
    }

    @Override
    public long progress() {
        return _offset - _startOffset;
    }

    @Override
    public ByteBuf readChunk(ByteBufAllocator byteBufAllocator) throws Exception {

        long offset = _offset;

        if (offset >= _endOffset) {
            return null;
        }

        int chunkSize = (int) Math.min((long) _chunkSize, _endOffset - offset);

        ByteBuf byteBuf = byteBufAllocator.buffer(chunkSize);

        boolean release = true;

        try {
            FileTime currentFileTime = Files.getLastModifiedTime(_path, LinkOption.NOFOLLOW_LINKS);

            long currentTime = currentFileTime.toMillis();

            if (currentTime != _modifiedTime) {
                throw new Exception("File modified during transfer: " + _path);
            }

            int bytesRead = 0;

            if (_closeAggressively || (_fileChannel == null)) {
                _fileChannel = FileChannel.open(_path);

                _fileChannel.position(_offset);
            }

            while (true) {
                int localBytesRead = byteBuf.writeBytes(_fileChannel, chunkSize - bytesRead);

                if (localBytesRead >= 0) {
                    bytesRead += localBytesRead;

                    if (bytesRead != chunkSize) {
                        continue;
                    }
                }

                _offset += bytesRead;

                release = false;

                return byteBuf;
            }
        } finally {
            if (_closeAggressively && (_fileChannel != null)) {
                _fileChannel.close();
            }

            if (release) {
                byteBuf.release();
            }
        }
    }

    /**
     * @deprecated As of 3.3.0, As of Netty 4.1.0, replaced by {@link
     *             #readChunk(ByteBufAllocator)}
     */
    @Deprecated
    @Override
    public ByteBuf readChunk(ChannelHandlerContext channelHandlerContext) throws Exception {

        return readChunk(channelHandlerContext.alloc());
    }

    private final int _chunkSize;
    private final boolean _closeAggressively;
    private boolean _closed;
    private final long _endOffset;
    private FileChannel _fileChannel;
    private final long _modifiedTime;
    private long _offset;
    private final Path _path;
    private final long _startOffset;

}