//     $Id: ClientRMI.java,v 3.4 1998/12/09 20:06:15 mk2z Exp $    
 ////////////////////////////////////////////////////////////////////////////
 //
 // File: ClientRMI.java
 //
 // Purpose: This is the main communications module on the clients side. Upon
 //        getting started, it looks up to see whether a Registry exists on
 //        a specified port/IP.
 //        It also implements the ClientRMIIface and the interface agreed upon
 //        with the ClientEngine. 
 //
 // Summary of incoming calls from the ServerRMI:
 //
 //    ReceiveMap
 //    Shutdown
 //    
 // Summary of outgoing calls (incoming from ClientEngine):
 //
 //    SetClientID -> RegisterClient -> (ServerRMI)
 //    SendChanges -> ReceiveModule -> (ServerRMI)
 //
 // Authors:
 //  Orim   Miro Kresonja  mk2z@virginia.edu
 //  txe       Travis Emmitt  
 //
 // Modifications:
 //  02-NOV-1998  Orim  Initial creation
 //  04-NOV-1998  txe   Debugging for integration
 //  09-NOV-1998  smg   Added automatic version header
 //  15-NOV-1998  Orim  Initial modifications for version 3.0
 //  18-NOV-1998  txe   Improved exception handling
 //  04-DEC-1998  Orim  Modifications for release 4.0 (conn., extra methods)
 //
 ////////////////////////////////////////////////////////////////////////////
 import java.net.URL;
 import java.rmi.*;
 import java.rmi.server.*;
 import java.util.*;
 public class ClientRMI
     implements ClientRMIIface, java.io.Serializable
 {
   // Class variable declarations
   private static final String DEFAULT_IP   = "mamba.cs.virginia.edu";
   private static final String DEFAULT_PORT = "1202";
   private static final String DEFAULT_RMI_NAME= "ServerRMI";
   private String server_ip_port;
   private String server_rmi_name;
   private int my_id;
   private int my_password;
   private static final int FAILED = 0;
   private ServerRMItoClientIface server_iface = null;
   private ClientEngine my_engine = null;
   ///////////////////////////////////////////////////////////////////
   //
   // ClientRMI Constructor - the client automatically exports itself.
   //   
   ///////////////////////////////////////////////////////////////////
   public ClientRMI (ClientEngine engine)
   throws NullException, Exception {
     my_engine = engine;
     if (engine == null) {
       throw new NullException ("engine");
     }
     // export the RMIClient as a remote object
     Print("Exporting Object");
     UnicastRemoteObject.exportObject(this);
   }
   ///////////////////////////////////////////////////////////////////
   //
   //   Connect - invoked by ClientEngine. It finds the server 
   //   on a specified port, and gets the initial map out of it.
   //
   ///////////////////////////////////////////////////////////////////
   public Map Connect (String ip, String port)
   throws RemoteException, Exception {
       // Get port/host/name information off of the web page
     String temp_ip, temp_port;
     if (ip == null) {
     temp_ip = DEFAULT_IP;
     }
     else {
     temp_ip = ip;
     }
     if (port == null) {
     temp_port = DEFAULT_PORT;
     }
     else {
     temp_port = port;
     }
     server_rmi_name = temp_ip + ":" + temp_port;
       // Look up the server port/service and get the initial map
     String server_name = "//" + server_rmi_name + "/" + DEFAULT_RMI_NAME;
     Print("Server Lookup for '" + server_name + "'");
     server_iface = (ServerRMItoClientIface)Naming.lookup(server_name);
     return (server_iface.ConnectClient());
   }
   ///////////////////////////////////////////////////////////////////
   //
   //   SetClientID - invoked by ClientEngine. It asks the server 
   //   whether it can get a specific module.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean SetClientID (int module_num)
   throws RemoteException, Exception {
     int result = server_iface.RegisterClient (module_num, this);
     if (result != FAILED) {
       my_id = module_num;
       my_password = result;
       return (true);
     }
     else {
         return (false);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   //   Quit - invoked by ClientEngine. It is the only notification of
   //   this event to the server.
   //
   ///////////////////////////////////////////////////////////////////
   public void Quit ()
   throws Exception {
       server_iface.ClientQuit(my_id, my_password);
   }
   ///////////////////////////////////////////////////////////////////
   //   
   //   ReceiveMap - implementation of ClientRMIIface. It gets the Map
   //   object passed to it, and it simply hands it along to the 
   //   ClientEngine.
   //   
   ///////////////////////////////////////////////////////////////////
   public void ReceiveMap (Map m)
   throws RemoteException, Exception {
     try {
         my_engine.ReceiveMap(m, my_id);
     }
     catch (Exception e) {
     my_engine.Error(e);
     throw (e);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //   
   //   ReceiveStats - implementation of ClientRMIIface. It gets the Stats
   //   object passed to it, and it simply hands it along to the 
   //   ClientEngine.
   //   
   ///////////////////////////////////////////////////////////////////
   public void ReceiveStats (Stats stats)
   throws RemoteException, Exception {
     try {
     my_engine.ReceiveStats(stats, my_id);
     }
     catch (Exception e) {
     my_engine.Error(e);
     throw (e);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //   
   //   SendChanges - invoked by ClientEngine. It gets the Module
   //   belonging to this client, and passes it to ServerRMI.
   //   
   ///////////////////////////////////////////////////////////////////
   public void SendChanges(Module m)
   throws Exception {
     try {
     server_iface.ReceiveModule(m, my_id);
     }
     catch (Exception e) {
         my_engine.Error(e);
         throw (e);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //   
   //   Shutdown - implementation of ClientRMIIface. It simply tells
   //   the ClientEngine it's no longer needed.
   //   
   ///////////////////////////////////////////////////////////////////
   public void Shutdown ()
   throws RemoteException, Exception {
     my_engine.Shutdown();
   }
   ///////////////////////////////////////////////////////////////////
   //   
   //   Print - ClientRMI's own method, receiving a string from within
   //   ClientRMI, and in turn hands it off to ClientEngine for display.
   //   
   ///////////////////////////////////////////////////////////////////
   private void Print(String s) {
     my_engine.PrintMessage("RMI: "+s);
   }
 }
 ////////////////////////////////////////////////////////////////////////////