package javacodebook.net.socket.threadserver;

import java.io.*;
import java.net.*;

/**
 * @author Benjamin Rusch
 * 
 * Dieser kleine "Datums-Server" empfängt auf Port 5000 über TCP/IP gesendete 
 * Nachrichten. Wird "date" gesendet, übermittelt der Server dem Sender das 
 * Datum, bei "help" wird eine Kurzbeschreibung der verfügaren Befehle über-
 * tragen, und bei "end" wird die Verbindung unterbrochen. Bei allen anderen
 * Eingaben wird eine Fehlermeldung zurückgeschickt. 
 * Dadurch, dass bei jeder Anfrage ein neuer Thread gestartet wird, können 
 * mehrere Anfragen parallel beantwortet werden.
 */

public class TCPThreadServer extends Thread {


	private Socket client;
	private BufferedReader clientIn;
	private PrintWriter clientOut;
	private String cRemoteClient;
	
	/**
	 * Konstruktor von TCPThreadServer. Ihm wird eine Referenz von dem Socket 
	 * des verbundenen Clients übergeben.
	 */
	public TCPThreadServer(Socket client) {
		try {
			this.client= client;
			
			// getInetAddress() liefert die IP-Addresse des Clients
			System.out.println("Client verbunden von " 
					+ client.getInetAddress());   
	
			// Der InputStream vom Socket wird geholt, und an einen 
			// BufferedReader weitergeleitet. So können Client-Meldungen 
			// leicht ausgelesen werden.
			clientIn = new BufferedReader( 
					new InputStreamReader(client.getInputStream()));
	
			// Ein PrintWriter leitet sämtliche Eingaben, an den OutputStream 
			// des Clients weiter. Über Ihn können einfach Meldungen an den 
			// Client übertragen werden.
			clientOut = new PrintWriter(client.getOutputStream(),true);
					  	       
		}
		catch(Exception err) {
			err.printStackTrace();
	    } 
 	}
 	
 	/**
 	 * "run" wird aufgerufen, wenn der Thread gestartet wird. Hier findet 
 	 * die gesamte Abhandlung des Clients statt.
 	 */
	public void run() {
 		try {
   			// Befehl vom Client
			String command;
			
			// Befehl vom Client wird ausgelesen und dem String command
			// zugewiesen, die while()-Schleife wird solange ausgeführt, 
			// solange command nicht "end" ist.
			while(!(command=clientIn.readLine()).equalsIgnoreCase("end")) {
				// wird beim Befehl "date" ausgeführt
				if(command.equals("date")) {
					clientOut.println("Das Datum im Java Format: " 
						+ new java.util.Date());
				}
				// wird beim Befehl "help" ausgeführt
				else if(command.equals("help")) {
					clientOut.println("Befehle: \"date\" liefert Datum,"
							+" \"help\" fuer Hilfe, "
							+"\"end\" fuer Verbindungsende");
				}
				// wird bei allen anderen Fällen ausgeführt.
				else {
					clientOut.println("Sorry, \""+command
							+"\" ist falscher Befehl!");
				}		
			}
	 	}
	 	catch (Exception err) {
	  		err.printStackTrace();
	 	}
	 	finally {
	  		try {		
	   			System.out.println("Verbindung zu "+ client.getInetAddress()
	   					+" wird beendet.");
	   			client.close();
	  		}
	  		catch (IOException err2) { 
	  			err2.printStackTrace();
	  		}
	 	}
	}
 
	/**
	 * main-Methode
	 */
	public static void main(String [] args) {
		try { 
			// Ein ServerSocket wird am Port 5000 angemeldet
			ServerSocket servSock = new ServerSocket(5000);        
		
			System.out.println("Warte auf Verbindung...");      
		                   
		    // Der Server wartet endlos auf Anfragen. Sobald eine eintrifft, 
		    // wird ein neuer Thread gestartet, der sich um alles weitere 
		    // kümmert.
		    while(true) {                             
				// Durch accept() wird der Server in Warteposition gebracht. 
				// In dieser Methode verweilt er, bis ein Client auf diesem 
				// Port ein Request abgibt. Erst dann wird das Socket Objekt, 
				// welches eine Repräsentation des Clients darstellt, 
				// zurückgegeben.
				Socket client = servSock.accept();
							
				// Der Thread, der alles weitere erledigt, ist eine Instanz 
				// dieser Klasse. Es wird jedesmal eine Instanz gebaut und 
				// gestartet, wenn ein Client sich mit diesem Server 
				// verbindet. Übergeben wird das SocketObjekt.
				new TCPThreadServer(client).start();
		    }  			
  		}
 		catch(IOException err) { 
  			err.printStackTrace();
  		}
 	}
}
