package edu.vt.marian.uip; import java.io.*; import java.net.*; import java.util.*; import edu.vt.marian.common.*; /** class name: server_uip class description: this class is responsible to communicate with a number of client_uips, send rpc_functions to and receive rpc_functions from them
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 { /** this is just used for debugging */ Debug debug; /** this is the thread which is in charge of finding new client connections, passing functions to client and recieveing functions from them */ private server_uip_thread sut; /** this is the object used to write logs about the server uip */ private uip_log_manager ulm; /** when a functuion uis received from a client uip, it will be passed to this object to process */ private call_back_processor cbp; /** this flag indicate when received a function to pass to a client uip, this object will call the sut's rpc_call() method directly or create a thread to call it */ private int call_in_method; /** this flag indicate when received a function to pass back to call back processor to process uip, this object will call the cbp's process_call_back() method directly or create a thread to call it */ private int call_back_method; /** these are possible values of the above two flags */ private final static int DIRECT_CALL = 0; private final static int THREAD_CALL = 1; /** this is the version of this server uip, currently only 1 and 2 are supported, different version will use different mechanism to send rpc_functions to socket */ private int version; /** this is the well known port number of this server uip, client uip will try to connect to this port */ private int port_number; /** this is the default port number */ private final static int DEFAULT_PORT = 8000; /** this is the default max client number */ private final static int DEFAULT_MAX_CLIENT_NUMBER = 100; /** this number indicate at most ow many client uips this server uip will support at the same time */ private int max_client_number; /** those are the possible return values of methods */ public final static int OK = 0; public final static int NULL_FUNCTION = 1; public final static int INVALID_FUNCTION = 2; public final static int STATUS_IS_EXIT = 3; public final static int PASSING_FUNCTION_FAILED = 4; public final static int PROCESS_CALL_BACK_FAILED = 5; public final static int OBJECT_NOT_VALID = 1000; /** method description: this constructor will create a server_uip object based on the information in th specified directory, when it receives a rpc_function from one of it's corresponding client_uips it will pass the function to the parameter cbp to process
uses the services of class(es): input parameter(s): dir --- this directory contains the configuration information of the server_uip object cbp --- this parameter is supposed to be able to process the functions received from one of the client_uips using the method process_call_back(client_uip cu, rpc_function, rf) debug -- used for debugging output parameter(s): none return value: none synchronization consideration: none */ public server_uip(String dir, call_back_processor cbp, Debug debug) { // initialize data members init(); this.debug = debug; // implementation required if (cbp == null) { debug.dumpTrace("server_uip.[constructor 1]: call_back_processor is null"); return; } this.cbp = cbp; if (dir == null) { debug.dumpTrace("server_uip.[constructor 1]: parameter dir is null"); return; } // input parameters are valid here 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; //variables for temporary info read from the config file in_config_file = new BufferedReader(new FileReader(dir + "config")); 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 version if (stoken.equals("version")) { s1 = token_line.nextToken(); try { version = Integer.parseInt(s1); if ((version != 1) && (version != 2)) { // only 1 and 2 are supported currently debug.dumpTrace("server_uip.[constructor 1]: invalid version read out from config file, version set to 1"); version = 1; } } catch (Exception e) { debug.dumpTrace("server_uip.[constructor 1]: version should be an integer"); version = 1; } } //for port number else if (stoken.equals("port_number")) { s1 = token_line.nextToken(); try { port_number = Integer.parseInt(s1); if ( (port_number <= 0) || (port_number > 65535) ) { debug.dumpTrace("server_uip.[constructor 1]: invalid port number" + Integer.toString(port_number)); port_number = DEFAULT_PORT; } } catch (Exception e) { debug.dumpTrace("server_uip.[constructor 1]: port number is not an integer"); port_number = DEFAULT_PORT; } }//end port_number //for max_client_number else if (stoken.equals("max_client_number")) { s1 = token_line.nextToken(); try { max_client_number = Integer.parseInt(s1); if (max_client_number <= 0) { debug.dumpTrace("server_uip.[constructor 1]: invalid max client number" + Integer.toString(max_client_number)); max_client_number = DEFAULT_MAX_CLIENT_NUMBER; } } catch (Exception e) { debug.dumpTrace("server_uip.[constructor 1]: max client number is not an integer"); max_client_number = DEFAULT_MAX_CLIENT_NUMBER; } }//end max_client_number //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("server_uip.[constructor 1]: 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("server_uip.[constructor 1]: invalid call_back_method"); call_back_method = THREAD_CALL; } }//end call_back_method } // end -- start with "#" } //end if token count > 1 line = in_config_file.readLine(); } //end while not null line in_config_file.close(); }//end try open file catch (Exception e) { debug.dumpTrace("server_uip.[constructor 1]: error reading config file."); try { in_config_file.close(); } catch (Exception e1) { } } // create uip log manager and server uip thread ulm = new uip_log_manager(dir + "log_manager" + File.separator, debug); sut = new server_uip_thread(this, version, port_number, max_client_number, debug); } /** method description: this method will return the current status of this object uses the services of class(es): none input parameter(s): none output parameter(s): none return value: 0 -- everything is fine other -- synchronization consideration: none */ public int get_status() { if (! is_valid()) { // constructor not completed, can't execute this method debug.dumpTrace("class server_uip, method get_status, cann't execute since constructor is not completed successfully"); return OBJECT_NOT_VALID; } // implementation required return sut.get_status(); } /** method description: this method will send the function to the specified client_uip
uses the services of class(es): rpc_function input parameter(s): function -- the function which need to be sent to the client_uip client_id -- specifies which client_uip to send the function output parameter(s): none return value: 0 -- the function has been passed to the server correctly other -- synchronization consideration: none */ public int rpc_call(int client_id, rpc_function function) { if (! is_valid()) { // constructor not completed, can't execute this method debug.dumpTrace("server_uip.rpc_call(): can't execute since constructor is not completed successfully"); return OBJECT_NOT_VALID; } // implementation required if (function == null) { debug.dumpTrace("server_uip.rpc_call(): parameter function is null"); return NULL_FUNCTION; } if (! function.is_valid()) { debug.dumpTrace("server_uip.rpc_call(): parameter function is not valid"); return INVALID_FUNCTION; } // now we have a valid function, first write log ulm.log_function_passed("server_uip", "function received from system for client: " + Integer.toString(client_id), function); // pass the function according to call_in_method if (call_in_method == THREAD_CALL) { // create a thread to pass it server_uip_call_in_thread sucit = new server_uip_call_in_thread(client_id, function, sut, debug); sucit.start(); return OK; } // pass it directly to server uip thread if (sut.get_status() == sut.EXIT) { // server uip thread has exited debug.dumpTrace("server_uip.rpc_call(): function received after exit"); return STATUS_IS_EXIT; } if (sut.rpc_call(client_id, function) == sut.OK) { return OK; } return PASSING_FUNCTION_FAILED; } /** method description: this method will let this object exit smoothly
uses the services of class(es): input parameter(s): condition -- specifies under which situation this method is called output parameter(s): none return value: 0 -- the object exited smoothly other -- synchronization consideration: none */ public int exit(String condition) { if (! is_valid()) { // constructor not completed, can't execute this method debug.dumpTrace("server_uip.exit(): can't execute since constructor is not completed successfully"); return OBJECT_NOT_VALID; } // implementation required if (condition == null) { debug.dumpTrace("server_uip.exit(): parameter condition is null"); } debug.dumpTrace("server_uip.exit(): before exit server uip thread"); // exit server uip thread and uip log manager sut.exit(condition); debug.dumpTrace("server_uip.exit(): after exit server uip thread"); ulm.exit(condition); debug.dumpTrace("v method exit after exit uip log manager"); return OK; } /** method description: this method will process the function received by it's server_uip_thread from one of it's corresponding client_uips
uses the services of class(es): input parameter(s): client_id -- specifies which client_uip this functiuon come from client_desc -- a description of the client_uip rpc_function -- the function sent by the client_uip 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_thread(int client_id, String client_desc, rpc_function function) { //debug.dumpTrace("server_uip.process_call_back_from_server_uip_thread(): at the beginning"); if (! is_valid()) { // constructor not completed, can't execute this method debug.dumpTrace("server_uip.process_call_back_from_server_uip_thread(): can't execute since constructor is not completed successfully"); return OBJECT_NOT_VALID; } // log the function first ulm.log_function_passed("server_uip", "function recieved from client: " + Integer.toString(client_id) + " " + client_desc, function); // pass the function according to call_back_method if (call_back_method == THREAD_CALL) { //debug.dumpTrace("server_uip.process_call_back_from_server_uip_thread(): before create and start the call back thread"); server_uip_call_back_thread sucbt = new server_uip_call_back_thread(client_id, function, cbp, debug); sucbt.start(); //debug.dumpTrace("server_uip.process_call_back_from_server_uip_thread(): after create and start the call back thread"); return OK; } // direct call if (cbp.process_call_back(client_id, function) == cbp.OK) { return OK; } return PROCESS_CALL_BACK_FAILED; } /** method description: this method will log the data send from it's server_uip_thread
uses the services of class(es): input parameter(s): message -- the message sent by server_uip_thread for logging output parameter(s): none return value: 0 -- the message has been logged successfully other -- synchronization consideration: none */ public int log_data_from_server_uip_thread(String message) { if (! is_valid()) { // constructor not completed, can't execute this method debug.dumpTrace("server_uip.log_data_from_server_uip_thread(): can't execute since constructor is not completed successfully"); return OBJECT_NOT_VALID; } // implementation required if (message == null) { debug.dumpTrace("server_uip.log_data_from_server_uip_thread(): parameter message is null"); } ulm.write_log("server_uip", message); return OK; } /** method description: this method will tell whether or not the constructor of this object has been executed successfully
uses the services of class(es): input parameter(s): none output parameter(s): none return value: true -- the constructor has been executed successfully false -- something bad happened in constructor synchronization consideration: none */ public boolean is_valid() { if ((ulm == null) || (sut == null)) { return false; } return true; } /** 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; version = 1; call_in_method = THREAD_CALL; call_back_method = THREAD_CALL; max_client_number = DEFAULT_MAX_CLIENT_NUMBER; port_number = DEFAULT_PORT; } }