FetchLiveTimesTask.java :  » App » androidedinburghbustracker » uk » org » rivernile » edinburghbustracker » android » fetchers » Android Open Source

Android Open Source » App » androidedinburghbustracker 
androidedinburghbustracker » uk » org » rivernile » edinburghbustracker » android » fetchers » FetchLiveTimesTask.java
/*
 * Copyright (C) 2010 Niall 'Rivernile' Scott
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors or contributors be held liable for
 * any damages arising from the use of this software.
 *
 * The aforementioned copyright holder(s) hereby grant you a
 * non-transferrable right to use this software for any purpose (including
 * commercial applications), and to modify it and redistribute it, subject to
 * the following conditions:
 *
 *  1. This notice may not be removed or altered from any file it appears in.
 *
 *  2. Any modifications made to this software, except those defined in
 *     clause 3 of this agreement, must be released under this license, and
 *     the source code of any modifications must be made available on a
 *     publically accessible (and locateable) website, or sent to the
 *     original author of this software.
 *
 *  3. Software modifications that do not alter the functionality of the
 *     software but are simply adaptations to a specific environment are
 *     exempt from clause 2.
 */

package uk.org.rivernile.edinburghbustracker.android.fetchers;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import uk.org.rivernile.edinburghbustracker.android.DisplayStopDataActivity;

/**
 * This class is a helper class to the DisplayStopDataActivity. Only a single
 * instance of this class can be created and this is controlled through the
 * getInstance() method. This is used so that problems do not occur regarding
 * null pointers and so in DisplayStopDataActivity.
 *
 * @author Niall Scott
 */
public class FetchLiveTimesTask implements Runnable {

    private final static String STOP_DATA_COMMAND = "getBusTimesByStopCode";

    private static FetchLiveTimesTask instance = null;
    private Handler handler;
    private String stopCode;
    private String remoteHost;
    private int remotePort;
    private boolean executing = false;
    private Thread fetchThread;

    /**
     * This constructor is intentionally left blank and private, this class
     * can only be instantiated from within.
     */
    private FetchLiveTimesTask() {
        // Nothing to do here
    }

    /**
     * Get an instance of this class. A handler object needs to be specified so
     * this class knows where to return the server data to.
     *
     * @param handler The handler object to fire data back to.
     * @return An instance of this class.
     */
    public static FetchLiveTimesTask getInstance(final Handler handler) {
        if(instance == null) instance = new FetchLiveTimesTask();
        instance.setHandler(handler);
        return instance;
    }

    /**
     * Set the handler to fire the data back to. This method is thread safe.
     * This method can even be called when the main task of this class is
     * executing. The handler may need to be changed when the device screen
     * orientation is changed.
     *
     * @param handler The handler object to fire data back to.
     */
    public void setHandler(final Handler handler) {
        if((handler == null || handler != this.handler)
                && fetchThread != null) {
            fetchThread.interrupt();
            executing = false;
        }
        this.handler = handler;
    }

    /**
     * Get the Handler object where data is fired back to.
     *
     * @return The Handler object.
     */
    public Handler getHandler() {
        return handler;
    }

    /**
     * When the thread within this class is executing, true will be returned
     * otherwise false will be returned.
     *
     * @return The execution state of the thread in this class.
     */
    public boolean isExecuting() {
        return executing;
    }

    /**
     * Contact the server and get the JSON string. This data will be fired back
     * to the Handler object specified by getInstance() or setHandler().
     *
     * @param stopCode The stop code to get.
     * @param remoteHost The remote host to connect to.
     * @param remotePort The remote port to connect to.
     */
    public void doTask(final String stopCode, final String remoteHost,
            final int remotePort) {
        this.stopCode = stopCode;
        this.remoteHost = remoteHost;
        this.remotePort = remotePort;
        if(!executing) {
            executing = true;
            fetchThread = new Thread(this);
            fetchThread.start();
        }
    }

    /**
     * The thread in this class.
     */
    @Override
    public void run() {
        Message msg;
        Bundle b = new Bundle();
        try {
            // Set up socket stuff.
            Socket sock = new Socket();
            sock.setSoTimeout(30000);
            sock.connect(new InetSocketAddress(remoteHost, remotePort), 20000);
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(sock.getInputStream()));
            PrintWriter writer = new PrintWriter(sock.getOutputStream(), true);
            writer.println(STOP_DATA_COMMAND + ":" + stopCode);
            String jsonString = "";
            String tmp = "";
            boolean readJson = false;
            while ((tmp = reader.readLine()) != null) {
                if(tmp.startsWith("Error:")) {
                    if(getHandler() != null) {
                        b.putInt("errorCode",
                                DisplayStopDataActivity.ERROR_SERVER);
                        msg = handler.obtainMessage();
                        msg.setData(b);
                        handler.sendMessage(msg);
                    }
                    writer.println("exit");
                    reader.close();
                    writer.close();
                    sock.close();
                    return;
                }
                if (tmp.equals("+")) {
                    readJson = true;
                } else if (tmp.equals("-")) {
                    break;
                } else if (readJson) {
                    jsonString = jsonString + tmp;
                }
            }
            writer.println("exit");
            reader.close();
            writer.close();
            sock.close();

            if(getHandler() == null || fetchThread.isInterrupted()) {
                executing = false;
                return;
            }
            b.putString("jsonString", jsonString);
            msg = handler.obtainMessage();
            msg.setData(b);
            handler.sendMessage(msg);
        } catch (UnknownHostException e) {
            if(getHandler() == null || fetchThread.isInterrupted()) {
                executing = false;
                return;
            }
            b.putInt("errorCode", DisplayStopDataActivity.ERROR_CANNOTRESOLVE);
            msg = handler.obtainMessage();
            msg.setData(b);
            handler.sendMessage(msg);
        } catch (IOException e) {
            if(getHandler() == null || fetchThread.isInterrupted()) {
                executing = false;
                return;
            }
            b.putInt("errorCode", DisplayStopDataActivity.ERROR_NOCONNECTION);
            msg = handler.obtainMessage();
            msg.setData(b);
            handler.sendMessage(msg);
        } finally {
            executing = false;
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.