com.taqueue.connection.QueueConnectionManager.java Source code

Java tutorial

Introduction

Here is the source code for com.taqueue.connection.QueueConnectionManager.java

Source

/*
 * Copyright 2010 Chad Brubaker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.taqueue.connection;

import org.apache.http.client.methods.HttpPost;
import org.apache.http.HttpEntity;
import org.apache.http.params.HttpParams;
import android.os.SystemClock;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.client.HttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.client.ResponseHandler;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.params.BasicHttpParams;
import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.lang.Runnable;
import java.util.concurrent.TimeUnit;

/**
 * Class that manages the connections to the queue server
 */
public class QueueConnectionManager implements java.io.Serializable {
    /**
     * The hostname where the queue is hosted
     */
    private static final String HOST = "http://tomcat.eng.utah.edu";
    /**
     * The path to the servlet on the host
     */
    private static final String PATH = "/taqueue/QueueServlet";
    /**
     * Connection timeout in ms
     */
    private static final int CONNECTION_TIMEOUT = 5000;
    /**
     * The 'section'(or class) that we want to be working with
     * @serial
     */
    private String section;

    /**
     * The password for the queue, this is all in plain text since it will be sent over the wire
     * that way(Don't blame me, I'm just doing what the client does)
     * @serial
     */
    private String password;

    /**
     * If we are connected to a queue or not
     * @serial
     */
    private boolean connected;

    /**
     * Manager for the connections to the server
     */
    private transient ThreadSafeClientConnManager manager;

    /**
     * QueueConnectionManager constructor
     */
    public QueueConnectionManager() {
        this.connected = false;
    }

    public String getSection() {
        return section;
    }

    /**
     * Returns whether or not the queue is connected.
     */
    public boolean isConnected() {
        return connected;
    }

    /**
     * Sends a POST to the queue with the parameters nvps, returns the result.
     * @param nvps the NameValuePair of parameters to be sent to the queue server
     * @return ConnectionResult containing the status code for the attempt and the message returned
     * message will be null iff the status is not OK
     */
    private ConnectionResult sendMessage(List<NameValuePair> nvps) {
        ConnectionResult res = new ConnectionResult();
        //default to OK, we'll change in the event of an error
        res.status = ConnectionStatus.OK;
        HttpPost post = new HttpPost(HOST + PATH);
        //DefaultHttpClient client = new DefaultHttpClient();
        //set up the timeout
        HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
        HttpConnectionParams.setSoTimeout(httpParams, CONNECTION_TIMEOUT);
        // set up the connection manager if needed
        if (manager == null) {
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            manager = new ThreadSafeClientConnManager(httpParams, registry);
        }
        DefaultHttpClient client = new DefaultHttpClient(manager, httpParams);
        try {
            //set up our POST values
            post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
            //send it along
            ResponseHandler<String> handler = new BasicResponseHandler();
            connectionWatcher watcher = new connectionWatcher(post);
            Thread t = new Thread(watcher);
            t.start();
            res.message = client.execute(post, handler);
            watcher.finished();
            //and clean up
            //if any exceptions are thrown return a connection error result
        } catch (Exception e) {
            res.status = ConnectionStatus.CONNECTION_ERROR;
            res.message = null;
        } finally {
            post.abort();
        }
        return res;
    }

    /**
     * Tells the servlet to remove the student 'name' at machine.
     * Uses remove(String)
     * @param name Name of the student to remove
     * @param machine Machine the student to remove is on
     * @return the connection result containing the status code for sending the message
     * and the message returned from the server(the state of the queue)
     * IMPORTANT: the returned state of the queue will most likely not include the changes just made by this call
     * it is a `feature' in the queue...
     */
    public ConnectionResult remove(String name, String machine) {
        return this.remove(name + " @ " + machine);
    }

    /**
     * Tells the servlet to remove toRemove from the queue
     * @param toRemove the entry to remove
     * @return  The connection result containing the status code for sending the message
     * and the message returned from the server(the state of the queue)
     * IMPORTANT: the returned state of the queue will most likely not include the changes just made by this call
     * it is a `feature' in the queue...
     */
    public ConnectionResult remove(String toRemove) {
        //first, make sure we have a connection going.
        if (!this.connected) {
            ConnectionResult res = new ConnectionResult();
            res.status = ConnectionStatus.NOT_CONNECTED;
            return res;
        }
        //set up our message parameters
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("REQUEST", "remove"));
        nvps.add(new BasicNameValuePair("SECTION", this.section));
        nvps.add(new BasicNameValuePair("STUDENT", toRemove));
        //I don't know why this command uses "KEY" instead of "PASSWORD", but that is what KEY is[someone was inconsistent].
        nvps.add(new BasicNameValuePair("KEY", this.password));
        //and return the result
        return this.sendMessage(nvps);
    }

    /**
     * Requests an updated student list from the servlet.
     * @return The connection result containing the status code for the send and a String containing the current queue[TODO: cite the format]
     */
    public ConnectionResult update() {
        //first, make sure we have a connection going.
        if (!this.connected) {
            ConnectionResult res = new ConnectionResult();
            res.status = ConnectionStatus.NOT_CONNECTED;
            return res;
        }
        //set up our message parameters
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("REQUEST", "update"));
        nvps.add(new BasicNameValuePair("SECTION", this.section));
        //and return the result
        return this.sendMessage(nvps);
    }

    /**
     * Activate the queue
     * IMPORTANT: the returned state of the queue will most likely not include the changes just made by this call
     * it is a `feature' in the queue...
     * @return The connection result containing the status code for sending the message
     * and the message returned from the server(the state of the queue)
     */
    public ConnectionResult activate() {
        return setStatus("active");
    }

    /**
     * Deactivate the queue
     * IMPORTANT: the returned state of the queue will most likely not include the changes just made by this call
     * it is a `feature' in the queue...
     * @return The connection result containing the status code for sending the message
     * and the message returned from the server(the state of the queue)
     */
    public ConnectionResult deactivate() {
        return setStatus("inactive");
    }

    /**
     * Freeze the queue
     * IMPORTANT: the returned state of the queue will most likely not include the changes just made by this call
     * it is a `feature' in the queue...
     * @return The connection result containing the status code for sending the message
     * and the message returned from the server(the state of the queue)
     */
    public ConnectionResult freeze() {
        return setStatus("frozen");
    }

    /**
     * Sets the queue status to newStatus(accept values are "active","inactive","frozen")
     * IMPORTANT: the returned state of the queue will most likely not include the changes just made by this call
     * it is a `feature' in the queue...
     * @return the connection result containing the status code and message returned(queue state)
     */
    private ConnectionResult setStatus(String newStatus) {
        //first, make sure we have a connection going.
        if (!this.connected) {
            ConnectionResult res = new ConnectionResult();
            res.status = ConnectionStatus.NOT_CONNECTED;
            return res;
        }
        //otherwise activate the queue
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("REQUEST", "change"));
        nvps.add(new BasicNameValuePair("STATUS", newStatus));
        nvps.add(new BasicNameValuePair("SECTION", this.section));
        nvps.add(new BasicNameValuePair("PASSWORD", this.password));
        //return the result of sending that message
        return sendMessage(nvps);
    }

    /**
     * Connects to the queue for class section using the password password
     * Saves the values if successful, otherwise the state is not changed
     * @param sec The class to connect to
     * @param password the password for the queue[NOTE: will be sent in the clear]
     * @return The connection status of the operation, OK on success, CONNECTION_ERROR
     * on any connection related issues, BAD_PASSWORD on a bad password, and 
     * SERV_ERROR on unexpected response from the server
     */
    public ConnectionStatus connectTo(String sec, String password) {
        //set up our POST values
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("REQUEST", "register"));
        nvps.add(new BasicNameValuePair("SECTION", sec));
        nvps.add(new BasicNameValuePair("PASSWORD", password));
        ConnectionResult res = sendMessage(nvps);
        //make sure our message was sent successfully
        if (res.status != ConnectionStatus.OK)
            return res.status;
        //check if the password is valid
        if (res.message.trim().equals("Incorrect password specified."))
            return ConnectionStatus.BAD_PASSWORD;
        //if this happens then something odd has came back to us from the server,ah!
        if (!res.message.trim().equals("success")) {
            System.out.println(res.message.trim());
            return ConnectionStatus.SERV_ERROR;
        }
        this.section = sec;
        this.password = password;
        this.connected = true;
        return ConnectionStatus.OK;
    }

    /**
     * Write the QueueConnectionManager to the output stream out
     */
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
    }

    /**
     * Sets the state of the QueueConnectionManager by reading in
     * NOTE: As of now we don't verify that the data we read is sane
     */
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        this.manager = null;
        in.defaultReadObject();
    }

    private class connectionWatcher implements Runnable {
        public boolean isDone;
        private HttpPost message;

        public connectionWatcher(HttpPost toWatch) {
            isDone = false;
            message = toWatch;
        }

        public void run() {
            SystemClock.sleep(CONNECTION_TIMEOUT);
            if (!isDone)
                message.abort();
        }

        public void finished() {
            isDone = true;
        }
    }
}