net.fluidnexus.FluidNexusAndroid.services.NexusServiceThread.java Source code

Java tutorial

Introduction

Here is the source code for net.fluidnexus.FluidNexusAndroid.services.NexusServiceThread.java

Source

/*
 *  This file is part of Fluid Nexus.
 *
 *  Fluid Nexus 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.
 *
 *  Fluid Nexus 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 Fluid Nexus.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package net.fluidnexus.FluidNexusAndroid.services;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.Vector;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Environment;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import org.apache.http.NameValuePair;
import org.apache.http.HttpVersion;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;

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

import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import oauth.signpost.exception.OAuthNotAuthorizedException;
import oauth.signpost.http.HttpParameters;

import net.fluidnexus.FluidNexusAndroid.provider.MessagesProviderHelper;
import net.fluidnexus.FluidNexusAndroid.Logger;

/**
 * This thread runs all of the device/service discovery and starts threads for socket communication
 */
public class NexusServiceThread extends ServiceThread {
    // Logging
    private static Logger log = Logger.getLogger("FluidNexus");

    // State of the system
    private int state;

    // Potential states
    public static final int STATE_NONE = 0; // we're doing nothing
    public static final int STATE_RESOLVING = 1; // we're resolving things
    public static final int STATE_DISCOVERY_FINISHED = 2; // we're done discovering things and can now move on
    public static final int STATE_SERVICES = 3; // we're discovering services
    public static final int STATE_CONNECTING = 4; // we're connecting other devices
    public static final int STATE_CONNECTED = 5; // we're connected and sending data
    public static final int STATE_WAIT_FOR_CONNECTIONS = 6; // we wait for all of the connection threads to finish
    public static final int STATE_SERVICE_WAIT = 7; // we sleep for a bit before beginning the discovery process anew
    public static final int STATE_QUIT = 100; // we're done with everything

    // Connected devices
    private HashSet<String> connectedDevices = new HashSet<String>();

    // wifi infos
    private WifiManager wifiManager = null;

    // API infos

    private static final String API_BASE = "https://fluidnexus.net/api/01/";
    private static final String HASH_REQUEST_URL = API_BASE + "nexus/hashes/";
    private static final String NEXUS_NONCE_URL = API_BASE + "nexus/message/nonce.json";
    private static final String NEXUS_MESSAGE_URL = API_BASE + "nexus/message/update.json";
    private static final String REQUEST_URL = API_BASE + "request_token/android";
    private static final String ACCESS_URL = API_BASE + "access_token";
    private static final String AUTH_URL = API_BASE + "authorize_token/android";
    private static final String CALLBACK_URL = "fluidnexus://access_token";
    private static CommonsHttpOAuthConsumer consumer = null;
    private static CommonsHttpOAuthProvider provider = new CommonsHttpOAuthProvider(REQUEST_URL, ACCESS_URL,
            AUTH_URL);
    private String key = null;
    private String secret = null;
    private String token = null;
    private String token_secret = null;

    /**
     * Constructor for the thread that does nexus
     */
    public NexusServiceThread(Context ctx, ArrayList<Messenger> givenClients, String gkey, String gsecret,
            String gtoken, String gtoken_secret) {

        super(ctx, givenClients);
        key = gkey;
        secret = gsecret;
        token = gtoken;
        token_secret = gtoken_secret;

        setName("NexusServiceThread");
        wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

        setServiceState(STATE_NONE);
    }

    /**
     * Set the state of the bluetooth service
     * @param state Int that defines the current service state
     */
    @Override
    public synchronized void setServiceState(int newState) {
        //log.debug("Changing state from " + state + " to " + newState);
        state = newState;
    }

    /**
     * Get the current state value
     */
    @Override
    public synchronized int getServiceState() {
        return state;
    }

    /**
     * Start the listeners for zeroconf services
     */
    public void doStateNone() {
        if (wifiManager.getWifiState() == wifiManager.WIFI_STATE_ENABLED) {
            Cursor c = messagesProviderHelper.publicMessages();

            while (c.isAfterLast() == false) {
                String message_hash = c.getString(c.getColumnIndex(MessagesProviderHelper.KEY_MESSAGE_HASH));
                boolean result = checkHash(message_hash);

                if (!result) {
                    try {
                        JSONObject message = new JSONObject();
                        message.put("message_title",
                                c.getString(c.getColumnIndex(MessagesProviderHelper.KEY_TITLE)));
                        message.put("message_content",
                                c.getString(c.getColumnIndex(MessagesProviderHelper.KEY_CONTENT)));
                        message.put("message_hash",
                                c.getString(c.getColumnIndex(MessagesProviderHelper.KEY_MESSAGE_HASH)));
                        message.put("message_type", c.getInt(c.getColumnIndex(MessagesProviderHelper.KEY_TYPE)));
                        message.put("message_time", c.getFloat(c.getColumnIndex(MessagesProviderHelper.KEY_TIME)));
                        message.put("message_received_time",
                                c.getFloat(c.getColumnIndex(MessagesProviderHelper.KEY_RECEIVED_TIME)));
                        message.put("message_priority",
                                c.getInt(c.getColumnIndex(MessagesProviderHelper.KEY_PRIORITY)));

                        String attachment_path = c
                                .getString(c.getColumnIndex(MessagesProviderHelper.KEY_ATTACHMENT_PATH));

                        //String serializedMessage = message.toString();

                        // First, get our nonce
                        consumer = new CommonsHttpOAuthConsumer(key, secret);
                        consumer.setTokenWithSecret(token, token_secret);
                        HttpPost nonce_request = new HttpPost(NEXUS_NONCE_URL);
                        consumer.sign(nonce_request);
                        HttpClient client = new DefaultHttpClient();
                        String response = client.execute(nonce_request, new BasicResponseHandler());
                        JSONObject object = new JSONObject(response);
                        String nonce = object.getString("nonce");

                        // Then, take our nonce and key and put them in the message
                        message.put("message_nonce", nonce);
                        message.put("message_key", key);

                        // Setup our multipart entity
                        MultipartEntity entity = new MultipartEntity();

                        // Deal with file attachment
                        if (!attachment_path.equals("")) {
                            File file = new File(attachment_path);
                            ContentBody cbFile = new FileBody(file);
                            entity.addPart("message_attachment", cbFile);

                            // add the original filename to the message
                            message.put("message_attachment_original_filename", c.getString(
                                    c.getColumnIndex(MessagesProviderHelper.KEY_ATTACHMENT_ORIGINAL_FILENAME)));
                        }

                        String serializedMessage = message.toString();
                        ContentBody messageBody = new StringBody(serializedMessage);
                        entity.addPart("message", messageBody);

                        HttpPost message_request = new HttpPost(NEXUS_MESSAGE_URL);
                        message_request.setEntity(entity);

                        client = new DefaultHttpClient();
                        client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

                        response = client.execute(message_request, new BasicResponseHandler());
                        object = new JSONObject(response);
                        boolean message_result = object.getBoolean("result");

                        if (message_result) {
                            ContentValues values = new ContentValues();
                            values.put(MessagesProviderHelper.KEY_MESSAGE_HASH, message_hash);
                            values.put(MessagesProviderHelper.KEY_UPLOADED, 1);
                            int res = messagesProviderHelper
                                    .setPublic(c.getLong(c.getColumnIndex(MessagesProviderHelper.KEY_ID)), values);
                            if (res == 0) {
                                log.debug("Message with hash " + message_hash
                                        + " not found; this should never happen!");
                            }
                        }

                    } catch (OAuthMessageSignerException e) {
                        log.debug("OAuthMessageSignerException: " + e);
                    } catch (OAuthExpectationFailedException e) {
                        log.debug("OAuthExpectationFailedException: " + e);
                    } catch (OAuthCommunicationException e) {
                        log.debug("OAuthCommunicationException: " + e);
                    } catch (JSONException e) {
                        log.debug("JSON Error: " + e);
                    } catch (IOException e) {
                        log.debug("IOException: " + e);
                    }
                }
                c.moveToNext();
            }

            c.close();

        }

        setServiceState(STATE_SERVICE_WAIT);
    }

    /**
     * Check the hash using the API
     */
    private boolean checkHash(String message_hash) {
        boolean result = true;

        try {
            HttpClient client = new DefaultHttpClient();
            HttpGet request = new HttpGet(HASH_REQUEST_URL + message_hash + ".json");
            String response = client.execute(request, new BasicResponseHandler());
            JSONObject object = new JSONObject(response);
            result = object.getBoolean("result");
        } catch (JSONException e) {
            log.debug("JSON Error: " + e);
        } catch (IOException e) {
            log.debug("IOException: " + e);
        }
        return result;

    }

    private void waitService() {
        try {
            log.debug("Service thread sleeping for " + getScanFrequency() + " seconds...");
            this.sleep(getScanFrequency() * 1000);
        } catch (InterruptedException e) {
            log.error("Thread sleeping interrupted: " + e);
        }

        setServiceState(STATE_NONE);
    }

    /**
     * Begin the thread, and thus the service main loop
     */
    @Override
    public void run() {

        while (getServiceState() != STATE_QUIT) {
            switch (getServiceState()) {
            case STATE_NONE:
                doStateNone();
                break;
            case STATE_SERVICE_WAIT:
                waitService();
                break;
            default:
                break;
            }
        }
    }
}