package edu.vt.marian.uip; import java.io.*; import java.net.*; import java.util.*; import edu.vt.marian.common.*; /** class name: client_uip class description: this class is responsible to send and receive rpc functions from the server. uses the services of class(es): debug, rpc_function, uip_log_manager, call_back_processor, uip_server client_uip_thread designer(s): Jianxin Zhao (jxzhao@csgrad.cs.vt.edu) implementator(s): Xuelei Sun (xusun@csgrad.cs.vt.edu) finished time: December 8, 1998 known bugs: JDK version: 1.1.5 side effects: */ public class client_uip extends Thread { //possible return values public final static int OK = 0; //success public final static int RPC_CALL_NULL_FUNCTION = -1; //null rpc function public final static int RPC_CALL_INVALID_FUNCTION = -2; //invalid rpc function public final static int RPC_CALL_STATUS_NOT_OK = -3; //client uip thread status not ok public final static int RPC_CALL_NOT_SUCCESSFUL = -4; //client uip thread pass function failed public final static int PROCESS_CALL_BACK_NULL_FUNCTION = -5; //null rpc function public final static int PROCESS_CALL_BACK_INVALID_FUNCTION = -6; //invalid rpc function public final static int PROCESS_CALL_BACK_FAILED = -7; //call_back_processor process call back failed // possible status of client_uip_thread public final static int NULL_PARAMETER = 1; public final static int INVALID_VERSION = 2; public final static int ERROR_CREAT_LISTEN_SOCKET = 3; public final static int ERROR_SET_SOCKET_TIME_OUT = 4; public final static int ERROR_CREATE_OUTBOUND_SOCKET = 5; public final static int NEW_SESSION_NOT_SENT = 6; public final static int LISTEN_TIME_OUT = 7; public final static int LISTEN_FAILED = 8; public final static int CREATE_OUTBOUND_STREAM_FAILED = 9; public final static int SEND_FUNCTION_FAILED = 10; public final static int REPLY_NOT_ACK = 11; public final static int RECEIVE_ACK_ERROR = 12; public final static int TIME_OUT_WAITING_ACK = 13; public final static int ERROR_READ_FUNCTION_FROM_SERVER = 14; public final static int SERVER_DISCONNECT = 15; public final static int EXIT = 16; public final static int NULL_FUNCTION = -1; public final static int INVALID_FUNCTION = -2; public final static int ERROR_WRITE_ACK = -3; /** This is for debugging */ Debug debug; /** This is the log manager handling the log file */ private uip_log_manager ulm; /** This is the call back processor to do the actually rpc function call */ private call_back_processor cbp; /** This is the uip server contains the server information */ private uip_server us; /** This is the client_uip_thread which actually handling the function passing */ private client_uip_thread cut; /** This is the choice for the call in method. */ private int call_in_method; /** This is the choice for the call back method. */ private int call_back_method; /** This is the flag for the existance of the log manager */ private boolean log_manager_exist; /** This is the version of this object */ private int version; /** These are two function call process methods */ private final static int THREAD_CALL = 0; //create a thread to handling the call process private final static int DIRECT_CALL = 1; //directly call the class method to handling the process /** method description: this constructor will create a client_uip object based on the information contained in the directory it assumes call back processor can process functions it receives from the server uses the services of class(es): Debug, call_back_processor, uip_log_manager, uip_server, client_uip_thread input parameter(s): String dr, the directory name call_back_processor cbp, the call back processor Debug debug, debug object output parameter(s): none return value: none synchronization consideration: none */ public client_uip (String dr, call_back_processor cbp, Debug debug) { this.debug = debug; //initialize data memebers init(); if (cbp == null) { debug.dumpTrace("client_uip.[constructor from directory]: null call back processor"); return; } this.cbp = cbp; if (dr == null) { debug.dumpTrace("client_uip.[constructor from directory]: null or empty directory"); return; } //the config file name including the path String config_file_name = dr + "config"; //variables for temporary info read from the config file String hostname = null; int port_number = 0; BufferedReader in_config_file = null; try { //variables for the config file reading String line = null; StringTokenizer token_line = null; String stoken = null; String s1 = null; in_config_file = new BufferedReader(new FileReader(config_file_name)); line = in_config_file.readLine(); while (line != null) { token_line = new StringTokenizer(line," ",false); if (token_line.countTokens() > 1) //in case an empty line is encountered { //ignore empty lines and lines with only one token stoken = token_line.nextToken(); if (!stoken.startsWith("#")) //ignore comments(begin with "#") { //for hostname if (stoken.equals("hostname")) { s1 = token_line.nextToken(); hostname = s1; } //for port number else if (stoken.equals("portnumber")) { s1 = token_line.nextToken(); try { port_number = Integer.parseInt(s1); if ((port_number < 0) || (port_number > 65535)) { debug.dumpTrace("client_uip.[constructor from directory]: port_number less than 0"); in_config_file.close(); return; } } catch (Exception e) { debug.dumpTrace("client_uip.[constructor from directory]: port number is not an integer"); in_config_file.close(); return; } }//end portnumber //for call in method else if (stoken.equals("call_in_method")) { s1 = token_line.nextToken(); if (s1.equals("DIRECT_CALL")) { call_in_method = DIRECT_CALL; } else if (s1.equals("THREAD_CALL")) { call_in_method = THREAD_CALL; } else { debug.dumpTrace("client_uip.[constructor from directory]: invalid call_in_method"); call_in_method = THREAD_CALL; } }//end call in method //for call back method else if (stoken.equals("call_back_method")) { s1 = token_line.nextToken(); if (s1.equals("DIRECT_CALL")) { call_back_method = DIRECT_CALL; } else if (s1.equals("THREAD_CALL")) { call_back_method = THREAD_CALL; } else { debug.dumpTrace("client_uip.[constructor from directory]: invalid call_back_method"); call_back_method = THREAD_CALL; } }//end call back method //for version else if (stoken.equals("version")) { s1 = token_line.nextToken(); try { version = Integer.parseInt(s1); if ((version != 1) && (version !=2)) { debug.dumpTrace("client_uip.[constructor from directory]: invalid version" + Integer.toString(version)); version = 1; } } catch (Exception e) { debug.dumpTrace("client_uip.[constructor from directory]: version is not an integer"); version = 1; } }//end version }//end if not comments line } //end if token count > 1 line = in_config_file.readLine(); } //end while not null line in_config_file.close(); }//end try open file catch (IOException e) { debug.dumpTrace("client_uip.[constructor from directory]: New FileInputStream for config file '" + config_file_name + "' failed: " + e.getMessage()); try { in_config_file.close(); } catch (Exception e1) { return; } return; } //set the log manager String log_dir_name = dr + "log_manager" + File.separator; ulm = new uip_log_manager(log_dir_name, debug); log_manager_exist = true; //create the uip server us = new uip_server(hostname, port_number, null, null, debug); //create client uip thread cut = new client_uip_thread(this, us, version, debug); // start this own thread to check the status of the client_uip_thread // from time to time, reconnect to server if necessary this.start(); }//end of the constructor from the directory /** method description: this constructor will create a client_uip object based on the uip server, version, call back processor that passed as parameter uses the services of class(es): Debug, call_back_processor, uip_log_manager, uip_server, client_uip_thread input parameter(s): uip_server us, the uip server contains the server information int version, the version number, 1 is hardcoded, 2 is flexible call_back_processor cbp, call back processor handling the call back process Debug debug, debug object output parameter(s): none return value: none synchronization consideration: none */ public client_uip(uip_server us, int version, call_back_processor cbp, Debug debug) { //set the debug this.debug = debug; //initialize the memeber variables init(); //set the us and cbp if (us == null) { debug.dumpTrace("client_uip.[constructor 2]: null uip server"); return; } this.us = us; if (cbp == null) { debug.dumpTrace("client_uip.[constructor 2]: null call back processor"); return; } this.cbp = cbp; this.version = version; //check version if ( (version != 1) && (version != 2) ) { debug.dumpTrace("client_uip.[constructor 2]: version number other than 1 or 2"); return; } //create the client uip thread cut = new client_uip_thread (this, us, version, debug); // start this own thread to check the status of the client_uip_thread // from time to time, reconnect to server if necessary this.start(); } /** method description: this method provide smooth exit for the client connection uses the services of class(es): Debug, uip_log_manager, client_uip_thread input parameter(s): String condition, condition to call the exit output parameter(s): none return value: OK: exit successfully synchronization consideration: none */ public int exit(String condition) { //check exit condition if (condition == null) { debug.dumpTrace("client_uip.exit(): null condition parameter"); } // stop this own thread used to check client_uip_thread status this.stop(); //exit the client uip thread cut.exit(condition); //exit uip log manager if (log_manager_exist) { ulm.exit(condition); } return OK; } /** method description: this method will check the status of the client_uip_thread from time to time, and reconnect to server if necessary input parameter(s): none output parameter(s): none return value: none synchronization consideration: none */ public void run() { while (true) { try { sleep(60000); } catch (Exception e) { debug.dumpTrace("client_uip.run(): error while sleeping."); } // check the status of the client_uip_thread and // perform actions if necessary if (cut.get_status() != client_uip_thread.OK) { // some problems have happened in the connection // between this client_uip and corresponding server_uip // try to reconnect cut.exit("exit under bad status, try to reconnect later"); cut = new client_uip_thread(this, us, version, debug); } } // end -- while } /** method description: this method return the status of the client uip thread uses the services of class(es): client_uip_thread input parameter(s): none output parameter(s): none return value: int status of client uip thread synchronization consideration: none */ public int get_status() { return cut.get_status(); } /** method description: this method pass rpc function to client uip thread to pass it through net uses the services of class(es): Debug, uip_log_manager, client_uip_thread input parameter(s): rpc_function rf, rpc function to pass output parameter(s): none return value: int OK: call successfully RPC_CALL_NULL_FUNCTION: null rpc function RPC_CALL_INVALID_FUNCTION: invalid rpc function RPC_CALL_STATUS_NOT_OK: client uip thread status not ok RPC_CALL_NOT_SUCCESSFUL: client uip thread pass function failed synchronization consideration: none */ public int rpc_call (rpc_function rf) { //error check the function if (rf == null) { debug.dumpTrace("client_uip.rpc_call(): null rpc function"); return RPC_CALL_NULL_FUNCTION; } if (!rf.is_valid()) { debug.dumpTrace("client_uip.rpc_call(): invalid rpc function"); return RPC_CALL_INVALID_FUNCTION; } //do the log if (log_manager_exist) { String message = new String("function received from system"); ulm.log_function_passed("client_uip", message, rf); } //creat thread to handling the call if (call_in_method == THREAD_CALL ) { client_uip_call_in_thread cucit = new client_uip_call_in_thread (rf, cut, debug); cucit.start(); return OK; } //call client_uip_thread method to pass the function if (cut.get_status()!= cut.OK) { debug.dumpTrace("client_uip.rpc_call(): client_uip_thread is not ok when called"); return RPC_CALL_STATUS_NOT_OK; } if (cut.rpc_call(rf) != cut.OK) { debug.dumpTrace("client_uip.rpc_call(): client_uip_thread rpc call failed"); return RPC_CALL_NOT_SUCCESSFUL; } return OK; } /** method description: this method return the uip server description uses the services of class(es): uip_server input parameter(s): none output parameter(s): none return value: uip_server the copy of member variable us synchronization consideration: none */ public uip_server get_server () { return us; } /** method description: this method pass the call back process to the call back processor uses the services of class(es): Debug, uip_log_manager, client_uip_call_back_thread, call_back_processor, input parameter(s): rpc_function rf the function to pass output parameter(s): none return value: int PROCESS_CALL_BACK_NULL_FUNCTION: null rpc function PROCESS_CALL_BACK_INVALID_FUNCTION: invalid rpc function PROCESS_CALL_BACK_FAILED: call_back_processor process call back failed OK successfully synchronization consideration: none */ public int process_call_back_from_client_uip_thread (rpc_function rf) { //do the log if (log_manager_exist) { String message = new String("function received from server"); ulm.log_function_passed("client_uip", message, rf); } //creat thread to handling the call if (call_back_method == THREAD_CALL ) { client_uip_call_back_thread cucbt = new client_uip_call_back_thread(this, rf, cbp, debug); cucbt.start(); return OK; } //call call back process method to process the call back if (cbp.process_call_back(this, rf) != cbp.OK) { debug.dumpTrace("client_uip.process_call_back_from_client_uip_thread(): process call back failed"); return PROCESS_CALL_BACK_FAILED; } return OK; } /** method description: this method initialize the member variables uses the services of class(es): none input parameter(s): none output parameter(s): none return value: none synchronization consideration: none */ private void init() { ulm = null; cbp = null; us = null; // just create an invalid client uip thread cut = new client_uip_thread(null, null, 1, debug); call_in_method = THREAD_CALL; call_back_method = THREAD_CALL; version = 2; log_manager_exist = false; } }