Fixed up code, made it prettier, it now follows the stylguide better and is more readable.


git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4182 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/971cv/src/org/spartanrobotics/AccepterThread.java b/971cv/src/org/spartanrobotics/AccepterThread.java
new file mode 100644
index 0000000..ad599de
--- /dev/null
+++ b/971cv/src/org/spartanrobotics/AccepterThread.java
@@ -0,0 +1,140 @@
+/**
+ * 
+ */
+package org.spartanrobotics;
+
+/**
+ * @author daniel
+ * Accepts clients for data server
+ */
+
+import java.io.IOException;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/** Thread accepts new connections for the server and sends data to them 
+ * without blocking.
+ */
+public class AccepterThread implements Runnable {
+	
+	private final static Logger LOG = Logger.getLogger(
+			AccepterThread.class.getName());
+	
+	private ServerSocketChannel sock;
+	
+	private List<Client> connected = new ArrayList<Client>(); 
+	
+	private Thread t;
+	
+	/** Constructor
+	 * 
+	 * @param sock is the ServerSocketChannel that you want to monitor
+	 */
+	public AccepterThread(ServerSocketChannel sock) {
+		t = new Thread(this, "Accepter Thread");
+		t.setPriority(Thread.NORM_PRIORITY - 1); 
+		//lowish priority so Image Processor overrides it
+		this.sock = sock;
+		t.start();
+	}
+	
+	/** Runs in separate thread. Continually accepts new connections. */
+	public void run() {
+		SocketChannel clientSock;
+		while (true) {
+			try {
+				clientSock = sock.accept();
+				//our writes must not block
+				clientSock.configureBlocking(false);
+				Client client = new Client();
+				client.channel = clientSock;
+				connected.add(client);
+			}
+			catch (IOException e) {
+				LOG.warning("Cannot serve image processing results to client:" 
+			+ e.getMessage());
+				Messages.warning("Cannot serve image processing results to client:"
+			+ e.getMessage());
+			}
+		}
+	}
+	
+	/** Sends a message to all currently connected clients.
+	 * 
+	 * @param message is the message that you want to send.
+	 */
+	public void sendtoAll(ByteBuffer message) {
+		/* Copy our connected list, so we don't have 
+		 * to hold our lock forever if the writes block.
+		 */
+		List<Client> connectedTemp = new ArrayList<Client>();
+		for (Client client : connected) {
+			connectedTemp.add(client);
+		}
+		
+		int result;
+		for (Client client : connectedTemp) {
+			try {
+				
+				/** If this socket has data from the 
+				 * last send operation still waiting to be
+				 * sent, send this instead of our original
+				 * message. Since we generally want only
+				 * current data, our original message will
+				 * not be missed. However, it is imperative
+				 * that we finish our pending transmission, 
+				 * because an incomplete transmission could
+				 * leave a client thread somewhere blocking
+				 * indefinitely.
+				 */
+				if (client.toSend != null) {
+					message = client.toSend;
+				}
+				
+				result = client.channel.write(message);
+				
+				/*if our send buffer is full, store our message away
+				 * so we can try again later without halting the thread.
+				 */
+				if (message.remaining() > 0) {
+					client.toSend = message;
+					//check and update our count of failed send attempts
+					++client.failedAttempts;
+					if (client.failedAttempts >= 100) {
+						//Socket has become dysfunctional
+						LOG.info("Write would have blocked 100 times. Assuming peer disconect.");
+						connected.remove(client);
+					}
+				}
+				
+				if (result == -1) {
+					//The write failed. This is probably because the client disconnected.
+					LOG.info("Write returned -1. Client has probably disconnected.");
+					connected.remove(client);
+				}
+			}
+			catch (IOException e) {
+				//The write failed. This is probably because the client disconnected.
+				LOG.info("Write threw IOException. Client has probably disconnected.");
+				connected.remove(client);
+			}
+		}
+	}
+	
+	/** Overloaded sendtoAll method for byte arrays. */
+	public void sendtoAll(byte[] message) {
+		sendtoAll(ByteBuffer.wrap(message));
+	}
+	
+	/** Overloaded sendtoAll method for Strings. */
+	public void sendtoAll(String message) {
+		sendtoAll(message.getBytes());
+	}
+}