content: package com.alecgorge.minecraft.jsonapi;
  
  import java.io.BufferedReader;
  import java.io.ByteArrayInputStream;
  import java.io.DataOutputStream;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.util.Properties;
  
  import com.alecgorge.minecraft.jsonapi.streams.StreamingResponse;
  
  public class JSONSocketServer implements Runnable{
  	protected int			serverPort		= 20060;
  	protected ServerSocket	serverSocket	= null;
  	protected JSONServer	jsonServer		= null;
  	protected boolean		isStopped		= true;
  	protected Thread		runningThread	= null;
  
  	public JSONSocketServer(int port, JSONServer jsonServer){
  		this.serverPort = port;
  		this.jsonServer = jsonServer;
  		start();
  	}
  
  	public void run(){
  		synchronized(this){
  			this.runningThread = Thread.currentThread();
  			isStopped = false;
  		}
  		
  		try {
  			if(JSONAPI.instance.bindAddress != null) {
  				this.serverSocket = new ServerSocket(this.serverPort, -1, JSONAPI.instance.bindAddress);
  			}
  			else {
  				this.serverSocket = new ServerSocket(this.serverPort);
  			}
  		} catch (IOException e) {
  			e.printStackTrace();
  		}
  		finally {
  			while(!isStopped()){
  				Socket clientSocket = null;
  				
  				try {
  					clientSocket = this.serverSocket.accept();
  					clientSocket.setTcpNoDelay(true);
  				} catch (IOException e) {
  					if(isStopped()) {
  						return;
  					}
  					e.printStackTrace();
  				}
  				
  				new Thread(
  					new WorkerRunnable(clientSocket)
  				).start();
  			}
  		}
  	}
  	
  	private synchronized boolean isStopped() {
  		return this.isStopped;
  	}
  
  	public synchronized void stop(){
  		this.isStopped = true;
  		try {
  			this.serverSocket.close();
  		} catch (IOException e) {
  			e.printStackTrace();
  		}
  	}
  
  	public synchronized void start(){
  		(new Thread(this)).start();
  	}
  	
  	public class WorkerRunnable implements Runnable{
  
  		protected Socket clientSocket = null;
  		protected String serverText	 = null;
  
  		public WorkerRunnable(Socket clientSocket) {
  			this.clientSocket = clientSocket;
  		}
  
  		public void run() {
  			try {
  				String line2 = "";
  				final BufferedReader input	= new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
  				final DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream());
  
  				while((line2 = input.readLine()) != null) {
  					// format method=xyz&args=[]&username=user&password=pass
  					String[] split = line2.split("\\?", 2);
  					
  					NanoHTTPD.Response r = null;
  					if(split.length < 2) {
  						r = jsonServer.new Response( NanoHTTPD.HTTP_NOTFOUND, NanoHTTPD.MIME_JSON, jsonServer.returnAPIError("", "Incorrect. Socket requests are in the format PAGE?ARGUMENTS. For example, /api/subscribe?source=....").toJSONString());
  					}
  					else {
  						Properties header = new Properties();
  						NanoHTTPD.decodeParms(split[1], header);
  						Properties p = new Properties();
  						p.put("X-REMOTE-ADDR", clientSocket.getInetAddress().getHostAddress());
  						r = jsonServer.serve(split[0], "GET", p, header);
  					}
  					
  					if(r.data instanceof StreamingResponse) {
  						final StreamingResponse s = (StreamingResponse)r.data;
  						(new Thread(new Runnable() {
  							@Override
  							public void run() {
  								String line = "";
  								boolean continueSending = true;
  								
  								while((line = s.nextLine()) != null && continueSending) {
  									try {
  										if(clientSocket.isConnected() && !clientSocket.isClosed()) {
  											output.write((line.trim()+"\r\n").getBytes("UTF-8"));
  										}
  										else {
  											continueSending = false;
  										}
  									} catch (IOException e) {
  										//e.printStackTrace();
  										continueSending = false;
  										try {
  											clientSocket.close();
  											output.close();
  											input.close();
  										} catch (IOException e1) {
  											e1.printStackTrace();
  										}
  									}
  								}
  							}
  						})).start();
  					}
  					else {
  						BufferedReader data;
  						if(r.data != null)
  							data = new BufferedReader(new InputStreamReader(r.data));
  						else
  							data = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(r.bytes)));
  						
  						try {
  							String line = "";
  	
  							while((line = data.readLine()) != null) {
  								output.write((line+"\r\n").getBytes("UTF-8"));
  								// fuck java: output.writeUTF(line+"\r\n");
  							}
  						}
  						catch (IOException e) {
  							e.printStackTrace();
  						}
  					}
  					
  				}
  				output.close();
  				input.close();
  			} catch (IOException e) {
  				try {
  					clientSocket.close();
  				} catch (IOException e1) {
  				}
  				
  				//e.printStackTrace();
  			}
  		}
  	}
  }