import java.net.*;
import java.io.*;
import java.lang.*;
import java.util.*;
public class Server {
public static void main(String[] args) throws IOException {
int port = 8888;
ServerSocket serverSocket = null;
Socket clientSocket = null;
Manager myManager = new Manager(); //go bureaucracy!
ClientThread clientName = null;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + port + ".");
System.exit(1);
}
try {
while (true)
{ try { clientSocket = serverSocket.accept(); }
catch (IOException e)
{ System.err.println("Accept failed.");
System.exit(1); }
clientName = new ClientThread (clientSocket, myManager);
clientName.start ();
}
} finally { serverSocket.close(); }
}//main close
}//serverthread class close
class Manager
{
Hashtable userlist = new Hashtable(); // Keeps current list of users
ClientThread temp = null;
//each ClientThread obj is called a clientName
//the myManager original obj from Server is passed around alot!
public boolean addUser(String newUserName, ClientThread clientName)
{
//check if name is only characters (no numbers/symbols)
Enumeration iter = userlist.elements(); //name already taken?
while (iter.hasMoreElements())
{
temp = (ClientThread) iter.nextElement();
if (temp.userName == newUserName)
{ clientName.push("Username already taken, please try another.");
return (false); }
}
userlist.put(newUserName, clientName); // If valid add it to the list
return (true);
}
public void removeUser(String userName)
{
userlist.remove(userName); // Simply remove the user and let everyone else know they left
broadcast(userName + " has just left the chat room");
}
public synchronized void broadcast(String message)
{
Enumeration iter = userlist.elements();
while (iter.hasMoreElements())
{
temp = (ClientThread) iter.nextElement();
temp.push(message);
}
}
//sent to only the destination user
public synchronized void whisper(String message, String receiverName)
{
Enumeration iter = userlist.elements();
while (iter.hasMoreElements())
{
temp = (ClientThread) iter.nextElement();
if (temp.userName.equals(receiverName))
{ temp.push(message); }
else
{ continue; }
}
}
public void whois(ClientThread clientName)
{
String tempstring = null;
Enumeration iter = userlist.elements();
while (iter.hasMoreElements())
{
temp = (ClientThread) iter.nextElement();
tempstring = (tempstring + ", " + temp.userName);
}
temp = (ClientThread) userlist.get(clientName);
temp.push(tempstring);
}
}//close of Manager class
class ClientThread extends Thread
{
Socket clientSocket = null;
Manager myManager = null;
String userName = new String();
private LinkedList messageQueue = new LinkedList();//FIFO Q
public ClientThread (Socket clientSocket, Manager myManager)
{
this.clientSocket = clientSocket;
this.myManager = myManager;
}
public void push(String message) // Adds a message to end of Q
{
messageQueue.addLast(message);
}
public String pop() // Pops the oldest string and returns it
{
String message = null;
if(messageQueue.size() == 0)
{
message = null;
}
else
{
message = (String) messageQueue.remove(0);
}
return (message);
}
public void run ()
{
BufferedReader clientIn = null;
PrintWriter clientOut = null;
InputStreamReader clientReady = null;
try {
clientIn = new BufferedReader ( new InputStreamReader(clientSocket.getInputStream() ) );
clientOut = new PrintWriter(clientSocket.getOutputStream(), true);
clientReady = new InputStreamReader(clientSocket.getInputStream() );
} catch (IOException e) {
System.err.println("Could not I/O Client Socket");
System.exit(1);
}
//clientIn, clientOut
try {
String inputLine, outputLine;
//WELCOME
//Server sends userName request, gets first try at userName
//this is unnecessary but sets the example for the rest of the code
outputLine = "Welcome to this CHAT SERVER, What is your Chat Name?";
push(outputLine);
clientOut.println( pop() );
userName = clientIn.readLine();
System.out.println(userName + " is trying to Log On"); //for a possible server log
//addUser returns false if it's an invalid name
//and puts the proper valid/invalid message in the FIFOQ
while( !(myManager.addUser(userName, this)) )
{
clientOut.println("/RETRY NAME"); //control string to client
clientOut.println( pop() ); //the error message
userName = clientIn.readLine(); //try again
}
push(userName + " is validated...");
clientOut.println( pop() ); //the validated message
clientOut.println( userName ); //the validated userName
System.out.println(userName + " is Logged On");
myManager.broadcast(userName + " has just entered the chat room");
//RECEIVE
//these complicated loops synchronize the actions between thread and client
do{
do{
if(clientReady.ready()) //if client is sending
{ break; //break the wait loop
}else{
if( (outputLine = pop()) != null )
{
clientOut.println(outputLine); //if no client input then pop client's FIFOQ
}
MyTimer.timeFor(200);//a fifth second wait
}
}while(true);
inputLine = clientIn.readLine(); //server thread gets the client's control message
//whisper etc will work later
if(inputLine.equals("/USER SENDING")) //the only way they can enter a message or command
{
outputLine = clientIn.readLine();
myManager.broadcast(this.clientName + ": " + outputLine);
}//if close
if(inputLine.equals("/LOG OFF"))
{
clientOut.println("LOG OFF");
clientOut.close();
clientIn.close();
clientSocket.close();
}
}while(true);
} catch (IOException e){
System.err.println("I/O problems");
System.exit(1);
}
}//run
}//class close
class MyTimer
{
//pauses for the "duration" in milliseconds
public static void timeFor(int duration)
{
long timer;
long starttime;
starttime = System.currentTimeMillis();
do{
timer = System.currentTimeMillis();
}while( (timer - starttime) < duration);
}
}