// $Id: ServerRMI.java,v 3.8 1998/12/14 04:06:25 mk2z Exp $
////////////////////////////////////////////////////////////////////////////
//
// File: ServerRMI.java
//
// Purpose: This is the main RMI module on the server side. On startup,
// it starts its own registry and binds itself into the registry.
// It also implements methods from the ServerRMI***Iface.
//
// Authors:
// Orim Miro Kresonja mk2z@virginia.edu
// txe Travis Emmitt
// smg Jimbo smg9c@virginia.edu
//
// Modifications:
// 02-NOV-1998 Orim Initial creation
// 09-NOV-1998 smg Added automatic version header
// 15-NOV-1998 Orim Initial modifications for version 3.0
// 17-NOV-1998 Orim Final exception throwing fixes
// 04-DEC-1998 Orim New features for v4.0
// 08-DEC-1998 Orim Added state knowledge to ServerRMI
//
////////////////////////////////////////////////////////////////////////////
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.LocateRegistry;
import java.util.*;
public class ServerRMI
extends UnicastRemoteObject
implements ServerRMItoClientIface, ServerRMItoDemonIface
{
// Note: on change of the next two variables, see ClientRMI.java
// and DemonRMI.java
private static final int SERVER_PORT = 1202;
private static final String SERVER_RMI_NAME = "ServerRMI";
private static final int FAILED = 0; // failed (password)
// ServerRMI keeps the state of the simulation
private static final int SIM_CHOOSEMODE = 0;
private static final int SIM_WAITSUBMIT = 1;
private static final int SIM_RUNNING = 2;
private static final int SIM_SHUTDOWN = 3;
private int sim_state = SIM_CHOOSEMODE;
private static final int DEMON_ID = 0;
private static final int EXP_DEMONS = 1;
private Connections connect_obj = null;
private ServerEngine my_engine;
///////////////////////////////////////////////////////////////////
//
// ServerRMI [constructor] - Creates its own registry, and binds
// itself in there.
//
///////////////////////////////////////////////////////////////////
public ServerRMI (ServerEngine engine, int port, int exp_clients)
throws RemoteException {
// Initialize variables
my_engine = engine;
try {
connect_obj = new Connections(exp_clients, EXP_DEMONS);
// Create and install the security manager
System.setSecurityManager(new RMISecurityManager());
Print("Creating registry");
if (port == 0) {
port = SERVER_PORT;
}
LocateRegistry.createRegistry(port);
String location = "//:" + port + "/" + SERVER_RMI_NAME;
Print ("Binding server to '" + location + "'");
Naming.rebind (location, this);
Print ("Binding done");
// state = start of the entire simulation
sim_state = SIM_CHOOSEMODE;
}
catch (Exception e) {
Print ("Exception - " + e.getMessage());
}
}
///////////////////////////////////////////////////////////////////
//
// ConnectClient - Implementation of a ServerRMItoClientIface method.
// Client asks for the initial map, and is given one.
//
///////////////////////////////////////////////////////////////////
public Map ConnectClient ()
throws RemoteException, Exception {
try {
return(my_engine.GetMap());
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
}
///////////////////////////////////////////////////////////////////
//
// ConnectDemon - Implementation of a ServerRMItoDemonIface method.
// Demon asks for the initial map, and is given one.
//
///////////////////////////////////////////////////////////////////
public Map ConnectDemon ()
throws RemoteException, Exception {
try {
return(my_engine.GetMap());
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
}
///////////////////////////////////////////////////////////////////
//
// RegisterClient - Implementation of a ServerRMItoClientIface method.
// If that module is free, the server accepts the remote pointer
// to a client, adds it to its list, and if that is the last module,
// notifies the ServerEngine that all the clients have reported in.
// Note: The clients are returned numbers starting with 0, increasing
// by 1 with each registration.
//
///////////////////////////////////////////////////////////////////
public int RegisterClient (int module, ClientRMIIface obj)
throws RemoteException, Exception {
int password = FAILED;
try {
password=connect_obj.AddClient(module, obj);
if (password != FAILED) {
Print("Client registered for module "+(module));
SendConnectionsToDemon(connect_obj);
}
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
return(password);
}
///////////////////////////////////////////////////////////////////
//
// RegisterDemon - Implementation of a ServerRMItoDemonIface method.
// A Demon is unconditionally registered (once). If there are other
// demons running, the newest one will not register.
//
///////////////////////////////////////////////////////////////////
public int RegisterDemon (DemonRMIIface obj)
throws RemoteException, Exception {
int password = FAILED;
try {
password = connect_obj.AddDemon(DEMON_ID, obj);
if (password != FAILED) {
Print("Demon registered");
// send connections, state_of_sim to demon
SendConnectionsToDemon(connect_obj);
SendStateToDemon(sim_state);
}
else {
obj.ReceiveState(SIM_SHUTDOWN);
}
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
return(password);
}
///////////////////////////////////////////////////////////////////
//
// ReceiveModule - Implementation of a ServerRMIIface method.
// Once the clients complete changing their own modules, they
// pass them back to server in a following way: ClientEngine ->
// ClientRMI -> ServerRMI -> ServerEngine. This Method acts as a
// bridge between the last two stations, ServerRMI (this class)
// and ServerEngine (its UpdateMap method is called).
//
///////////////////////////////////////////////////////////////////
public void ReceiveModule(Module m, int client_id)
throws RemoteException, Exception {
try {
Print("Received Module from Client "+client_id);
connect_obj.SetClientSubStatus(client_id, true);
my_engine.UpdateMap(m, client_id);
// Send status to demon
SendConnectionsToDemon(connect_obj);
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
}
///////////////////////////////////////////////////////////////////
//
// SubmitMode - accepts exec. mode from DemonRMI, passes them
// onto ServerEngine.
//
///////////////////////////////////////////////////////////////////
public boolean SubmitMode(int mode, int runs)
throws RemoteException, Exception {
try {
// change the simulation mode
my_engine.SubmitMode(mode, runs);
sim_state = SIM_WAITSUBMIT;
// just in case, set everybody's submission to false
connect_obj.SetAllSubmitFalse();
// then we re-send the maps out
//? Am I supposed to selectively do this (on Auto, do not resend?)
Map m = my_engine.GetMap();
SendMapAll(m);
// send state to demon
SendStateToDemon(sim_state);
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
return(true);
}
///////////////////////////////////////////////////////////////////
//
// StartRun - accepts parameters from DemonRMI, then starts the run
// of the simulation.
//
///////////////////////////////////////////////////////////////////
public boolean StartRun (int propagation, long delay)
throws RemoteException, Exception {
try {
// change the simulation status, run it
sim_state = SIM_RUNNING;
my_engine.BeginSimulation(propagation, delay);
// send state to demon
SendStateToDemon(sim_state);
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
return(true);
}
///////////////////////////////////////////////////////////////////
//
// Abort - tells the server to stop the current run.
//
///////////////////////////////////////////////////////////////////
public boolean Abort()
throws RemoteException, Exception {
try {
sim_state = SIM_CHOOSEMODE;
my_engine.Abort();
// then we re-send the maps out
Map m = my_engine.GetMap();
SendMapAll(m);
// send state to demon
SendStateToDemon(sim_state);
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
return(true);
}
///////////////////////////////////////////////////////////////////
//
// Shutdown - tells all clients to shutdown.
//
///////////////////////////////////////////////////////////////////
public boolean Shutdown()
throws RemoteException, Exception {
ClientRMIIface client_iface = null;
try {
int num_exp = connect_obj.GetNumClients();
for (int i=0; i<num_exp; ++i) {
if (connect_obj.GetClientConnStatus(i)) {
client_iface=connect_obj.GetClientIface(i);
client_iface.Shutdown();
}
}
sim_state = SIM_SHUTDOWN;
SendStateToDemon(sim_state);
my_engine.ShutDown();
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
return(true);
}
///////////////////////////////////////////////////////////////////
//
// ClientQuit - tells the server a client is going away. The server
// updates its Connections object of this.
//
///////////////////////////////////////////////////////////////////
public void ClientQuit (int client_id, int password)
throws RemoteException, Exception {
try {
if (connect_obj.RemoveClient(client_id, password)) {
Print("Client "+client_id+" unregistered");
SendConnectionsToDemon(connect_obj);
}
else {
Print("Client "+client_id+" tried to unregister");
}
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
}
///////////////////////////////////////////////////////////////////
//
// DemonQuit - tells the server the demon is going away. The server
// updates its Connections object.
//
///////////////////////////////////////////////////////////////////
public void DemonQuit (int password)
throws RemoteException, Exception {
try {
if (connect_obj.RemoveDemon(DEMON_ID, password)) {
Print("Demon unregistered");
}
else {
Print("Demon tried to unregister");
}
}
catch (Exception e) {
my_engine.Error(e);
throw (e);
}
}
///////////////////////////////////////////////////////////////////
//
// SendMapAll - invoked internally. It gets the full Map as a
// parameter and sends this map to all clients, and the demon.
//
///////////////////////////////////////////////////////////////////
public void SendMapAll(Map m)
throws RemoteException, Exception {
// send maps to clients, then demon(s)
int num_exp = connect_obj.GetNumClients();
for (int i=0; i<num_exp; ++i) {
SendMapClient(m, i);
}
num_exp = connect_obj.GetNumDemons();
for (int i=0; i<num_exp; ++i) {
SendMapDemon(m, i);
}
}
///////////////////////////////////////////////////////////////////
//
// SendMapClient - invoked by ServerEngine. It gets the full Map and
// the number of a client to send this map to. An appropriate call is
// made to ClientRMI.
//
///////////////////////////////////////////////////////////////////
public int SendMapClient(Map m, int client_id)
throws Exception, RemoteException {
ClientRMIIface client_iface;
if (connect_obj.GetClientConnStatus(client_id)) {
client_iface = connect_obj.GetClientIface(client_id);
client_iface.ReceiveMap (m);
return(1);
}
else {
return(0);
}
}
///////////////////////////////////////////////////////////////////
//
// SendMapDemon - invoked by ServerEngine. It gets the full Map and
// sends it to the demon (via DemonRMI).
//
///////////////////////////////////////////////////////////////////
public int SendMapDemon(Map m, int demon_id)
throws RemoteException, Exception {
DemonRMIIface demon_iface;
if (connect_obj.GetDemonConnStatus(demon_id)) {
demon_iface = connect_obj.GetDemonIface(demon_id);
demon_iface.ReceiveMap (m);
return(1);
}
else {
return(0);
}
}
///////////////////////////////////////////////////////////////////
//
// SendMapDemon - invoked by ServerEngine. It gets the full Map and
// sends it to the main demon (via DemonRMI).
//
///////////////////////////////////////////////////////////////////
public int SendMapDemon(Map m)
throws RemoteException, Exception {
return(SendMapDemon(m, DEMON_ID));
}
///////////////////////////////////////////////////////////////////
//
// SendStatsClient - invoked by ServerEngine. It gets the Stats object
// and sends it to the specified client (via ClientRMI).
//
///////////////////////////////////////////////////////////////////
public int SendStatsClient(Stats stats, int client_id)
throws RemoteException, Exception {
if (connect_obj.GetClientConnStatus(client_id)) {
ClientRMIIface client_iface = connect_obj.GetClientIface(client_id);
client_iface.ReceiveStats (stats);
return(1);
}
else {
return(0);
}
}
///////////////////////////////////////////////////////////////////
//
// SendStatsDemon - invoked by ServerEngine. It gets the Stats object
// and sends it to the demon (via DemonRMI).
//
///////////////////////////////////////////////////////////////////
public int SendStatsDemon(Stats stats)
throws Exception, RemoteException {
if (connect_obj.GetDemonConnStatus(DEMON_ID)) {
DemonRMIIface demon_iface = connect_obj.GetDemonIface(DEMON_ID);
demon_iface.ReceiveStats (stats);
return(1);
}
else {
return(0);
}
}
///////////////////////////////////////////////////////////////////
//
// RunEnded - This method exists for the serverengine to notify
// the ServerRMI when the simulation has ended and last maps
// have been sent out.
//
///////////////////////////////////////////////////////////////////
public void RunEnded ()
throws Exception, RemoteException {
// just in case, set everybody's submission to false
connect_obj.SetAllSubmitFalse();
sim_state = SIM_CHOOSEMODE;
SendStateToDemon(sim_state);
SendConnectionsToDemon(connect_obj);
}
///////////////////////////////////////////////////////////////////
//
// SendConnectionsToDemon - sends the connection object
// explicitly to the demon.
//
///////////////////////////////////////////////////////////////////
public void SendConnectionsToDemon(Connections obj)
throws Exception, RemoteException {
int num_demons = connect_obj.GetNumDemons();
for (int i=0; i<num_demons; ++i) {
if (connect_obj.GetDemonConnStatus(i)) {
DemonRMIIface demon_rmi = connect_obj.GetDemonIface(i);
demon_rmi.ReceiveClientConnectStatus(obj);
}
}
}
///////////////////////////////////////////////////////////////////
//
// SendStateToDemon - sends the state of the simulation explicitly
// to the demon. This is done either on registration or on state
// change.
//
///////////////////////////////////////////////////////////////////
private void SendStateToDemon (int state)
throws RemoteException, Exception {
int num_demons = connect_obj.GetNumDemons();
for (int i=0; i<num_demons; ++i) {
if (connect_obj.GetDemonConnStatus(i)) {
DemonRMIIface demon_iface = connect_obj.GetDemonIface(i);
demon_iface.ReceiveState (state);
}
}
}
///////////////////////////////////////////////////////////////////
//
// Print - ServerRMI's own method, receiving a string from within
// ServerRMI, and in turn hands it off to ClientEngine for display.
//
///////////////////////////////////////////////////////////////////
private void Print (String s) {
my_engine.PrintMessage("\tRMI: "+s);
}
}
////////////////////////////////////////////////////////////////////////////