import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.awt.*;
public class ChatServer extends JApplet implements ActionListener, Runnable
{
ServerSocket serverSocket = null;
Thread runner = null;
ArrayList users = new ArrayList(); //list of users sorted after ID in alphabetic order.
boolean connected = false;
public void init()
{
setUpWindow();
}
//
static int width =300;
static int height = 200;
Container pane = null;
JLabel t = new JLabel("Port", JLabel.LEFT);
JTextField port = new JTextField("5000", 5);
JButton connect = new JButton("Connect");
JTextArea messages = new JTextArea();
JButton userList = new JButton("users");
void setUpWindow()
{
setSize(width, height);
pane = getContentPane();
pane.setLayout(new BorderLayout());
JPanel junk = new JPanel();
junk.add(t);
junk.add(port);
junk.add(connect);
connect.addActionListener(this);
junk.add(userList, BorderLayout.EAST);
userList.setBackground(Color.blue);
pane.add(junk, BorderLayout.SOUTH);
userList.addActionListener(this);
pane.add(new JScrollPane(messages), BorderLayout.CENTER);
messages.append("*Welcome to ChatServer made by Mads Lenskjær 1-4-2001 (using java 1.3)\n");
}
//
public void start() {}
public void stop()
{
cleanUp();
}
public void actionPerformed(ActionEvent evt)
{
Object s = evt.getSource();
if(s instanceof JButton)
{
JButton b = (JButton)s;
if(b == connect)
{
connected = !connected;
if(connected)
{
try
{
int myPort = Integer.parseInt(port.getText());
if(myPort > 1024)
{
serverSocket = new ServerSocket(myPort);
runner = new Thread(this);
runner.start();
connect.setText("Disconnect");
messages.append("*Server up and running!\n");
InetAddress ia = serverSocket.getInetAddress();
messages.append("*Your hostName: " + ia.getHostName() + " IP:" + ia.getHostAddress() +
" Port:" + serverSocket.getLocalPort() +"\n");
}
else
{
connected = false;
messages.append("*The port number must be above 1024!\n");
}
}catch(Exception e)
{ connected = false;
connect.setText("Connect");
messages.append("*Unable to open socket (try an other port number)\n");
return;
}
}
else
cleanUp();
}
else if(b == userList && connected)
printUserList();
}
}
void cleanUp()
{
terminateAll();
messages.append("*Stopping server listener thread!\n");
if(runner != null)
runner.interrupt();
runner = null;
messages.append("*Closing server socket\n");
if(serverSocket != null)
try{ serverSocket.close(); }catch(IOException e) {}
serverSocket = null;
connect.setText("Connect");
connected = false;
messages.append("*Server has been fully disconnected\n");
}
synchronized void terminateAll()
{
int n = users.size();
messages.append("*Disconnecting "+ n + " clients\n");
for(int i = 0; i < n; i++)
{ ((ClientServer)users.get(0)).closeConnection();
users.remove(0);
}
}
synchronized boolean removeClient(ClientServer cs)
{
int index = Collections.binarySearch(users, cs);
if(index >= 0)
{ ClientServer css = (ClientServer)users.get(index);
users.remove(index);
messages.append("*Client named "+css.ID+" has disconnected.\n");
return true;
}
return false;
}
synchronized boolean addClient(ClientServer cs)
{
int index = Collections.binarySearch(users, cs);
if(index < 0)
{
users.add(-index-1, cs);
return true;
}
else //in the case the user name allready exicist => make it unique
{
cs.ID += ("" + users.size());
System.out.println(cs.ID);
index = Collections.binarySearch(users, cs);
System.out.println(index);
users.add(-index-1,cs);
return false;
}
}
synchronized boolean renameUser(ClientServer cs, String newName)
{
int index = Collections.binarySearch(users, cs);
if(index >= 0)
{
users.remove(index);
cs.ID = newName;
index = Collections.binarySearch(users, cs);
if(index < 0)
{ users.add(cs);
return true;
}
else
{
cs.ID += ("" + users.size());
System.out.println(cs.ID);
index = Collections.binarySearch(users, cs);
System.out.println(index);
users.add(-index-1,cs);
return false;
}
}
return false;
}
synchronized void printUserList()
{
int n = users.size();
messages.append("Corrently " + n + " clients is logged on =>\n");
for(int i = 0; i < n; i++)
messages.append((i+1) + ". " + ((ClientServer)users.get(i)).ID);
}
synchronized String getUserList()
{
int n = users.size();
String names = "";
for(int i = 0; i < n; i++)
names += ((ClientServer)users.get(i)).ID + " ";
return names;
}
synchronized void postMessage(String msg)
{
int n = users.size();
for(int i = 0; i < n; i++)
{
ClientServer cs = (ClientServer)users.get(i);
cs.addMessage(msg);
}
}
synchronized boolean personalMessage(String reciever, String msg)
{
ClientServer cs = new ClientServer(reciever);
int index = Collections.binarySearch(users, cs);
if(index >= 0)
{
ClientServer recieverCS = (ClientServer)users.get(index);
recieverCS.addMessage(msg);
return true;
}
return false;
}
//Server listener thread. => accepting new clients; giving them an sender+reciever thread.
public void run()
{
while(!runner.interrupted())
{
try
{
Socket clientSocket = serverSocket.accept();
ClientServer cs = new ClientServer(clientSocket, this);
//Next the client has to send his name.!
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String name = br.readLine();
cs.ID = name;
if(!addClient(cs))
cs.addMessage("/ChangeName " + cs.ID); //If the name allready exicist, we change it.
messages.append("*New client called "+cs.ID+": "+clientSocket.getInetAddress().toString()+
" "+clientSocket.getPort()+"\n");
postMessage("/NewUser " + cs.ID);
}catch(IOException e) {}
}
}
}
class ClientServer implements Comparable
{
//Sender thread.
class Sender extends Thread
{
Sender() { this.start(); }
void stopSender() { this.interrupt(); }
public void run()
{
try
{
String[] msg = null;
while(!this.interrupted())
{
while((msg = getMessages()) == null)
;
//print all messages for the client.
for(int i = 0; i < msg.length; i++)
pw.println(msg[i]);
}
}catch(Exception e) {}
}
}
//Reciever thread.
class Reciever extends Thread
{
Reciever() { this.start(); }
void stopReciever() { this.interrupt(); }
public void run()
{
try
{
String l = "";
while(!this.interrupted() && l != null)
{ if((l = br.readLine()) != null)
{
l = l.trim();
if(l.charAt(0) == '/')
{
StringTokenizer token = new StringTokenizer(l, " ");
String command = token.nextToken();
//recieving new chat message.
if(command.equals("/cast"))
{
String to = token.nextToken();
l = token.nextToken("\0");
l = l.trim();
//cast message to all in the chat-room
if(to.equals("all"))
cs.postMessage("/cast " + l);
//cast message to the specified person.
else
{
if(cs.personalMessage(to, "/personal " + l))
addMessage("/personal "+l);
else
addMessage("/personal The user ("+to +") you wrote to; is no longer with us!");
}
}
//Change the user name.
else if(command.equals("/name"))
{
String name = token.nextToken();
if(!rename(name))
cs.personalMessage(ID, "/ChangeName " + ID);
}
//send the client a userlist.
else if(command.equals("/UserList"))
{
String userList = cs.getUserList();
addMessage("/UserList " + userList);
}
}
}
}
}catch(IOException e) {}
finally
{
s.stopSender();
cleanUp();
//tell all the other that the client has quit.
cs.postMessage("/QuitUser " + ID);
}
}
}
Socket clientSocket = null;
BufferedReader br = null;
PrintWriter pw = null;
String ID = "";
ArrayList messages = new ArrayList();
ChatServer cs = null;
Sender s = null;
Reciever r = null;
ClientServer(Socket clientSocket, ChatServer cs)
{
this.clientSocket = clientSocket;
this.cs = cs;
try
{
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
pw = new PrintWriter(clientSocket.getOutputStream(), true);
ID = clientSocket.getInetAddress().toString() + clientSocket.getPort();
s = new Sender();
r = new Reciever();
}catch(IOException e) {}
}
ClientServer(String name)
{
this.ID = name;
}
synchronized String[] getMessages()
{
if(messages.size() == 0)
{
try{ this.wait(); }catch(InterruptedException e) {}
}
if(messages.size() > 0)
{
String[] msg = new String[messages.size()];
int n = messages.size();
for(int i = 0; i < n; i++)
{ msg[i] = (String)messages.get(0);
messages.remove(0);
}
return msg;
}
return null;
}
synchronized void addMessage(String msg)
{
messages.add(messages.size(), msg);
this.notifyAll();
}
public int compareTo(java.lang.Object obj)
{
ClientServer cs = (ClientServer)obj;
return ID.compareTo(cs.ID);
}
boolean cleanUp()
{
return cs.removeClient(this);
}
boolean addUp()
{
return cs.addClient(this);
}
boolean rename(String name)
{
return cs.renameUser(this, name);
}
public void closeConnection()
{
s.stopSender();
r.stopReciever();
try{ clientSocket.close(); }catch(IOException e) {}
}
}