Android Open Source - dissertation-project Server Upload Connectable






From Project

Back to project page dissertation-project.

License

The source code is released under:

MIT License

If you think the Android project dissertation-project listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.fyp.resilience.connection;
/*from  ww w  .  j a v a2 s.c  o  m*/
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

import android.content.Context;
import android.util.Log;

import com.fyp.resilience.Flags;
import com.fyp.resilience.ResilienceController;
import com.fyp.resilience.database.model.DataPiece;
import com.fyp.resilience.database.model.DataWhole;
import com.fyp.resilience.event.ServerUploadFinished;
import com.fyp.resilience.widerst.Widerst;
import com.fyp.resilience.widerst.model.DataPiecePartial;
import com.fyp.resilience.widerst.model.PostResponse;
import com.google.api.client.http.HttpMethods;

import de.greenrobot.event.EventBus;

public class ServerUploadConnectable extends UploadConnectable {

    private static final String TAG = ServerUploadConnectable.class.getSimpleName();
    private static final String MULTI_PART_BOUNDARY = "********";
    private static final String DOUBLE_HYPHEN = "--";
    public static final String CRLF = "\r\n";
    private static final int BUFFER_SIZE = 4096;

    /**
     * A workaround to counter issue 9172
     * https://code.google.com/p/googleappengine/issues/detail?id=9172
     */
    private static final HostnameVerifier workaroundVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /**
     * @param url - The URL to attempt a connection with.
     * @return A {@link HttpsURLConnection} "linked" with the specified URL.
     */
    private static HttpsURLConnection createMultiPartHttpUrlConnectionFromUrl(final String url) {

        /* If the URL is null then immediately return */
        if (null == url) {
            return null;
        }

        final URL postUrl;
        try {
            postUrl = new URL(url);
        } catch (MalformedURLException e) {
            return null;
        }

        final HttpsURLConnection httpConn;
        try {
            httpConn = (HttpsURLConnection) postUrl.openConnection();
            httpConn.setDoOutput(true);
            httpConn.setUseCaches(false);
            httpConn.setRequestMethod(HttpMethods.POST);
            httpConn.setConnectTimeout(20000);
            httpConn.setReadTimeout(20000);
            httpConn.setRequestProperty("Connection", "Keep-Alive");
            httpConn.setRequestProperty("Cache-Control", "no-cache");
            httpConn.setRequestProperty("Content-Type", "multipart/form-data;boundary="
                    + MULTI_PART_BOUNDARY);
            httpConn.setHostnameVerifier(workaroundVerifier);

        } catch (IOException e) {
            return null;
        }

        return httpConn;
    }

    /**
     * A function to create the multi-part form pre-file upload header. This
     * header constists of the piece & whole IDs as well as the multi-part
     * boundaries.
     * 
     * @param dataPiece - The {@link DataPiece} this connection relates to.
     * @return A {@link StringBuilder} object containing the pre-file header.
     */
    private static StringBuilder createBlobstorePreFileStreamHeader(final DataPiece dataPiece) {

        final StringBuilder headerString = new StringBuilder();
        headerString.append(DOUBLE_HYPHEN + MULTI_PART_BOUNDARY + CRLF);
        headerString.append("Content-Disposition: form-data; name=\"dataPieceId\"");
        headerString.append(CRLF + CRLF);
        headerString.append(dataPiece.getKey());
        headerString.append(CRLF);

        headerString.append(DOUBLE_HYPHEN + MULTI_PART_BOUNDARY + CRLF);
        headerString.append("Content-Disposition: form-data; name=\"dataWholeId\"");
        headerString.append(CRLF + CRLF);
        headerString.append(dataPiece.getParent().getKey());
        headerString.append(CRLF);

        headerString.append(DOUBLE_HYPHEN + MULTI_PART_BOUNDARY + CRLF);
        headerString.append("Content-Disposition: form-data; name=\""
                + dataPiece.getKey() + "\"; filename=\"" + dataPiece.getKey()
                + "\"" + CRLF);

        headerString
                .append("Content-Type: application/octet-stream" + CRLF);
        headerString.append(CRLF);

        return headerString;
    }

    /**
     * A function to create the terminator string of the multi-part request.
     * 
     * @return A {@link StringBuilder} object containing the post-file
     *         terminator.
     */
    private static StringBuilder createBlobstorePostFileStreamTerminator() {
        final StringBuilder requestEndString = new StringBuilder();
        requestEndString.append(CRLF);
        requestEndString.append(DOUBLE_HYPHEN + MULTI_PART_BOUNDARY + DOUBLE_HYPHEN
                + CRLF);

        return requestEndString;
    }

    private final Widerst mService;
    private final long mBackOff;
    private final String mServerId;

    /**
     * @param context - The {@link Context} of the app.
     * @param dataWhole - The {@link DataWhole} parent of the given
     *            {@link DataPiece}.
     * @param dataPiece - The {@link DataPiece} relating to this connection.
     * @param file - The {@link File} of the given {@link DataWhole}.
     * @param service - The instance of the {@link Widerst} service to
     *            communicate with.
     * @param serverId - The current Server ID of this device.
     * @param backoff - The backoff time that the server is currently under.
     * @throws Exception
     */
    public ServerUploadConnectable(final Context context, final DataWhole dataWhole, final DataPiece dataPiece,
            final File file, final Widerst service, final String serverId, final long backoff) throws Exception {

        super(context, dataWhole, dataPiece, file);

        mConnectionType = Connectable.CONNECTION_TYPE_SERVER_UPLOAD;
        mServerId = serverId;
        mService = service;
        mBackOff = backoff;
    }

    private static final int BLOBSTORE_SUCCESS = HttpURLConnection.HTTP_OK;

    @Override
    public int runTask() {

        if (mBackOff > 0) {
            try {
                mConnectionStatus = Connectable.STATUS_BACKING_OFF;
                notifyOfStateChange();

                Thread.sleep(mBackOff);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        mConnectionStatus = Connectable.STATUS_IN_PROGRESS;
        notifyOfStateChange();

        HttpURLConnection httpConn = null;

        try {
            /*
             * Post the DataPiece to the AppEngine backend and wait for a
             * response
             */
            PostResponse postResponse;
            try {
                final DataPiecePartial dataPiecePartial = mDataPiece.toPartial().setDeviceId(
                        mServerId);
                postResponse = mService.pieces().insert(dataPiecePartial).execute();

                /*
                 * Set progress once we've made a connection to ensure a retry
                 * state isn't overwritten
                 */
                mDataPiece.setState(DataPiece.STATE_IN_PROGRESS);

            } catch (EOFException e) {
                return Connectable.STATUS_CONNECTION_ERROR;
            }
            final int postResult = postResponse.getSuccess();

            /* postResult determines the success of the post */
            if (postResult == PostResponse.STATUS_SUCCESS) {

                DataOutputStream requestStream = null;

                try {
                    /*
                     * Instantiate HttpConnection and URL to communicate with
                     * the Blobstore
                     */
                    httpConn = createMultiPartHttpUrlConnectionFromUrl(postResponse.getPostUrl());

                    /* Build the multi-part file requests */
                    final StringBuilder requestHeader = createBlobstorePreFileStreamHeader(mDataPiece);
                    final StringBuilder requestTerminator = createBlobstorePostFileStreamTerminator();

                    httpConn.setFixedLengthStreamingMode(
                            (int) mPieceSize
                                    + requestHeader.toString().length()
                                    + requestTerminator.toString().length());

                    /*
                     * Create a DataOutputStream to construct the multi-part
                     * request
                     */
                    requestStream = new DataOutputStream(
                            httpConn.getOutputStream());

                    /* WRITE HEADER TO THE STREAM */
                    requestStream.writeBytes(requestHeader.toString());

                    /*
                     * Reference previously instantiated RandomAccessFile (field
                     * referencing is SIGNIFICANTLY quicker than getter
                     * functions within Android
                     */

                    final byte[] buff = new byte[BUFFER_SIZE];
                    double totalRead = 0;
                    int lengthRead = 0;
                    int previousProgress = 0;

                    while ((lengthRead = mFile.read(buff)) != -1) {
                        requestStream.write(buff, 0, lengthRead);
                        totalRead += lengthRead;
                        mProgress = (int) ((totalRead / mPieceSize) * 100);
                        if (mProgress != previousProgress) {
                            notifyOfProgressChange();
                        }
                        previousProgress = mProgress;
                    }

                    /* WRITE THE TERMINATOR TO THE STREAM */
                    requestStream.writeBytes(requestTerminator.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                    return Connectable.STATUS_RETRYABLE;
                } finally {
                    if (null != requestStream) {
                        requestStream.flush();
                        requestStream.close();
                    }
                    mFile.close();
                }

                /* Notify the DataPiece of a change to its state */
                if (httpConn.getResponseCode() == BLOBSTORE_SUCCESS) {
                    return Connectable.STATUS_SUCCESS;
                } else {
                    return Connectable.STATUS_RETRYABLE;
                }

            } else if (postResult == PostResponse.STATUS_NOT_REQUIRED) {
                return Connectable.STATUS_NOT_REQUIRED;

            } else if (postResult == PostResponse.STATUS_WHOLE_COMPLETE) {
                return Connectable.STATUS_NONE_REQUIRED;

            } else if (postResult == PostResponse.STATUS_FAILED) {
                return Connectable.STATUS_CONNECTION_ERROR;

            } else if (postResult == PostResponse.STATUS_BUSY) {
                return Connectable.STATUS_CONNECTION_ERROR;

            } else if (postResult == PostResponse.STATUS_REGISTRATION_ERROR) {
                return Connectable.STATUS_REGISTRATION_ERROR;

            }

        } catch (IOException e) {
            /*
             * TODO: If this is called then something has gone VERY wrong. The
             * file SHOULD exist due to being checked within Connectable.
             */
            if (Flags.DEBUG) {
                e.printStackTrace();
            }
        } finally {
            /* Disconnect the connection to ensure the GC can reclaim */
            if (httpConn != null) {
                httpConn.disconnect();
            }
        }

        return Connectable.STATUS_CONNECTION_ERROR;

    }

    @Override
    protected void runPostTask() {
        final Context context = mContext.get();
        if (null != context) {
            final ResilienceController controller = ResilienceController.getInstance(context);
            switch (mConnectionStatus) {
                case Connectable.STATUS_SUCCESS:
                case Connectable.STATUS_NOT_REQUIRED:
                    mDataPiece.setState(DataPiece.STATE_UPLOADED_TO_SERVER);
                    mDataPiece.setRetry(false);
                    Log.d(TAG, mDataPiece.getKey() + "Piece uploaded");
                    break;

                case Connectable.STATUS_NONE_REQUIRED:
                    mDataWhole.setState(DataWhole.STATE_COMPLETED);
                    mDataWhole.setAvailability(true);
                    controller.removeDataPieces(mDataWhole);
                    controller.addDataWhole(mDataWhole);

                    Log.d(TAG, mDataPiece.getKey() + "Piece none required");
                    break;

                case Connectable.STATUS_RETRYABLE:
                    mDataPiece.setRetry(true);
                    Log.d(TAG, mDataPiece.getKey() + "Piece requires a try");
                    break;

                default:
                    mDataPiece.setState(DataPiece.STATE_NONE);
                    Log.d(TAG, mDataPiece.getKey() + "Piece errored with " + mConnectionStatus);
                    break;
            }
            controller.removeConnection(this);
        }
    }

    @Override
    protected void notifyOfCompletion() {
        EventBus.getDefault().post(new ServerUploadFinished(this));
    }
}




Java Source Code List

com.fyp.resilience.Constants.java
com.fyp.resilience.Flags.java
com.fyp.resilience.GCMIntentService.java
com.fyp.resilience.PreferenceConstants.java
com.fyp.resilience.ResilienceApplication.java
com.fyp.resilience.ResilienceController.java
com.fyp.resilience.activity.LicenceActivity.java
com.fyp.resilience.activity.ResilienceActivity.java
com.fyp.resilience.activity.SettingsActivity.java
com.fyp.resilience.adapter.ClientListAdapter.java
com.fyp.resilience.adapter.ConnectionListAdapter.java
com.fyp.resilience.adapter.FileListAdapter.java
com.fyp.resilience.connection.Connectable.java
com.fyp.resilience.connection.ServerDownloadConnectable.java
com.fyp.resilience.connection.ServerUploadConnectable.java
com.fyp.resilience.connection.UploadConnectable.java
com.fyp.resilience.connection.WifiDownloadConnectable.java
com.fyp.resilience.connection.WifiUploadConnectable.java
com.fyp.resilience.database.ResilienceDbHelper.java
com.fyp.resilience.database.ResilienceDbManager.java
com.fyp.resilience.database.model.DataPiece.java
com.fyp.resilience.database.model.DataWhole.java
com.fyp.resilience.event.ClientListChanged.java
com.fyp.resilience.event.ClientModified.java
com.fyp.resilience.event.ConnectionProgressChange.java
com.fyp.resilience.event.ConnectionStateChange.java
com.fyp.resilience.event.ConnectionsModified.java
com.fyp.resilience.event.PieceStateChange.java
com.fyp.resilience.event.ServerRegistrationChanged.java
com.fyp.resilience.event.ServerUploadFinished.java
com.fyp.resilience.event.WholeModified.java
com.fyp.resilience.event.WifiDownloadFinished.java
com.fyp.resilience.event.WifiUploadFinished.java
com.fyp.resilience.fragment.ClientsFragment.java
com.fyp.resilience.fragment.ConnectionsFragment.java
com.fyp.resilience.fragment.FilesFragment.java
com.fyp.resilience.interfaces.Messagable.java
com.fyp.resilience.interfaces.Partialable.java
com.fyp.resilience.proto.ProtoBuffSpecification.java
com.fyp.resilience.receiver.AbstractConnectivityBroadcastReceiver.java
com.fyp.resilience.receiver.BootReceiver.java
com.fyp.resilience.receiver.ConnectivityBroadcastReceiver.java
com.fyp.resilience.receiver.WiFiDirectBroadcastReceiver.java
com.fyp.resilience.register.RegisterRequestInitializer.java
com.fyp.resilience.register.RegisterRequest.java
com.fyp.resilience.register.RegisterScopes.java
com.fyp.resilience.register.Register.java
com.fyp.resilience.register.model.DeviceInfo.java
com.fyp.resilience.service.PieceUploadService.java
com.fyp.resilience.stream.PiecedRandomAccessFile.java
com.fyp.resilience.swarm.helper.NsdHelper.java
com.fyp.resilience.swarm.helper.SwarmHelperInterface.java
com.fyp.resilience.swarm.helper.WifiDirectSdHelper.java
com.fyp.resilience.swarm.model.SwarmClient.java
com.fyp.resilience.thread.ResilienceRunnable.java
com.fyp.resilience.thread.ResilienceThreadFactory.java
com.fyp.resilience.util.ConnectionUtils.java
com.fyp.resilience.util.Utils.java
com.fyp.resilience.view.ClientView.java
com.fyp.resilience.view.ConnectionView.java
com.fyp.resilience.view.FileView.java
com.fyp.resilience.view.PieceProgressIndicator.java
com.fyp.resilience.widerst.WiderstRequestInitializer.java
com.fyp.resilience.widerst.WiderstRequest.java
com.fyp.resilience.widerst.WiderstScopes.java
com.fyp.resilience.widerst.Widerst.java
com.fyp.resilience.widerst.model.DataPiecePartial.java
com.fyp.resilience.widerst.model.DataWholePartial.java
com.fyp.resilience.widerst.model.PostResponse.java
com.fyp.widerst.Constants.java
com.fyp.widerst.WiderstObjectifyService.java
com.fyp.widerst.backend.FileJoinerBackend.java
com.fyp.widerst.cron.CronJobServlet.java
com.fyp.widerst.endpoint.DataPieceEndpoint.java
com.fyp.widerst.endpoint.DeviceInfoEndpoint.java
com.fyp.widerst.entity.DataPiece.java
com.fyp.widerst.entity.DataWhole.java
com.fyp.widerst.entity.DeviceInfo.java
com.fyp.widerst.handler.BlobstoreUploadHandler.java
com.fyp.widerst.partial.DataPiecePartial.java
com.fyp.widerst.partial.DataWholePartial.java
com.fyp.widerst.response.PostResponse.java
com.fyp.widerst.servlet.WholeFileServer.java
com.fyp.widerst.util.DbHelper.java
com.fyp.widerst.util.GcmHelper.java