Android Open Source - dissertation-project Piece Upload Service






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.service;
/*from  w  w w  .j a  v a  2 s  . c om*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;

import com.fyp.resilience.Constants;
import com.fyp.resilience.Flags;
import com.fyp.resilience.PreferenceConstants;
import com.fyp.resilience.R;
import com.fyp.resilience.ResilienceApplication;
import com.fyp.resilience.ResilienceController;
import com.fyp.resilience.connection.Connectable;
import com.fyp.resilience.connection.ServerUploadConnectable;
import com.fyp.resilience.connection.WifiDownloadConnectable;
import com.fyp.resilience.connection.WifiUploadConnectable;
import com.fyp.resilience.database.model.DataPiece;
import com.fyp.resilience.database.model.DataWhole;
import com.fyp.resilience.event.ServerUploadFinished;
import com.fyp.resilience.event.WifiDownloadFinished;
import com.fyp.resilience.event.WifiUploadFinished;
import com.fyp.resilience.receiver.AbstractConnectivityBroadcastReceiver;
import com.fyp.resilience.receiver.ConnectivityBroadcastReceiver;
import com.fyp.resilience.swarm.model.SwarmClient;
import com.fyp.resilience.util.Utils;
import com.fyp.resilience.widerst.Widerst;

import de.greenrobot.event.EventBus;

/**
 * Responsible for interpreting Event postings and deciding on the pieces that
 * must be uploaded.
 */
public class PieceUploadService extends Service implements ConnectionInfoListener,
        OnSharedPreferenceChangeListener {

    private static final String TAG = PieceUploadService.class.getSimpleName();

    private static final int NOTIFICATION_ID = 100;
    private static final String VERIFICATION_STRING = "resilience_direct_client";

    private ResilienceApplication mApplication;
    private ResilienceController mController;

    private Widerst mWiderstService;

    private ExecutorService mServerUploadExecutor;
    private ExecutorService mWifiUploadExecutor;

    private Notification.Builder mNotificationBuilder;

    private String mServerId;
    private static final int mMaximumServerConnections = 1;
    private int mMaximumWifiConnections;

    private int mCurrentServerConnections;
    private int mCurrentWifiConnections;

    private ServerSocket mSocket;
    private Thread mAcceptThread;
    private Thread mDirectRegistrationThread;

    private IntentFilter mConnIntentFilter;
    private AbstractConnectivityBroadcastReceiver mConnBroadcastReceiver;

    private long mCurrentBackOff = 0;

    private static final Handler mainHandler = new Handler();

    private final Runnable mWifiConnRunnable = new Runnable() {
        @Override
        public void run() {
            mCurrentWifiConnections++;
            updateNotification();
        }
    };

    /**
     * Responsible for listening to {@link Socket} connections sent from
     * {@link WifiUploadConnectable}s.
     */
    class ClientSocketHandler implements Runnable {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    Socket clientSocket = mSocket.accept();

                    Log.d(TAG, "Client has hit service!");

                    Connectable wifiConnection = new WifiDownloadConnectable(
                            PieceUploadService.this,
                            null, clientSocket);

                    final InetAddress clientAddress = clientSocket.getInetAddress();
                    mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            SwarmClient client = mController.getClientFromListWithAddress(clientAddress);
                            if (null == client) {
                                mController.addClientToList(new SwarmClient(clientAddress, Constants.CLIENT_DATA_PORT));
                            }
                        }
                    });

                    mWifiUploadExecutor.submit(wifiConnection);
                    mController.addConnection(wifiConnection);
                    mainHandler.post(mWifiConnRunnable);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * {@link Runnable} that is posted to the UI Thread.
     */
    class DirectAddToSwarmRunnable implements Runnable {

        private final InetAddress mAddress;

        public DirectAddToSwarmRunnable(final InetAddress address) {
            mAddress = address;
        }

        @Override
        public void run() {
            mController.addClientToList(new SwarmClient(mAddress, Constants.CLIENT_DATA_PORT));
            getAndPostNextWifiUploads();
        }
    }

    /**
     * Responsible for listening to {@link Socket} connections send from Wi-Fi
     * Direct Peers.
     */
    class WifiDirectClientVerification implements Runnable {

        @Override
        public void run() {
            try {
                final ServerSocket registerSocket = new ServerSocket(Constants.CLIENT_VERIFICATION_PORT);
                while (!Thread.interrupted()) {
                    Socket newConnection = registerSocket.accept();

                    Log.d(TAG, "Wi-Fi Direct client is registering");

                    final ObjectInputStream input = new ObjectInputStream(newConnection.getInputStream());
                    final Object verificationObject = input.readObject();

                    /* Ensure it is of type String */
                    if (verificationObject.getClass().equals(String.class)) {

                        final String testString = (String) verificationObject;
                        if (testString.equals(VERIFICATION_STRING)) {

                            Log.d(TAG, "Registered a client: " + newConnection.getInetAddress());

                            mainHandler.post(new DirectAddToSwarmRunnable(newConnection.getInetAddress()));
                        }
                    }

                    input.close();
                    newConnection.close();

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Responsible for posting peer verification connections to the Wi-Fi Direct
     * Group Owner.
     */
    static class WifiDirectClientRegistration implements Runnable {

        private final InetAddress mGroupOwnerAddress;

        private static final int retries = 3;

        public WifiDirectClientRegistration(final InetAddress groupOwner) {
            mGroupOwnerAddress = groupOwner;
        }

        @Override
        public void run() {
            
            int count = 0;
            while (count <= retries) {
                try {
                    
                    /* Ensure the connection has settled */
                    Thread.sleep(2000);
                    
                    final Socket newConnection = new Socket(mGroupOwnerAddress, Constants.CLIENT_VERIFICATION_PORT);

                    Log.d(TAG, "Registering with Group Owner: " + mGroupOwnerAddress);

                    final ObjectOutputStream output = new ObjectOutputStream(newConnection.getOutputStream());
                    output.writeObject(new String(VERIFICATION_STRING));

                    output.flush();
                    output.close();

                    newConnection.close();

                    break;

                } catch (Exception e) {
                    e.printStackTrace();
                    count++;
                }
            }
        }
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {

        /*
         * If connected to a Wi-Fi connection then start the Network Service
         * Discovery helper
         */
        if (mController.getSwarmList().size() > 0) {
            if (mController.hasFilesWaiting()) {
                getAndPostNextWifiUploads();
            }
        }

        /*
         * If the device currently has a connection to the Internet, then
         * attempt a post to the server
         */
        if (ConnectivityBroadcastReceiver.isConnected(this)) {
            getAndPostNextServerUploads();
        }

        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        if (Flags.DEBUG) {
            Log.i(TAG, "onCreate has been called");
        }

        /* Register this object with the EventBus */
        EventBus.getDefault().register(this);

        /* Obtain Application instances */
        mApplication = ResilienceApplication.getApplication(this);
        mController = mApplication.getResilienceController();
        mServerUploadExecutor = mApplication.getServerUploadThreadExecutorService();
        mWifiUploadExecutor = mApplication.getWifiUploadThreadExecutorService();
        mMaximumWifiConnections = mApplication.getMaximumWifiThreads();
        mWiderstService = mApplication.getWiderstService();

        /* Retrieve initial preference settings */
        final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPreferences.registerOnSharedPreferenceChangeListener(this);
        mServerId = sharedPreferences.getString(PreferenceConstants.SERVER_ID_KEY, "");

        /* Initialise ConnectivityBroadcastReceiver */
        mConnIntentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        mConnIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        mConnBroadcastReceiver = new ConnectivityBroadcastReceiver(mController,
                (WifiManager) getSystemService(WIFI_SERVICE), this);
        registerReceiver(mConnBroadcastReceiver, mConnIntentFilter);

        try {
            mSocket = new ServerSocket(Constants.CLIENT_DATA_PORT);

            if (null != mSocket) {
                mAcceptThread = new Thread(new ClientSocketHandler(), "Wi-Fi Acceptance");
                mAcceptThread.start();

                mDirectRegistrationThread = new Thread(new WifiDirectClientVerification(), "Wi-Fi Direct Registration");
                mDirectRegistrationThread.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        stopForeground(true);

        mConnBroadcastReceiver.onDestroy();

        EventBus.getDefault().unregister(this);

        PreferenceManager.getDefaultSharedPreferences(this)
                .unregisterOnSharedPreferenceChangeListener(this);

        if (Flags.DEBUG) {
            Log.i(TAG, "onDestroy has been called");
        }
        mController.clearClientList();

        mAcceptThread.interrupt();
        mDirectRegistrationThread.interrupt();

        unregisterReceiver(mConnBroadcastReceiver);

        super.onDestroy();
    }

    @Override
    public IBinder onBind(final Intent intent) {
        return null;
    }

    /**
     * Attempts to retrieve and upload waiting {@link DataPiece}s to the Widerst
     * server.
     */
    private void getAndPostNextServerUploads() {
        if (!Utils.canUploadToServer(this)
                || mCurrentServerConnections >= mMaximumServerConnections) {
            return;
        }

        final DataPiece dataPiece = mController.getNextDataPieceToUpload();
        if (null == dataPiece) {
            if (mController.getConnectionList().size() == 0) {
                stopForeground(true);
            }
            return;
        }

        Connectable connectable = null;
        final DataWhole dataWhole = dataPiece.getParent();
        try {

            File uploadFile = null;
            if (dataWhole.isOwned()) {
                uploadFile = dataWhole.getFile(this);
            } else {
                uploadFile = dataPiece.getFile(this);
            }

            if (null == uploadFile) {
                Log.e(TAG, "FOUND A NULL FILE!?");
                return;
            }

            connectable = new ServerUploadConnectable(this, dataWhole, dataPiece,
                    uploadFile, mWiderstService, mServerId, mCurrentBackOff);

        } catch (FileNotFoundException fe) {
            if (!dataWhole.getFile(this).exists()) {
                // TODO: what to do if file has been deleted
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        if (null != connectable) {
            mController.addConnection(connectable);
            mServerUploadExecutor.submit(connectable);
            mCurrentServerConnections++;

            updateNotification();
        }
    }

    /**
     * Attempts to retrieve and upload waiting {@link DataPiece}s to
     * {@link SwarmClient}s.
     */
    private void getAndPostNextWifiUploads() {

        /* Obtain all pieces that require an upload */
        final List<DataPiece> uploadPieces = mController.getAllPiecesToUpload();

        if (uploadPieces.size() == 0) {
            if (mController.getConnectionList().size() == 0) {
                stopForeground(true);
            }
            return;
        }

        for (final DataPiece piece : uploadPieces) {

            /*
             * Wi-Fi connections can be triggered by incoming connections.
             * Therefore, it is impossible to control the amount that come in
             * but is possible to limit those going out.
             */
            if (mCurrentWifiConnections >= mMaximumWifiConnections) {
                return;
            }

            List<SwarmClient> swarmList = mController.getSwarmList();

            if (swarmList.size() == 0) {
                return;
            }

            SwarmClient swarmClient = null;
            for (final SwarmClient client : swarmList) {
                if (!client.isBusy() && !client.hasPiece(piece)) {
                    swarmClient = client;
                    break;
                }
            }

            if (swarmClient != null) {

                final DataWhole dataWhole = piece.getParent();
                File uploadFile = null;
                /* If a DataWhole is owned then it WILL have a file attached */
                if (dataWhole.isOwned()) {
                    uploadFile = dataWhole.getFile(this);
                } else {
                    uploadFile = piece.getFile(this);
                }

                if (null != uploadFile) {
                    Connectable connectable = null;
                    try {
                        connectable = new WifiUploadConnectable(this, dataWhole, piece,
                                uploadFile, swarmClient);

                    } catch (FileNotFoundException fe) {
                        // TODO
                    } catch (Exception e) {
                        // TODO
                    }

                    if (null != connectable) {
                        swarmClient.setBusy(true);
                        mController.addConnection(connectable);
                        mWifiUploadExecutor.submit(connectable);
                        mCurrentWifiConnections++;
                        updateNotification();
                    }
                }
            }
        }
    }

    /**
     * @param The {@link ServerUploadFinished} event posted to the EventBus.
     */
    public void onEventMainThread(final ServerUploadFinished event) {
        mCurrentServerConnections--;
        int status = event.getConnectable().getConnectionStatus();
        if (status == Connectable.STATUS_CONNECTION_ERROR || status == Connectable.STATUS_RETRYABLE) {
            /* Calculate the backoff on failure */
            calculateBackoff();
        } else {
            /* Reset any backoff value */
            mCurrentBackOff = 0;
        }
        getAndPostNextServerUploads();
        getAndPostNextWifiUploads();
    }

    /**
     * @param The {@link WifiUploadFinished} event posted to the EventBus.
     */
    public void onEventMainThread(final WifiUploadFinished event) {
        Log.d(TAG, "A Wi-Fi upload has finished!");

        final SwarmClient swarmClient = mController.getClientFromListWithAddress(event.getConnectable().getClient()
                .getAddress());
        if (null != swarmClient) {
            swarmClient.setBusy(false);

            if (event.getConnectable().getConnectionStatus() == Connectable.STATUS_SUCCESS) {
                swarmClient.addSuccessfulAttempt();
                swarmClient.addPieceToMap(event.getConnectable().getDataPiece());
            } else {
                if (swarmClient.getFailedAttempts() >= Constants.MAX_SWARM_CLIENT_RETRIES) {
                    /* Remove the client if it */
                    mController.removeClientFromList(swarmClient);
                } else {
                    swarmClient.addFailedAttempt();
                }
            }

        }

        mCurrentWifiConnections--;
        updateNotification();
        getAndPostNextWifiUploads();
    }

    /**
     * @param The {@link WifiDownloadFinished} event posted to the EventBus.
     */
    public void onEventMainThread(final WifiDownloadFinished event) {
        if (event.getConnectable().getConnectionStatus() == Connectable.STATUS_SUCCESS) {
            final SwarmClient client = mController.getClientFromListWithAddress(event.getConnectable().getSocket()
                    .getInetAddress());
            if (null != client) {
                final DataPiece piece = event.getConnectable().getPiece();

                /*
                 * Add the piece to the client map so that we don't attempt to
                 * upload to the same client
                 */
                if (null != piece) {
                    client.addPieceToMap(piece);
                }

            }
        }
        mCurrentWifiConnections--;
        updateNotification();
        getAndPostNextServerUploads();
        getAndPostNextWifiUploads();
    }

    /**
     * Calculates the exponential back-off for a Server connection. If a
     * connection fails then the current back-off is doubled.
     */
    private void calculateBackoff() {
        if (mCurrentBackOff > 0) {
            if ((mCurrentBackOff << 1) < Constants.MAXIMUM_BACKOFF) {
                mCurrentBackOff <<= 1;
                return;
            }
        }

        mCurrentBackOff = TimeUnit.SECONDS.toMillis(2);
    }

    /**
     * Create/Update the foreground notification.
     */
    private void updateNotification() {

        /* Create the Notification if it doesn't already exist */
        if (null == mNotificationBuilder) {
            mNotificationBuilder = new Notification.Builder(this)
                    .setOngoing(true)
                    .setContentTitle("Resilience")
                    .setSmallIcon(R.drawable.ic_launcher);
        }

        /* Set Notification information */
        mNotificationBuilder.setContentText("Server Connections: " + mCurrentServerConnections
                + "\n" +
                "Wi-Fi Connections: " + mCurrentWifiConnections);
        startForeground(NOTIFICATION_ID, mNotificationBuilder.build());
    }

    @Override
    public void onConnectionInfoAvailable(final WifiP2pInfo info) {

        /*
         * Perform check to see who is group owner. This will determine which
         * device goes first.
         */
        if (info.isGroupOwner) {
            Log.d(TAG, "Connected as group owner");
        } else {
            new Thread(new WifiDirectClientRegistration(info.groupOwnerAddress)).start();
            mController.addClientToList(new SwarmClient(info.groupOwnerAddress, Constants.CLIENT_DATA_PORT));
            getAndPostNextWifiUploads();
            Log.d(TAG, "Connected as peer");
        }
    }

    @Override
    public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {

        if (key.equals(PreferenceConstants.SERVER_ID_KEY)) {
            mServerId = sharedPreferences.getString(PreferenceConstants.SERVER_ID_KEY, "");
        }

        getAndPostNextServerUploads();
    }
}




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