import java.util.*; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; /** Implementation of Server */ public class ServerImpl extends UnicastRemoteObject implements Server { Hashtable connections = new Hashtable(); public ServerImpl() throws RemoteException { } public void notifyWhoChanged() { // OK. We had to fix a little problem here. // We need to tell all connections that a new user has logged on // However, the user logging on might not be fully established, // and be unable to accept the message that whoChanged until // such time as the log-on is complete. // We can fix this either Server side or Client Side. // The Server side fix is to run this in a seperate thread, // so that if it blocks, we won't delay the return from logon // (which could create deadlock) (new Thread() { public void run() { Hashtable sendTo; synchronized (connections) { sendTo = (Hashtable)connections.clone(); } for (Enumeration e = sendTo.keys(); e.hasMoreElements(); ) { String who = (String)e.nextElement(); Client c = (Client)sendTo.get(who); try { c.whoChanged(); } catch (RemoteException err) { System.out.println("Dropping " + who + " due to remote error"); connections.remove(who); } } } }).start(); } public Connection logon(String name, Client c) throws java.rmi.RemoteException { Connection conn; synchronized (connections) { if (name.equals("Server") || connections.get(name) != null) { c.speak("Server","Sorry, but that name is already in use"); return null; } conn = new ConnectionImpl(name, c, this, connections); connections.put(name,c); } c.speak("Server","Welcome"); notifyWhoChanged(); return conn; } public static void main(String args[]) { try { ServerImpl obj = new ServerImpl(); Naming.rebind("//savoir.cs.umd.edu/ChatServer", obj); // Create and install a security manager // System.setSecurityManager(new RMISecurityManager()); System.out.println("ChatServer bound in registry"); } catch (Exception e) { System.out.println("ChatServerImpl err: " + e.getMessage()); e.printStackTrace(); } } }