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;
System.out.println("Server starting... ");
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 ();
System.out.println("New client started... ");
}
} 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)
{
boolean nametest = false;
//check if name is blank or could mimic a command
if( newUserName.startsWith("/") || newUserName.equals("") )
{
clientName.push(newUserName + " is an invalid user name. Please try another:");
nametest = false;
}
else //check if the name already exists (no duplicates!)
{
temp = (ClientThread) userlist.get(newUserName);
if (temp == null)
{
userlist.put(newUserName, clientName); // If valid add it to the list
nametest = true;
}
else
{ clientName.push(newUserName + " already exists. Please try another:");
nametest = false;
}
}
return nametest;
}
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(String clientName)
{
Enumeration iter = userlist.elements();
temp = (ClientThread) iter.nextElement(); //a user must type whois, thus not null!
String tempstring = temp.userName;
while (iter.hasMoreElements())
{
temp = (ClientThread) iter.nextElement();
tempstring = (tempstring + ", " + temp.userName);
}
temp = (ClientThread) userlist.get(clientName);
temp.push("The users currently online are: " + tempstring);
}
public void help(String clientName)
{
temp = (ClientThread) userlist.get(clientName);
temp.push("Welcome to Superior Chat!! ");
temp.push("");
temp.push("Press return before typing in a message or command.");
temp.push("There are several commands that you may type: ");
temp.push("");
temp.push(" typing a message will broadcast it to all users");
temp.push(" /help - a listing of these commands ");
temp.push(" /whois - a listing of who is on ");
temp.push(" /whisper <username> <message> - whispers to and individual user ");
temp.push(" /quit - exits the server ");
temp.push("");
temp.push("");
}
}//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 boolean messagetest()
{
if (messageQueue.size() > 0)
return true;
else
return false;
}
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,";
push(outputLine);
clientOut.println( pop() );
outputLine = "Enter your Chat Name? (Only letters)";
push(outputLine);
clientOut.println( pop() );
userName = clientIn.readLine(); //gets the user name
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");
MyTimer.timeFor(1000);
outputLine = pop(); //tell me I'm here
clientOut.println(outputLine);
//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
if(messagetest()) //is there a message on this FIFOQ?
{
outputLine = pop(); //if no client input then pop client's FIFOQ
clientOut.println(outputLine);
}
}while(true);
inputLine = clientIn.readLine(); //server thread gets the client's control message
if(inputLine.equals("/USER SENDING")) //the only way they can enter a message or command
{
outputLine = clientIn.readLine();
if (outputLine.startsWith("/")) //is it a command?
{
if (outputLine.startsWith("/whisper")) //parse the whisper command
{
int index = outputLine.indexOf(" ");
String temp = outputLine.substring(index).trim();
index = temp.indexOf(" ");
String toName = temp.substring(0, index).trim();
String message = temp.substring(index).trim();
myManager.whisper("Whisper from " + userName + ":: " + message, toName);
}
else if (outputLine.equals("/whois")) {
myManager.whois(userName);
}
else if (outputLine.equals("/help")) {
myManager.help(userName);
}
else if (outputLine.equals("/quit")) {
break; // out of while loop
}
else{ clientOut.println(outputLine + " is not a valid command"); }
}
else // if it's not a command, it is a broadcast
{ myManager.broadcast(this.userName + ": " + outputLine); }
}//if close
}while(true);
} catch (IOException e){
System.out.println("I/O problems or one of the users dropped");
}
try {
myManager.removeUser(userName);
clientOut.close();
clientIn.close();
clientSocket.close();
clientReady.close();
} catch (IOException e){
System.err.println("couldn't remove somebody");
}
}//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);
}
}