package edu.vt.marian.uip; import java.io.*; import java.net.*; import java.util.*; import edu.vt.marian.common.*; /** class name: server_uip_receiver_table class description: this class is responsible to create, delete and manage a number of server_uip_receivers, it's responsible to pass rpc_functions to them to pass to corresponding client_uips, it's also responsible for receiving rpc_functions received by them from client_uips.

uses the services of class(es): designer(s): Jianxin Zhao (jxzhao@csgrad.cs.vt.edu) implementator(s): finished time: known bugs: JDK version: 1.1.5 side effects: */ public class server_uip_receiver_table { /** this is just used for debugging */ Debug debug; /** this is the object which created this object */ private server_uip_thread sut; /** this vector contains all the receivers */ private Vector receivers; /** this number defines the upper limit of the receivers vector */ private int max_client_number; /** these two variables are used to guarantee that all the receivers have uniq id */ private int max_client_id; private boolean id_wrap_flag; /** this thread is used to clean receivers with bad status from time to time */ private server_uip_receiver_manage surm; /** this object is used to do the synchronization control of the receiver vector */ private ReaderWriterMutex rwm; /** possible return values of methods */ public final static int OK = 0; public final static int NULL_SOCKET = 1; public final static int TEABLE_OVERFLOW = 2; public final static int INVALID_ID = 3; public final static int PASSING_FUNCTION_FAILED = 4; public final static int RECEIVER_NOT_FOUND = 5; public final static int NULL_FUNCTION = 6; public final static int PROCESS_CALL_BACK_FAILED = 7; public final static int NULL_MESSAGE = 8; /** this is the default max client number */ private final static int DEFAULT_MAX_CLIENT_NUMBER = 100; /** method description: this constructor will create a server_uip_receiver _table object based on teh information in the parameters

uses the services of class(es): input parameter(s): sut -- the server_uip_thread which created this object max_client_number -- specifies at most how many server_uip_receivers are allowed in this object debug -- used for debugging output parameter(s): none return value: none synchronization consideration: none */ public server_uip_receiver_table(server_uip_thread sut, int max_client_number, Debug debug) { // initialize data members init(); this.debug = debug; // implementation required if (sut == null) { debug.dumpTrace("class server_uip_receiver_table, constructor, parameter server_uip_thread is null"); return; } this.sut = sut; this.max_client_number = max_client_number; rwm = new ReaderWriterMutex(debug); surm = new server_uip_receiver_manage(this, debug); surm.start(); } /** method description: this method will create a new server_uip_receiver based on the information in the parameters

uses the services of class(es): input parameter(s): s -- the socket used to communicate with the client_uip version -- specifies how to pass rpc_functions to and receive rpc_functions from the client_uip output parameter(s): none return value: 0 -- the server_uip_receiver has been created successfully other -- synchronization consideration: this is a writer method since it will modify the receiver table */ public int add_receiver(Socket s, int version) { // implementation required if (s == null) { debug.dumpTrace("class server_uip_receiver_table, method add_receiver, parameter socket is null"); return NULL_SOCKET; } // create a thread to do the real stuff to avoid deadlock add_receiver_thread art = new add_receiver_thread(this, s, version, debug); art.start(); return OK; } /** method description: this method will create a new server_uip_receiver based on the information in the parameters

uses the services of class(es): input parameter(s): s -- the socket used to communicate with the client_uip version -- specifies how to pass rpc_functions to and receive rpc_functions from the client_uip output parameter(s): none return value: 0 -- the server_uip_receiver has been created successfully other -- synchronization consideration: this is a writer method since it will modify the receiver table */ public int add_receiver_by_thread(Socket s, int version) { rwm.writer_enter(); if (receivers.size() >= max_client_number) { rwm.writer_exit(); debug.dumpTrace("class server_uip_receiver, method add_receiver_by_thread, upper limit has been reached"); return TEABLE_OVERFLOW; } if (! id_wrap_flag) { // id has not been wrapped back server_uip_receiver sur = new server_uip_receiver(this, max_client_id, s, version, debug); max_client_id ++; if (max_client_id == Integer.MAX_VALUE) { // we reached the upper limit, should wrap back the // next time max_client_id = 0; id_wrap_flag = true; } receivers.addElement(sur); rwm.writer_exit(); return OK; } // id has been wrapped back, need to find an unused one for (int i = 0; i < receivers.size(); i++) { server_uip_receiver sur = (server_uip_receiver) receivers.elementAt(i); if (sur.get_client_id() != i) { // we find an unused id here server_uip_receiver sur1 = new server_uip_receiver(this, i, s, version, debug); receivers.insertElementAt(sur1, i); rwm.writer_exit(); return OK; } } // it must be the last element server_uip_receiver sur1 = new server_uip_receiver(this, receivers.size(), s, version, debug); receivers.addElement(sur1); rwm.writer_exit(); return OK; } /** method description: this method will delete those server_uip_receivers whose status is not "ok"

uses the services of class(es): input parameter(s): none output parameter(s): none return value: non negative integer -- specifies how many server_uip_receivers have been deleted other -- synchronization consideration: this is a writer method since it will modify the receiver table */ public int clean() { // implementation required int number_deleted = 0; rwm.writer_enter(); server_uip_receiver sur = null; // hopefully from high to low can increase speed a little // bit for (int i = receivers.size() - 1; i >= 0; i--) { sur = (server_uip_receiver) receivers.elementAt(i); if (sur.get_status() != sur.OK) { // this is a "bad" receiver, delete it sur.exit("bad status"); receivers.removeElementAt(i); number_deleted ++; } } // return after delete all the bad receivers rwm.writer_exit(); return number_deleted; } /** method description: this method will send the function to the corresponding server_uip_receiver to pass to the client_uip

uses the services of class(es): input parameter(s): client_id -- specifies which server_uip_receiver to pass the function to function -- the function which need to be passed output parameter(s): none return value: 0 -- the function has been passed correctly other -- synchronization consideration: this is a reader method since it will search the receiver table */ public int rpc_call(int client_id, rpc_function function) { debug.dumpTrace("server_uip_receiver_table.rpc_call(): function is " + function.get_name() + "()."); // implementation required if (client_id < 0) { debug.dumpTrace("class server_uip_receiver_table, method rpc_call, parameter client_id less than 0"); return INVALID_ID; } rwm.reader_enter(); server_uip_receiver sur = null; for (int i = 0; i < receivers.size(); i++) { sur = (server_uip_receiver) receivers.elementAt(i); if (sur.get_client_id() == client_id) { // we find the receiver to pass the function if (sur.rpc_call(function) != sur.OK) { rwm.reader_exit(); return PASSING_FUNCTION_FAILED; } // everything is ok here rwm.reader_exit(); return OK; } } // something must be wrong since we couldn't find a receiver // with the same id rwm.reader_exit(); debug.dumpTrace("class server_uip_receiver_table, method rpc_call, couldn't find corresponding receiver"); return RECEIVER_NOT_FOUND; } /** method description: this method will let this object exit smoothly

uses the services of class(es): input parameter(s): consideration -- specifies the situation under which this method is called output parameter(s): none return value: 0 -- the exit is smooth other -- synchronization consideration: this is a writer method since it will modify the receiver table (delete all the elements) */ public int exit(String condition) { // implementation required rwm.writer_enter(); // first stop the thread which is responsible to clean bad // receivers from time to time // note: to avoid deadlock this statement and the above one // must in this order surm.stop(); server_uip_receiver sur = null; // scan the vector from high to low to increase speed for (int i = receivers.size() - 1; i >= 0; i--) { sur = (server_uip_receiver) receivers.elementAt(i); sur.exit(condition); receivers.removeElementAt(i); } rwm.writer_exit(); return OK; } /** method description: this method will process the function received by one of it's server_uip_receivers a from client_uip

uses the services of class(es): input parameter(s): client_id -- specifies which server_uip_receiver received this function client_desc -- a description of the client_uip which sent this function output parameter(s): none return value: 0 -- the function has been processed successfully other -- synchronization consideration: none */ public int process_call_back_from_server_uip_receiver( int client_id, String client_desc, rpc_function function) { if (client_desc == null) { debug.dumpTrace("class server_uip_receiver_table, method process_call_back_from_server_uip_receiver, parameter client_desc is null"); } debug.dumpTrace("server_uip_receiver_table.process_call_back_from_server_uip_receiver(): function is " + function.get_name() + "()."); ////DEBUG // just pass them to server_uip_thread to process if (sut.process_call_back_from_server_uip_receiver_table( client_id, client_desc, function) != sut.OK) { return PROCESS_CALL_BACK_FAILED; } // everything is fine here return OK; } /** method description: this method will process the log data sent from a server_uip_receiver

uses the services of class(es): input parameter(s): client_id -- indicate which receiver send the message message -- the message sent from the server_uip_receiver output parameter(s): none return value: 0 -- the message has been processed successfully other -- synchronization consideration: none */ public int log_data_from_server_uip_receiver(int client_id, String message) { // implementation required if (message == null) { debug.dumpTrace("class server_uip_receiver_table, method log_data_from_server_uip, parameter message is null"); return NULL_MESSAGE; } // add the client id to the beginning of the message message = "client: " + Integer.toString(client_id) + "\n" + message; sut.log_data_from_server_uip_receiver_table(message); return OK; } /** method description: this method will initialize the data members of this object

uses the services of class(es): input parameter(s): none output parameter(s): none return value: none synchronization consideration: none */ private void init() { debug = null; sut = null; surm = null; rwm = null; max_client_number = DEFAULT_MAX_CLIENT_NUMBER; max_client_id = 0; id_wrap_flag = false; receivers = new Vector(); } }