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

Java tutorial

Introduction

Here is the source code for com.polyvi.xface.extension.advancedfiletransfer.XFileUploader.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.DataInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import org.json.JSONException;
import org.json.JSONObject;

import com.polyvi.xface.extension.XCallbackContext;
import com.polyvi.xface.extension.XExtensionContext;
import com.polyvi.xface.extension.XExtensionResult;
import com.polyvi.xface.extension.XExtensionResult.Status;
import com.polyvi.xface.plugin.api.XIWebContext;
import com.polyvi.xface.util.XLog;
import com.polyvi.xface.util.XPathResolver;
import com.polyvi.xface.util.XStringUtils;

//???????Content-Length=?;filename=?;sourceid= ??sourceid).
// ???????(? sourceid=?;position=?),?position
public class XFileUploader implements XIFileTransfer, XIFileTransferListener {

    private static final String CLASS_NAME = XFileUploader.class.getSimpleName();

    /**???*/
    private static final String ACTION_NAME_HAND = "HAND";

    /**??*/
    private static final String ACTION_NAME_UPLOAD = "UPLOAD";

    /** http */
    private static final String HTTP_HEAD = "http://";

    /**  */
    private static final int mTimeout = 5000;

    /**??*/

    private static final int FILE_NOT_FOUND_ERR = 1;
    private static final int INVALID_URL_ERR = 2;
    private static final int CONNECTION_ERR = 3;

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

    /**????*/
    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 READ_FILE_END = -1;

    /***/
    private static final int RESULT_CODE_ERROR = -1;

    /**??,1???0??*/
    private static final int RESULT_CODE_CHUNK_RECEIVED = 1;
    private static final int RESULT_CODE_FILE_RECEIVED = 0;

    /**??*/
    private long mUploadFileSize;

    /**???*/
    private int mUploadFileSizePerTime;

    /** ? */
    private String mFilePath;

    /**?*/
    private File mUploadFile;

    /**???id*/
    private String mResponseId;

    /**??*/
    private int mStartedPosition;

    /**???*/
    private int mAlreadyUploadLength;

    /** ?? */
    private String mServer;

    /** nativejs */
    private XCallbackContext mCallbackCtx;

    /** ? */
    private XIWebContext mWebContext;

    /** ?? */
    private XFileTransferRecorder mFileTransferRecorder;

    /** ? */
    private XFileTransferManager mFileTransferManager;

    public XFileUploader(String filePath, String server, XExtensionContext extensionContext,
            XIWebContext webContext, XFileTransferRecorder recorder, XFileTransferManager manager) {
        init(filePath, server, extensionContext, webContext, recorder, manager);
    }

    /** ? */
    private void init(String filePath, String server, XExtensionContext extensionContext, XIWebContext webContext,
            XFileTransferRecorder recorder, XFileTransferManager manager) {
        mFilePath = filePath;
        mServer = server;
        mWebContext = webContext;
        mFileTransferRecorder = recorder;
        mFileTransferManager = manager;
    }

    @Override
    public void onSuccess() {
        mFileTransferRecorder.deleteUploadInfo(mFilePath);
        setState(INIT);
        mFileTransferManager.removeFileTranferTask(mWebContext.getApplication().getAppId(), mFilePath);
        mCallbackCtx.success();
    }

    @Override
    public void onError(int errorCode) {
        setState(INIT);
        JSONObject error = new JSONObject();
        Status status = Status.ERROR;
        try {
            error.put("code", errorCode);
            error.put("source", mFilePath);
            error.put("target", mServer);
        } catch (JSONException e) {
            status = Status.JSON_EXCEPTION;
            XLog.e(CLASS_NAME, e.getMessage());
        }
        XExtensionResult result = new XExtensionResult(status, error);
        mCallbackCtx.sendExtensionResult(result);
    }

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

    /**  */
    private void upload() {
        // URL
        if (!initUploadFileInfo()) {
            return;
        }
        byte[] buffer = new byte[mUploadFileSizePerTime];
        //????
        while ((mAlreadyUploadLength < mUploadFileSize)) {
            //?
            if (!handleShake()) {
                break;
            }
            // ??
            int len = readFileData(buffer);
            //
            if (!uploadData(buffer, len)) {
                break;
            }
        }
        if (mState != PAUSE && mAlreadyUploadLength != mUploadFileSize) {
            onError(CONNECTION_ERR);
        }
    }

    /**
     * ??????id?
     *
     * @return true:??false:?
     */
    private boolean handleShake() {
        HttpURLConnection httpConnection = null;
        DataInputStream dataInputStream = null;
        String souceid = mFileTransferRecorder.getSourceId(mFilePath, "" + mUploadFileSize);
        try {
            httpConnection = getHttpConnection(mServer);
            // ?
            httpConnection.setRequestProperty("Charset", "UTF-8");
            httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            httpConnection.setRequestProperty("ACTIONNAME", ACTION_NAME_HAND);
            httpConnection.setRequestProperty("RESOURCEID", souceid);
            httpConnection.setRequestProperty("FILENAME", getUploadFileName());
            httpConnection.setRequestProperty("FILESIZE", "" + mUploadFileSize);
            if (HttpURLConnection.HTTP_OK == httpConnection.getResponseCode()) {
                // ????? RESOURCEID=?;BFFORE=?
                dataInputStream = new DataInputStream(httpConnection.getInputStream());
                // ???response?
                handleResponse(dataInputStream.readLine());
                // souceid?
                setSourceId(souceid);
            } else {
                onError(INVALID_URL_ERR);
            }
        } catch (Exception e) {
            onError(INVALID_URL_ERR);
            e.printStackTrace();
            return false;
        } finally {
            if (null != httpConnection) {
                httpConnection.disconnect();
                httpConnection = null;
            }
            // ??
            try {
                if (null != dataInputStream) {
                    dataInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * 
     *
     * @return true??,false?
     */
    private boolean uploadData(byte[] buffer, int len) {
        HttpURLConnection httpConnection = null;
        InputStream inStream = null;
        try {
            // 
            httpConnection = getHttpConnection(mServer);
            httpConnection.setRequestProperty("Charset", "UTF-8");
            httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            httpConnection.setRequestProperty("ACTIONNAME", ACTION_NAME_UPLOAD);
            httpConnection.setRequestProperty("RESOURCEID", mResponseId);
            httpConnection.setRequestProperty("BEFORE", "" + mStartedPosition);
            // ??buffer?
            writeBufferData(httpConnection.getOutputStream(), buffer, len);
            // ????
            int resultCode = getResultCode(httpConnection);
            doProcessUpdate(resultCode, len);
            if ((RESULT_CODE_FILE_RECEIVED == resultCode) && (mAlreadyUploadLength == mUploadFileSize)) {
                onSuccess();
            }
            if (mState == PAUSE) {
                return false;
            }
        } catch (Exception e) {
            onError(CONNECTION_ERR);
            XLog.e(CLASS_NAME, "connection error");
            return false;
        } finally {
            if (null != inStream) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpConnection) {
                httpConnection.disconnect();
                httpConnection = null;
            }
        }
        return true;
    }

    /**
     * ??
     *
     * @return true:???,false?
     * */
    private boolean initUploadFileInfo() {
        // URL
        if (null == (mUploadFile = getFile())) {
            onError(FILE_NOT_FOUND_ERR);
            return false;
        }
        if (!mServer.startsWith(HTTP_HEAD)) {
            onError(INVALID_URL_ERR);
            return false;
        }
        mUploadFileSize = getUploadFileSize();
        mUploadFileSizePerTime = getSingleUploadLength();
        return true;
    }

    /**
     * ???
     *
     * @param response
     *            ?response
     * @return true:responsefalse:response
     * */
    private void handleResponse(String response) throws Exception {
        if (XStringUtils.isEmptyString(response)) {
            throw new Exception("response is null");
        }
        String items[] = response.split(";");
        int first_index = items[0].indexOf(":");
        int second_index = items[1].indexOf(":");
        if ((RESULT_CODE_ERROR == first_index) || (RESULT_CODE_ERROR == second_index)) {
            throw new Exception("response error");
        }
        mResponseId = items[0].substring(items[0].indexOf(":") + 1);
        mStartedPosition = Integer.parseInt(items[1].substring(items[1].indexOf(":") + 1));
        if (mStartedPosition > mUploadFileSize) {
            throw new Exception("file StartedPosition is bigger than  fileSize error");
        }
    }

    /**
     * souceid?
     *
     * @param souceid
     *            ?sourceid
     */
    private void setSourceId(String souceid) {
        if (null == souceid) {
            mFileTransferRecorder.saveUploadInfo(mResponseId, mFilePath, "" + mUploadFileSize);
        }

    }

    /**
     * ?buffer?,??
     *
     * @param buffer
     *            :??
     */
    private int readFileData(byte[] buffer) {
        int len = READ_FILE_END;
        RandomAccessFile accessFile = null;
        try {
            accessFile = new RandomAccessFile(mUploadFile, "r");
            accessFile.seek(mStartedPosition);
            len = accessFile.read(buffer);
            if (mStartedPosition != mAlreadyUploadLength) {
                mAlreadyUploadLength = mStartedPosition;
            }
            accessFile.close();
        } catch (FileNotFoundException e) {
            len = READ_FILE_END;
            onError(FILE_NOT_FOUND_ERR);
        } catch (IOException e) {
            len = READ_FILE_END;
            onError(FILE_NOT_FOUND_ERR);
        }
        return len;
    }

    /**
     * buff??
     *
     * @param outStream
     *            ?
     * @param buffer
     *            :??
     * @param len
     *            :??
     * @return ??
     */
    private int writeBufferData(OutputStream outStream, byte[] buffer, int len) throws IOException {
        outStream.write(buffer, 0, len);
        outStream.flush();
        outStream.close();
        return len;
    }

    /**
     * ????
     *
     * @param httpConnection
     *            :http
     * @return 1?? 0? -1??
     */
    private int getResultCode(HttpURLConnection httpConnection) {
        DataInputStream dataInputStream = null;
        try {
            if (HttpURLConnection.HTTP_OK != httpConnection.getResponseCode()) {
                return RESULT_CODE_ERROR;
            }
            // ??RETURN_CODE:1
            dataInputStream = new DataInputStream(httpConnection.getInputStream());
            // ???response?
            String data = dataInputStream.readLine();
            int resultCode = Integer.valueOf(data.substring(data.indexOf(":") + 1));
            return (resultCode == RESULT_CODE_CHUNK_RECEIVED || resultCode == RESULT_CODE_FILE_RECEIVED)
                    ? resultCode
                    : RESULT_CODE_ERROR;
        } catch (Exception e) {
            e.printStackTrace();
            return RESULT_CODE_ERROR;
        } finally {
            try {
                if (null != dataInputStream) {
                    dataInputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 
     *
     * @param len
     *            :?
     */
    private void doProcessUpdate(int resultCode, int len) {
        if (RESULT_CODE_ERROR != resultCode) {
            mAlreadyUploadLength += len;
            XLog.d("xface", "" + mAlreadyUploadLength);
            onProgressUpdated(mAlreadyUploadLength, mUploadFileSize);
        }
    }

    /** ??? */
    private long getUploadFileSize() {
        return mUploadFile.length();
    }

    /** ???? */
    private String getUploadFileName() {
        return mUploadFile.getName();
    }

    /**
     * ?2<br/>
     * 1.?????<br/>
     * 2.??<br/>
     * ????? <br/>
     * ??1k?2<br/>
     * ?1k-1M?10<br/>
     * ?1M-10M?20<br/>
     * ?10M?2M<br/>
     * */
    private int getSingleUploadLength() {
        // ?
        int totalLength = (int) mUploadFileSize;
        //?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;
        }
    }

    /**
     * ?urlhttp
     *
     * @param url
     *            :url?
     * @return urlhttp
     * */
    private HttpURLConnection getHttpConnection(String url)
            throws IOException, MalformedURLException, ProtocolException {
        HttpURLConnection httpConnection;
        httpConnection = ((HttpURLConnection) new URL(url).openConnection());
        httpConnection.setConnectTimeout(mTimeout);
        httpConnection.setRequestMethod("POST");
        httpConnection.setDoInput(true);
        httpConnection.setDoOutput(true);
        return httpConnection;
    }

    @Override
    public void transfer(XCallbackContext callbackCtx) {
        if (mState == UPLOADING) {
            return;
        }
        mCallbackCtx = callbackCtx;
        setState(UPLOADING);
        new Thread(new Runnable() {
            @Override
            public void run() {
                upload();
            }
        }).start();
    }

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

    /**
     * ??
     */
    private File getFile() {
        XPathResolver pathResolver = new XPathResolver(mFilePath, mWebContext.getWorkSpace());
        String absoluteFilePath = pathResolver.resolve();
        File uploadFile = new File(absoluteFilePath);
        if (null != absoluteFilePath) {
            uploadFile = new File(absoluteFilePath);
            if (uploadFile.exists()) {
                return uploadFile;
            }
        }
        return null;
    }

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

}