com.frand.easyandroid.http.FFFileRespHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.frand.easyandroid.http.FFFileRespHandler.java

Source

/*
 * Copyright (C) 2013 frandfeng
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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.frand.easyandroid.http;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectTimeoutException;

import com.frand.easyandroid.exception.FFFileExistException;
import com.frand.easyandroid.log.FFLogger;

public class FFFileRespHandler extends FFHttpRespHandler {

    public final static int TIME_OUT = 30000;
    private final static int BUFFER_SIZE = 1024 * 8;

    private static final String TEMP_SUFFIX = ".download";
    /*??*/
    private File file;
    /*?*/
    private File tempFile;
    /*fileName??*/
    private File baseDirFile;
    /*??*/
    private RandomAccessFile outputStream;
    /*??*/
    private long downloadSize;
    /*??downloadSize=previousFileSize+??*/
    private long previousFileSize;
    /*?*/
    private long totalSize;
    private long networkSpeed;
    private long previousTime;
    private long totalTime;
    private boolean interrupt = false;
    private boolean timerInterrupt = false;
    private Timer timer = new Timer();
    private static final int TIMERSLEEPTIME = 100;

    public FFFileRespHandler(String rootFile, String fileName) {
        super();
        this.baseDirFile = new File(rootFile);
        this.file = new File(rootFile, fileName);
        this.tempFile = new File(rootFile, fileName + TEMP_SUFFIX);
        init();
    }

    public FFFileRespHandler(String filePath) {
        super();
        this.file = new File(filePath);
        this.baseDirFile = new File(this.file.getParent());
        this.tempFile = new File(filePath + TEMP_SUFFIX);
        init();
    }

    private void init() {
        if (!this.baseDirFile.exists()) {
            this.baseDirFile.mkdirs();
        }
        FFLogger.i(this, "init completely baseDirFile=" + baseDirFile.getAbsolutePath() + ", file="
                + file.getAbsolutePath() + ", tempFile=" + tempFile.getAbsolutePath());
    }

    @Override
    protected void onStart(int reqTag, String reqUrl) {
    }

    @Override
    protected void onFailure(Throwable error, int reqTag, String reqUrl) {
    }

    @Override
    protected void onSuccess(String resp, int reqTag, String reqUrl) {
    }

    @Override
    protected void onFinish(int reqTag, String reqUrl) {
    }

    public boolean isInterrupt() {
        return interrupt;
    }

    public void setInterrupt(boolean interrupt) {
        this.interrupt = interrupt;
    }

    public long getDownloadSize() {
        return downloadSize;
    }

    public long getTotalSize() {
        return totalSize;
    }

    public double getDownloadSpeed() {
        return this.networkSpeed;
    }

    public void setPreviousFileSize(long previousFileSize) {
        this.previousFileSize = previousFileSize;
    }

    public File getFile() {
        return file;
    }

    public long getTotalTime() {
        return this.totalTime;
    }

    public File getTempFile() {
        return tempFile;
    }

    private void stopTimer() {
        timerInterrupt = true;
        timer.cancel();
    }

    private void stopCopy() {
        interrupt = true;
    }

    @Override
    protected void sendRespMsg(HttpResponse response, int reqTag, String reqUrl) {
        FFLogger.i(this, "start to send response message");
        Throwable error = null;
        long result = -1;
        try {
            // ??
            long contentLength = response.getEntity().getContentLength();
            // -1?ContentLength -1
            if (contentLength == -1) {
                contentLength = response.getEntity().getContent().available();
            }
            // ??
            previousFileSize = 0;
            File tempFile = this.getTempFile();
            if (tempFile.exists()) {
                previousFileSize = this.getTempFile().length();
            }
            totalSize = contentLength + previousFileSize;
            FFLogger.i(this, "totalSize: " + totalSize + ",contentLength: " + contentLength + ",previousFileSize: "
                    + previousFileSize);
            if (file.exists() && totalSize == file.length()) {
                FFLogger.i(this, "Output file already exists. Skipping download.");
                throw new FFFileExistException("Output file already exists. Skipping download.");
            } else if (tempFile.exists()) {
                previousFileSize = tempFile.length();
            }
            outputStream = new ProgressReportingRandomAccessFile(tempFile, "rw");
            InputStream input = response.getEntity().getContent();
            startTimer(reqTag, reqUrl);
            int bytesCopied = copy(input, outputStream);
            if ((previousFileSize + bytesCopied) != totalSize && totalSize != -1 && !interrupt) {
                throw new IOException("Download incomplete: " + bytesCopied + " != " + totalSize);
            } else if (interrupt) {
                throw new Exception("download has been paused");
            }
            result = bytesCopied;
        } catch (FileNotFoundException e) {
            error = e;
        } catch (FFFileExistException e) {
            error = e;
        } catch (IllegalStateException e) {
            error = e;
        } catch (IOException e) {
            error = e;
        } catch (Exception e) {
            error = e;
        }
        // ??
        stopTimer();
        // ??timer
        try {
            Thread.sleep(TIMERSLEEPTIME);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (result == -1 || interrupt || error != null) {
            if (error != null) {
                if (error instanceof FFFileExistException) {
                    sendSuccMsg("??", reqTag, reqUrl);
                } else {
                    sendFailureMsg(error, reqTag, reqUrl);
                }
            }
            return;
        }
        tempFile.renameTo(file);
        sendSuccMsg("??", reqTag, reqUrl);
    }

    private void startTimer(final int reqTag, final String reqUrl) {
        timerInterrupt = false;
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                while (!timerInterrupt) {
                    sendProgressMsg(totalSize, getDownloadSize(), networkSpeed, reqTag, reqUrl);
                    try {
                        Thread.sleep(TIMERSLEEPTIME);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, 0, 1000);
        new Thread(new Runnable() {

            @Override
            public void run() {

            }
        }).start();
    }

    public void PauseDownload() {
        stopCopy();
        stopTimer();
    }

    public int copy(InputStream input, RandomAccessFile out) throws IOException {
        interrupt = false;
        if (input == null || out == null) {
            return -1;
        }
        byte[] buffer = new byte[BUFFER_SIZE];
        BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
        int count = 0, n = 0;
        long errorBlockTimePreviousTime = -1, expireTime = 0;
        try {
            out.seek(out.length());
            previousTime = System.currentTimeMillis();
            while (!interrupt) {
                n = in.read(buffer, 0, BUFFER_SIZE);
                if (n == -1) {
                    break;
                }
                out.write(buffer, 0, n);
                count += n;
                if (networkSpeed == 0) {
                    if (errorBlockTimePreviousTime > 0) {
                        expireTime = System.currentTimeMillis() - errorBlockTimePreviousTime;
                        if (expireTime > TIME_OUT) {
                            throw new ConnectTimeoutException("connection time out.");
                        }
                    } else {
                        errorBlockTimePreviousTime = System.currentTimeMillis();
                    }
                } else {
                    expireTime = 0;
                    errorBlockTimePreviousTime = -1;
                }
            }
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return count;
    }

    private class ProgressReportingRandomAccessFile extends RandomAccessFile {
        private int progress = 0;

        public ProgressReportingRandomAccessFile(File file, String mode) throws FileNotFoundException {
            super(file, mode);
        }

        @Override
        public void write(byte[] buffer, int offset, int count) throws IOException {
            super.write(buffer, offset, count);
            progress += count;
            totalTime = System.currentTimeMillis() - previousTime;
            downloadSize = progress + previousFileSize;
            if (totalTime > 0) {
                networkSpeed = (long) ((progress / totalTime) / 1.024);
            }
        }
    }
}