com.vodafone360.people.service.transport.http.photouploadmanager.PhotoUploadManager.java Source code

Java tutorial

Introduction

Here is the source code for com.vodafone360.people.service.transport.http.photouploadmanager.PhotoUploadManager.java

Source

/*
 * CDDL HEADER START
 *
 *@author MyZenPlanet Inc.
 *
 * The contents of this file are subject to the
 * terms of the Common Development and Distribution
 * License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at
 *  src/com/vodafone/people/VODAFONE.LICENSE.txt or
 * ###TODO:URL_PLACEHOLDER###
 * See the License for the specific language governing
 * permissions and limitations under the 
 * License.
 *
 * When distributing Covered Code, include this CDDL HEADER
 * in each file and include the License 
 * file at src/com/vodafone/people/VODAFONE.LICENSE.txt.
 * If applicable, add the following below this CDDL HEADER,
 *  with the fields enclosed by brackets 
 * "[]" replaced with your own identifying information:
 * Portions Copyright [yyyy] [name of
 * copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright 2009 Vodafone Sales & Services Ltd.  All rights reserved.
 * Use is subject to license terms.
 */

package com.vodafone360.people.service.transport.http.photouploadmanager;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import com.caucho.hessian.micro.MicroHessianInput;

import android.util.Log;

import com.caucho.hessian.micro.MicroHessianInput;
import com.vodafone360.people.Settings;
import com.vodafone360.people.SettingsManager;
import com.vodafone360.people.datatypes.BaseDataType;
import com.vodafone360.people.engine.EngineManager.EngineId;
import com.vodafone360.people.service.io.QueueManager;
import com.vodafone360.people.service.io.Request;
import com.vodafone360.people.service.io.ResponseQueue;
import com.vodafone360.people.service.io.Request.Type;
import com.vodafone360.people.service.transport.DecoderThread;
import com.vodafone360.people.service.transport.IConnection;
import com.vodafone360.people.service.transport.DecoderThread.RawResponse;
import com.vodafone360.people.service.transport.http.HttpConnectionThread;
import com.vodafone360.people.service.utils.hessian.HessianDecoder;
import com.vodafone360.people.service.utils.hessian.HessianUtils;
import com.vodafone360.people.utils.LogUtils;

/*
 * PhotoUploadManager uploads the file to the server.
 * There are 2 usecases
 * a)File size is less than 600k 
 * b) file size > 600k.
 * For file size less than 600k,directly payload is made and sent to server using direct httpclient.
 * For file size greater than 600k,chunking is bieng done .
 * The request is sent to server in following three steps.
 * 1)Tell the server that file is to be uplaoded in chunks-using FUNCTION-StartUpload
 * .(Server return uploadid,which is used in subsequent uploading of chunks
 * 2)Read chunks from file and send chunks to server in size of 30k,
 * as mentioned by vodaphone,using function UploadChunk.
 * 3)End the chunking,telling the server that chunking is finished and this is last chunk-using function-UploadEnd.
 *Server return fileuuid.
 *The total request in case of chunking would be like
 * |----StartUpload----|--ReadFromFileInChunks--send chunksto server---|---EndChunking---uploadend--|
 * In the second and third step,uploadid is used,which is returned by server,
 * when startupload request is sent to server as firstpayload.
 *     
 */

public class PhotoUploadManager extends Thread implements IConnection {

    /**
     * Clinet for execution of the httppost
     */
    private volatile HttpClient mHttpClient;

    /**
     * Decoder thread thats going to be same
     */
    private DecoderThread mdecoder = null;
    /**
     * Chunk Number of the payload to be send
     */
    Integer mchunkNumber = 0;
    /**
     * URL to add the content
     */
    private URI mApiUrl;
    /**
     * singleton instance.
     */
    private static PhotoUploadManager m_instance = null;
    /**
     * ref counting for singleton.
     */
    private static int refCount = 0;
    /**
     * Checks whether its runnig.
     */
    Boolean mRunning = true;
    /**
     * Max size to be sent in one go.600k.
     */
    Long MAX_FILE_SEND_IN_ONE_CHUNK = new Long(614400);

    /**
     * Singleton pattern.
     * @param decode
     * @return Instance singleton
     */

    public static PhotoUploadManager getInstanceContentUpload(final DecoderThread decode) {

        if (m_instance != null) {
            refCount++;

        } else {
            m_instance = new PhotoUploadManager(decode);
        }
        return m_instance;
    }

    /**
     * Constructor.
     * @param decode decoder thread.
     */
    PhotoUploadManager(final DecoderThread decode) {
        super();
        mdecoder = decode;
        try {
            mApiUrl = (new URL(SettingsManager.getProperty(Settings.SERVER_URL_HESSIAN_KEY))).toURI();
            int connectionTimeout = Settings.HTTP_CONNECTION_TIMEOUT;
            HttpParams myHttpParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(myHttpParams, connectionTimeout);

            HttpConnectionParams.setSoTimeout(myHttpParams, connectionTimeout);
            mHttpClient = new DefaultHttpClient(myHttpParams); // get http
        } catch (MalformedURLException e) {
            LogUtils.logE("HttpContentUpload-Error defining URL");
        } catch (URISyntaxException e) {
            LogUtils.logE("HttpContentUpload-Error defining URI");
        }

    }

    /**
     * Printing the response.
     * @param response inoput.
     * @return integer.
     */
    final int print(final HttpResponse response) {
        byte[] ret = null;
        int respCode = response.getStatusLine().getStatusCode();
        try {
            HttpEntity entity = response.getEntity();
            if (null != entity) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                InputStream is = entity.getContent();
                if (null != is) {
                    int nextByte = 0;
                    while ((nextByte = is.read()) != -1) {
                        baos.write(nextByte);
                    }
                    baos.flush();
                    ret = baos.toByteArray();
                    baos.close();
                    baos = null;
                }
                entity.consumeContent();
            }
            if (Settings.ENABLED_TRANSPORT_TRACE) {
                int length = 0;
                if (ret != null) {
                    length = ret.length;
                }
                Log.v("HttpContentUpload-handleApiResponse()", "\n \n \n" + "Response with length " + length
                        + " bytes received " + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
                        + (length == 0 ? "" : HessianUtils.getInHessian(new ByteArrayInputStream(ret), false)));

            }
        } catch (IOException e) {
            Log.v("HttpContentUpload Exception", "e" + e);
        }

        return respCode;
    }

    /**
     * first chunk.
     * @param resp
     * @return long 
     */
    Long getUploadIDFromUploadStart(HttpResponse resp) {

        byte[] ret = null;
        HttpEntity entity = resp.getEntity();
        Long uploadid = null;
        InputStream is = null;
        try {
            if (null != entity) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                is = entity.getContent();
            }
            MicroHessianInput mhi = null;
            if (is != null) {
                mhi = new MicroHessianInput(is);
            }
            HessianDecoder hessianDecoder = new HessianDecoder();
            int tag = is.read(); // initial map tag or fail

            if (tag == 'r') { // reply / response
                is.read(); // read major and minor
                is.read();

                tag = is.read(); // read next tag
                // usesReplyTag = true;
            }
            Hashtable<String, Object> map = (Hashtable<String, Object>) mhi.decodeType(tag);
            Enumeration<String> e = map.keys();
            while (e.hasMoreElements()) {
                Object key = e.nextElement();
                Object value = map.get(key);
                String keyObj = (String) key;
                String upload = new String("uploadid");
                if (keyObj.compareTo(upload) == 0) {
                    uploadid = (Long) value;
                    break;
                }
                String numOfChunk = new String("numofchunks");
                if (numOfChunk.compareTo(keyObj) == 0) {
                    mchunkNumber = (Integer) value;

                }
            }
            entity.consumeContent();
        } catch (IOException e) {

        }
        return uploadid;
    }

    /**
     * second chunk.
     * @param request Input.
     * @param reqIds INput.
     * @return hhresponse.
     */
    private HttpResponse UploadFirstPayload(final Request request, final List<Integer> reqIds) {
        byte[] payload1 = request.getEncodedUploadStartPayload();
        HttpResponse resp = null;
        Boolean merror = false;
        try {
            resp = postHTTPRequest(payload1, mApiUrl, Settings.HTTP_HEADER_CONTENT_TYPE);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                // handleApiResponse(resp, reqIds);
            } else {
                merror = true;
                addErrorToResponseQueue(reqIds);
                resp = null;
            }
        } catch (Exception e) {
            addErrorToResponseQueue(reqIds);
            resp = null;
        }
        return resp;
    }

    /**
     * Uploadfile in chnks.
     * @param request Input.
     * @param reqIds Input.
     * @param uploadid Input.
     * @return boolean for success.
     */
    Boolean UploadFileInChunks(final Request request, final List<Integer> reqIds, final Long uploadid) {
        HttpResponse resp = null;
        File mfilname = new File(request.mfileName);
        Boolean merror = false;
        try {
            FileInputStream fin = new FileInputStream(mfilname);
            byte[] arrayBuff = new byte[request.chunkSize];
            Long num = request.mfileSize / new Long(request.chunkSize);
            int offset = 0;
            Integer mchunkNumberToUpload = 1;

            while (mchunkNumber > 1) {
                int sizeread = fin.read(arrayBuff);
                mchunkNumber--;
                offset = offset + sizeread;
                byte[] payload2 = request.getEncodedUploadChunkPayload(arrayBuff, uploadid, mchunkNumberToUpload);
                resp = postHTTPRequest(payload2, mApiUrl, Settings.HTTP_HEADER_CONTENT_TYPE);
                if (print(resp) == HttpStatus.SC_OK) {
                    Log.v("http-contentuplaod", "Response-SC_OK");
                } else {
                    addErrorToResponseQueue(reqIds);
                    merror = true;
                    break;
                }
                mchunkNumberToUpload++;
            }
            if (merror == false) {
                Long left = request.mfileSize - offset;
                byte[] lastOfFile = new byte[left.intValue()];
                int sizeread = fin.read(lastOfFile);
                fin.close();
                byte[] payload3 = request.getEncodedUploadChunkPayload(lastOfFile, uploadid, mchunkNumberToUpload);
                resp = postHTTPRequest(payload3, mApiUrl, Settings.HTTP_HEADER_CONTENT_TYPE);
                if (print(resp) == HttpStatus.SC_OK) {
                    Log.v("HttpContentUpload", "Correct-Http-Response");
                } else {
                    addErrorToResponseQueue(reqIds);
                    merror = true;
                }
            }
        } catch (Exception e) {
            merror = true;
            addErrorToResponseQueue(reqIds);
        }
        return merror;
    }

    /**
     * Uploadfile end.
     * @param request input
     * @param reqIds  input.
     * @param uploadid input.
     * @return boolean.
     */
    private Boolean UploadFileEnd(final Request request, final List<Integer> reqIds, Long uploadid) {
        HttpResponse resp = null;
        Boolean merror = false;
        try {
            byte[] payload4 = request.getEncodedUploadEndPayload(uploadid);
            resp = postHTTPRequest(payload4, mApiUrl, Settings.HTTP_HEADER_CONTENT_TYPE);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                handleApiResponse(resp, reqIds);
            } else {
                merror = true;
                addErrorToResponseQueue(reqIds);
            }
        } catch (Exception e) {
            merror = true;
            addErrorToResponseQueue(reqIds);
        }
        return merror;
    }

    /**
     * Upload file in 1 chunk.
     * @param request input
     * @param reqIds input.
     * @return boolean.
     */
    private Boolean UploadFileInOneChunk(final Request request, final List<Integer> reqIds) {
        Boolean merror = false;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            request.writeToOutputStream(baos, false);
            byte[] payload = baos.toByteArray();
            if (Settings.ENABLED_TRANSPORT_TRACE) {
                logI("AuthenticationManager.handleAuthRequests()",
                        "\n \n \nAUTHENTICATING: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
                                + HessianUtils.getInHessian(new ByteArrayInputStream(payload), true));
            }
            HttpResponse resp = postHTTPRequest(payload, mApiUrl, Settings.HTTP_HEADER_CONTENT_TYPE);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                handleApiResponse(resp, reqIds);
            } else {
                merror = true;
                addErrorToResponseQueue(reqIds);
            }

        } catch (Exception e) {
            merror = true;
            addErrorToResponseQueue(reqIds);
        }
        return merror;
    }

    /**
     * Uses the passed http connection to start a synchronous request against
     * the API. This method blocks until the request is made and the response is
     * retrieved.
     */
    public final void run() {

        while (mRunning) {
            List<Request> requests = QueueManager.getInstance().getApiRequests();
            List<Integer> reqIds = null;
            Boolean error = false;
            if (null == requests) {
                return;
            }
            for (int i = 0; i < requests.size(); i++) {
                Request request = requests.get(i);
                reqIds = new ArrayList<Integer>();
                reqIds.add(request.getRequestId());
                if (request.getAuthenticationType() == 1) { // USE_API==1
                    if (request.mType == Request.Type.UPLOAD_PHOTO) {
                        if (request.mfileSize == null || request.mfileSize < MAX_FILE_SEND_IN_ONE_CHUNK) {
                            UploadFileInOneChunk(request, reqIds);
                        } else {
                            Long uploadid = null;
                            HttpResponse resp = null;
                            resp = UploadFirstPayload(request, reqIds);
                            if (resp != null && resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                                uploadid = getUploadIDFromUploadStart(resp);
                                if (!UploadFileInChunks(request, reqIds, uploadid)) {
                                    if (!UploadFileEnd(request, reqIds, uploadid)) {
                                        Log.i("Photomanager", "Success Upload");
                                    }
                                }
                            }
                        }
                    }
                }
            } // end for
            synchronized (this) {
                try {
                    wait();
                } catch (Exception e) {
                }
            }
        } // end while

    }

    /**
     * Used to post the response to server.Its synchronous API.
     */
    final public HttpResponse postHTTPRequest(final byte[] postData, final URI uri, final String contentType)
            throws Exception {

        HttpResponse response = null;
        if (null == postData) {
            return response;
        }
        if (uri != null) {
            Log.v("httpcontentupload-postHTTPRequest()",
                    "HTTP Requesting URI " + uri.toString() + " " + contentType);
            HttpPost httpPost = new HttpPost(uri);
            httpPost.addHeader("Content-Type", contentType);
            httpPost.addHeader("User-Agent", "PeopleRPGClient/1.0");
            httpPost.addHeader("Cache-Control", "no-cache");
            httpPost.setEntity(new ByteArrayEntity(postData));
            try {
                response = mHttpClient.execute(httpPost);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return response;
    }

    @Override
    public final boolean getIsConnected() {
        return true;
    }

    @Override
    public final boolean getIsRpgConnectionActive() {
        return true;
    }

    @Override
    public void notifyOfRegainedNetworkCoverage() {
    }

    @Override
    public void notifyOfUiActivity() {
    }

    @Override
    public void onLoginStateChanged(final boolean isLoggedIn) {
    }

    @Override
    public final void startThread() {
        mRunning = true;
        start();
    }

    @Override
    public final void stopThread() {
        synchronized (this) {
            mRunning = false;
            notify();
        }
    }

    @Override
    public final void notifyOfItemInRequestQueue() {
        synchronized (this) {
            notify();
            // handleRequests();
        }
    }

    /**
     *
     * @param reqIds input.
     */
    final void addErrorToResponseQueue(final List<Integer> reqIds) {
        EngineId source = null;
        QueueManager requestQueue = QueueManager.getInstance();
        ResponseQueue responseQueue = ResponseQueue.getInstance();
        for (Integer reqId : reqIds) {
            // attempt to get type from request
            Request req = requestQueue.getRequest(reqId);
            if (req != null)
                source = req.mEngineId;
            responseQueue.addToResponseQueue(reqId, null, source);
        }

    }

    /**
     * Handles the synchronous responses for the authentication calls which go
     * against the API directly by adding it to the queue and checking if the
     * response code was a HTTP 200. TODO: this should be refactored into a
     * AuthenticationManager class.
     *
     * @param response
     *            The response to add to the decoder.
     * @param reqIds
     *            The request IDs the response is to be decoded for.
     * @throws Exception
     *             Thrown if the status line could not be read or the response
     *             is null.
     */
    final public void handleApiResponse(final HttpResponse response, final List<Integer> reqIds) throws Exception {
        byte[] ret = null;
        if (null != response) {
            if (null != response.getStatusLine()) {
                int respCode = response.getStatusLine().getStatusCode();

                switch (respCode) {
                case HttpStatus.SC_OK:
                case HttpStatus.SC_CONTINUE:
                case HttpStatus.SC_CREATED:
                case HttpStatus.SC_ACCEPTED:
                case HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION:
                case HttpStatus.SC_NO_CONTENT:
                case HttpStatus.SC_RESET_CONTENT:
                case HttpStatus.SC_PARTIAL_CONTENT:
                case HttpStatus.SC_MULTI_STATUS:
                    HttpEntity entity = response.getEntity();
                    if (null != entity) {
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();

                        InputStream is = entity.getContent();
                        if (null != is) {
                            int nextByte = 0;
                            while ((nextByte = is.read()) != -1) {
                                baos.write(nextByte);
                            }
                            baos.flush();
                            ret = baos.toByteArray();
                            baos.close();
                            baos = null;
                        }
                        entity.consumeContent();
                    }

                    if (Settings.ENABLED_TRANSPORT_TRACE) {
                        int length = 0;
                        if (ret != null) {
                            length = ret.length;
                        }
                        PhotoUploadManager.logI("ResponseReader.handleApiResponse()",
                                "\n \n \n" + "Response with length " + length + " bytes received "
                                        + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" + (length == 0 ? ""
                                                : HessianUtils.getInHessian(new ByteArrayInputStream(ret), false)));

                    }
                    addToDecoder(ret, reqIds);
                    break;
                default:
                    addErrorToResponseQueue(reqIds);
                }
            } else {
                throw new Exception("Status line of response was null.");
            }
        } else {
            throw new Exception("Response was null.");
        }
    }

    /**
     * Adds a response to the response decoder.
     *
     * @param input
     *            The data of the response.
     * @param reqIds
     *            The request IDs that a response was received for.
     */
    private void addToDecoder(final byte[] input, final List<Integer> reqIds) {
        if (input != null && mdecoder != null) {
            int reqId = reqIds.size() > 0 ? reqIds.get(0) : 0;
            mdecoder.addToDecode(new RawResponse(reqId, input, false, false));

        }
    }

    /**
     * logs.
     * @param tag input
     * @param message input
     */
    public static void logI(final String tag, final String message) {
        if (Settings.ENABLED_TRANSPORT_TRACE) {
            Thread t = Thread.currentThread();
            Log.i("(PROTOCOL)", tag + "[" + t.getName() + "]" + " : " + message);
        }
    }

}