com.polyvi.xface.extension.advancedfiletransfer.XFileDownloader.java Source code

Java tutorial

Introduction

Here is the source code for com.polyvi.xface.extension.advancedfiletransfer.XFileDownloader.java

Source

/*
 Copyright 2012-2013, Polyvi Inc. (http://polyvi.github.io/openxface)
 This program is distributed under the terms of the GNU General Public License.
    
 This file is part of xFace.
    
 xFace is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
 xFace 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 General Public License for more details.
    
 You should have received a copy of the GNU General Public License
 along with xFace.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.polyvi.xface.extension.advancedfiletransfer;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;

import com.polyvi.xface.app.XApplication;
import com.polyvi.xface.extension.XCallbackContext;
import com.polyvi.xface.extension.XExtensionContext;
import com.polyvi.xface.extension.XExtensionResult;
import com.polyvi.xface.util.XFileUtils;
import com.polyvi.xface.util.XLog;

public class XFileDownloader implements XIFileTransferListener, XIFileTransfer {

    private static final String CLASS_NAME = XFileDownloader.class.getSimpleName();
    private static final int TIME_OUT_MILLISECOND = 5000;

    /** ??????? */
    private static final int INIT = 1;
    private static final int DOWNLOADING = 2;
    private static final int PAUSE = 3;
    private int mState = INIT;

    private static final int CONNECTION_ERR = 3;

    /**????*/
    private static final int DIVIDE_SIZE_TWO = 2;
    private static final int DIVIDE_SIZE_TEN = 10;
    private static final int DIVIDE_SIZE_TWENTY = 20;
    private static final int SIZE_KB = 1024;

    /**?*/
    private static final int FILE_NOT_EXIST = 0;

    /**temp?*/
    private static final String TEMP_FILE_SUFFIX = ".temp";

    /**?*/
    private static final int RETRY = 3;

    /**?1*/
    private static final int RETRY_INTERVAL = 1000;

    /**?*/
    private int mBufferSize;

    /**  */
    private String mUrl;

    /**  */
    private String mLocalFilePath;

    /** nativejs */
    private XCallbackContext mCallbackCtx;

    /** ? */
    private XApplication mApp;

    /** ? */
    private XFileDownloadInfo mDownloadInfo;

    /** ?? */
    private XFileTransferRecorder mFileTransferRecorder;

    /** ? */
    private XFileTransferManager mFileTransferManager;

    private Context mContext;

    private CookieSyncManager mCookieSyncManager;

    public XFileDownloader(Context context, String url, String localFilePath, XExtensionContext extensionContext,
            XApplication app, XFileTransferRecorder recorder, XFileTransferManager manager) {
        init(context, url, localFilePath, extensionContext, app, recorder, manager);
    }

    /** ? */
    private void init(Context context, String url, String localFilePath, XExtensionContext extensionContext,
            XApplication app, XFileTransferRecorder recorder, XFileTransferManager manager) {
        mUrl = url;
        mLocalFilePath = localFilePath;
        mApp = app;
        mFileTransferManager = manager;
        mFileTransferRecorder = recorder;
        mContext = context;
        mCookieSyncManager = CookieSyncManager.createInstance(mContext);
    }

    /**
     * ??(?????
     * ??????)
     */
    private void initDownloadInfo() {
        int totalSize = 0;
        if (isFirst(mUrl)) {
            HttpURLConnection connection = null;
            try {
                URL url = new URL(mUrl);
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(TIME_OUT_MILLISECOND);
                connection.setRequestMethod("GET");
                System.getProperties().setProperty("http.nonProxyHosts", url.getHost());
                //cookie?
                setCookieProperty(connection, mUrl);
                if (HttpURLConnection.HTTP_OK == connection.getResponseCode()) {
                    totalSize = connection.getContentLength();
                    if (-1 != totalSize) {
                        mDownloadInfo = new XFileDownloadInfo(totalSize, 0, mUrl);
                        // ?mDownloadInfo??
                        mFileTransferRecorder.saveDownloadInfo(mDownloadInfo);
                    } else {
                        XLog.e(CLASS_NAME, "cannot get totalSize");
                    }
                    // temp
                    File file = new File(mLocalFilePath + TEMP_FILE_SUFFIX);
                    if (file.exists()) {
                        file.delete();
                    }
                }
            } catch (IOException e) {
                XLog.e(CLASS_NAME, e.getMessage());
            } finally {
                if (null != connection) {
                    connection.disconnect();
                }
            }
        } else {
            // ?url?
            mDownloadInfo = mFileTransferRecorder.getDownloadInfo(mUrl);
            totalSize = mDownloadInfo.getTotalSize();
            mDownloadInfo.setCompleteSize(getCompleteSize(mLocalFilePath + TEMP_FILE_SUFFIX));
        }
        mBufferSize = getSingleTransferLength(totalSize);
    }

    /**
     * ? 
     */
    private boolean isFirst(String url) {
        return !mFileTransferRecorder.hasDownloadInfo(url);
    }

    @Override
    public void transfer(XCallbackContext callbackCtx) {
        initDownloadInfo();
        if (mState == DOWNLOADING) {
            return;
        }
        mCallbackCtx = callbackCtx;
        if (null == mDownloadInfo) {
            onError(CONNECTION_ERR);
        } else {
            setState(DOWNLOADING);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    HttpURLConnection connection = null;
                    RandomAccessFile randomAccessFile = null;
                    InputStream is = null;
                    int retry = RETRY;
                    //TODO:?????
                    do {
                        int completeSize = mDownloadInfo.getCompleteSize();
                        try {
                            URL url = new URL(mUrl);
                            connection = (HttpURLConnection) url.openConnection();
                            connection.setConnectTimeout(TIME_OUT_MILLISECOND);
                            connection.setRequestMethod("GET");
                            // ?Rangebytes x-;
                            connection.setRequestProperty("Range", "bytes=" + completeSize + "-");
                            //cookie
                            setCookieProperty(connection, mUrl);
                            // ?.temp
                            randomAccessFile = new RandomAccessFile(mLocalFilePath + TEMP_FILE_SUFFIX, "rwd");
                            randomAccessFile.seek(completeSize);
                            // ???
                            is = connection.getInputStream();
                            byte[] buffer = new byte[mBufferSize];
                            int length = -1;
                            while ((length = is.read(buffer)) != -1) {
                                try {
                                    randomAccessFile.write(buffer, 0, length);
                                } catch (Exception e) {
                                    retry = -1;
                                    break;
                                }
                                completeSize += length;
                                onProgressUpdated(completeSize, 0);
                                if (PAUSE == mState) {
                                    break;
                                }
                            }
                            if (mDownloadInfo.isDownloadCompleted()) {
                                // ??.temp
                                renameFile(mLocalFilePath + TEMP_FILE_SUFFIX, mLocalFilePath);
                                onSuccess();
                                break;
                            }
                        } catch (IOException e) {
                            if (retry <= 0) {
                                onError(CONNECTION_ERR);
                                XLog.e(CLASS_NAME, e.getMessage());
                            }
                            // ,?1?
                            try {
                                Thread.sleep(RETRY_INTERVAL);
                            } catch (InterruptedException ex) {
                                XLog.e(CLASS_NAME, "sleep be interrupted", ex);
                            }
                        } finally {
                            try {
                                if (null != is) {
                                    is.close();
                                }
                                if (null != randomAccessFile) {
                                    // new URL??randomAccessFilenull
                                    randomAccessFile.close();
                                }
                                if (null != connection) {
                                    // new URL??connectionnull
                                    connection.disconnect();
                                }
                            } catch (IOException e) {
                                XLog.e(CLASS_NAME, e.getMessage());
                            }
                        }
                    } while ((DOWNLOADING == mState) && (0 < retry--));
                }
            }).start();
        }
    }

    private synchronized void setState(int state) {
        mState = state;
    }

    @Override
    public void pause() {
        setState(PAUSE);
    }

    @Override
    public void onSuccess() {
        mFileTransferRecorder.deleteDownloadInfo(mUrl);
        mFileTransferManager.removeFileTranferTask(mApp.getAppId(), mUrl);
        setState(INIT);
        JSONObject jsonObj = new JSONObject();
        try {
            jsonObj = XFileUtils.getEntry(mApp.getWorkSpace(), new File(mLocalFilePath));
        } catch (JSONException e) {
            XLog.e(CLASS_NAME, e.getMessage());
        }
        mCallbackCtx.success(jsonObj);
    }

    @Override
    public void onError(int errorCode) {
        setState(INIT);
        String fullPath = null;
        String workspace = mApp.getWorkSpace();
        if (mLocalFilePath.equals(workspace)) {
            fullPath = File.separator;
        } else {
            fullPath = mLocalFilePath.substring(workspace.length());
        }
        JSONObject error = new JSONObject();
        try {
            error.put("code", errorCode);
            error.put("source", mUrl);
            error.put("target", fullPath);
        } catch (JSONException e) {
            XLog.e(CLASS_NAME, e.getMessage());
        }

        mCallbackCtx.error(error);
    }

    @Override
    public void onProgressUpdated(int completeSize, long totalSize) {
        mDownloadInfo.setCompleteSize(completeSize);
        JSONObject jsonObj = new JSONObject();
        try {
            jsonObj.put("loaded", completeSize);
            jsonObj.put("total", mDownloadInfo.getTotalSize());
        } catch (JSONException e) {
            XLog.e(CLASS_NAME, e.getMessage());
        }
        XExtensionResult result = new XExtensionResult(XExtensionResult.Status.PROGRESS_CHANGING, jsonObj);
        result.setKeepCallback(true);
        mCallbackCtx.sendExtensionResult(result);
    }

    /**
     * ??<br/>
     * ????? <br/>
     * ??1k?2<br/>
     * ?1k-1M?10<br/>
     * ?1M-10M?20<br/>
     * ?10M?2M<br/>
     * */
    private int getSingleTransferLength(int totalSize) {
        // ?
        int totalLength = totalSize;
        //?100?
        if (totalLength < SIZE_KB / DIVIDE_SIZE_TEN) {
            return SIZE_KB / DIVIDE_SIZE_TEN;
        } else if (totalLength < SIZE_KB) {
            return totalLength / DIVIDE_SIZE_TWO;
        } else if (totalLength < SIZE_KB * SIZE_KB) {
            return totalLength / DIVIDE_SIZE_TEN;
        } else if (totalLength < DIVIDE_SIZE_TEN * SIZE_KB * SIZE_KB) {
            return totalLength / DIVIDE_SIZE_TWENTY;
        } else {
            return DIVIDE_SIZE_TWO * SIZE_KB * SIZE_KB;
        }
    }

    /**
     * ???
     *
     * @param oldName:??
     * @param newName:??
     */
    private void renameFile(String oldName, String newName) {
        File file = new File(oldName);
        file.renameTo(new File(newName));
    }

    /**
     * ???-1
     *
     * @param fileName:??
     */
    private int getCompleteSize(String fileName) {
        File file = new File(fileName);
        if (file.exists()) {
            return (int) file.length();
        }
        return FILE_NOT_EXIST;
    }

    /**
     * connectionCookie
     * @param connection   Http
     * @param domain       cookie
     */
    private void setCookieProperty(HttpURLConnection connection, String domain) {
        //Add cookie support
        mCookieSyncManager.startSync();
        String cookie = CookieManager.getInstance().getCookie(domain);
        if (cookie != null) {
            connection.setRequestProperty("cookie", cookie);
        }
    }
}