package edu.vt.marian.server; import java.io.*; import java.net.*; import java.lang.*; import java.util.*; import edu.vt.marian.common.*; import edu.vt.marian.uip.*; /** class name: session class description: this class represents a session in the system, currently a session represent a user's activity in a period of time. uses the services of class(es): designer(s): Jianxin Zhao (jxzhao@csgrad.cs.vt.edu) implementator(s): Ning Chai (nchai@csgrad.cs.vt.edu) finished time: Nov 26th, 1998 known bugs: JDK version: 1.1.5 side effects: */ public class session { public final static int OK = 0; public final static int CLIENT_QUEUE_SIZE_NOT_EQUAL_0 = 1; public final static int C_QUEUE_SIZE_NOT_EQUAL_0 = 2; public final static int CLIENT_AND_C_QUEUES_SIZE_NOT_EQUAL_0 = 3; public final static int PROCESS_CALL_FROM_SESSION_TO_C_FAILED = 4; public final static int PROCESS_CALL_FROM_CLIENT_FAILED = 5; public final static int PROCESS_CALL_FROM_C_FAILED = 6; public final static int NULL_RPC_FUNCTION = 7; public final static int NULL_PARAMETER = 8; public final static int INVALID_PARAMETER_TYPE = 9; public final static int PROCESS_FUNCTION_FROM_CLIENT_FAILED = 10; public final static int PROCESS_FUNCTION_FROM_C_FAILED = 11; public final static int NULL_RPC_FUNCTION_NAME = 12; public final static int PROCESS_ERROR_FOR_SESSION_MANAGER_FAILED = 13; public final static int PROCESS_SHOW_INFORMATION_1_FAILED = 14; public final static int CANNOT_FIND_QUERY = 15; public final static int PROCESS_CALL_FROM_SESSION_TO_CLIENT_FAILED = 16; public final static int INVALID_SESSION_ID = 17; public final static int INVALID_MAX_NUMBER_QUERIES = 18; public final static int QUERIES_OVERFLOW = 19; public final static int NULL_MESSAGE = 20; private Vector queries; private int id; private session_table st; private resource_manager rm; private long last_access_time; private session_execution se; private function_queue client_queue; private function_queue c_queue; private int max_number_queries; private String session_execution_file_name; private int max_client_functions; private int max_c_functions; /** this is just used for debugging */ Debug debug; /** method description: this constructor will create a session object, this session belongs to the specified session table, has the specified id and will use the specified resource manager, the directory/file contains all the configuration information for this session. uses the services of class(es): input parameter(s): st -- the session table this session belongs to session_id -- the id of this sesion, it's uniq in the session table file_name -- directory/file which contains all the configuration information of this session object rm -- this session will use this resource manager to log data and it also pass the resource manager to all the queries it created debug -- used for debugging output parameter(s): none return value: none synchronization: none */ public session(session_table st, int session_id, String dir_name, resource_manager rm, Debug debug) { BufferedReader in_file = null; String line = null; StringTokenizer token_line = null; String s; String s1; init(); this.debug = debug; this.st = st; if (st == null) { debug.dumpTrace("Class:session Method:constructor Session_table is null."); } set_id(session_id); this.rm = rm; if (rm == null) { debug.dumpTrace("Class:session Method:constructor Resource_manager is null."); } if ((dir_name == null) || dir_name.equals("")) { debug.dumpTrace("Class:session Method:constructor Dir_name is null or empty."); } try { in_file = new BufferedReader(new FileReader(dir_name.concat("config"))); line = in_file.readLine(); while (line != null) { token_line = new StringTokenizer(line," ",false); if (token_line.countTokens() > 1) { //ignore empty lines and lines with only one token if (!line.startsWith("#")) //Ignore comments(begin with "#") { s = token_line.nextToken(); if (s.equals("max_number_queries")) { s1 = token_line.nextToken(); try { max_number_queries = Integer.parseInt(s1); if (max_number_queries <= 0) { max_number_queries = 1; debug.dumpTrace("Class:session Method:constructor max_number_queries must be greater than 0."); } } catch (Exception e) { max_number_queries = 1; debug.dumpTrace("Class:session Method:constructor max_number_queries must be an integer."); } } if (s.equals("max_client_functions")) { s1 = token_line.nextToken(); try { max_client_functions = Integer.parseInt(s1); if (max_client_functions <= 0) { max_client_functions = 1; debug.dumpTrace("Class:session Method:constructor max_client_functions must be greater than 0."); } } catch (Exception e) { max_client_functions = 1; debug.dumpTrace("Class:session Method:constructor max_client_functions must be an integer."); } } if (s.equals("max_c_functions")) { s1 = token_line.nextToken(); try { max_c_functions = Integer.parseInt(s1); if (max_c_functions <= 0) { max_c_functions = 1; debug.dumpTrace("Class:session Method:constructor max_c_functions must be greater than 0."); } } catch (Exception e) { max_c_functions = 1; debug.dumpTrace("Class:session Method:constructor max_c_functions must be an integer."); } } if (s.equals("session_execution_file")) { session_execution_file_name = token_line.nextToken(); } } // end if (!line.startsWith("#")) } // end if (token_line.countTokens() > 1) line = in_file.readLine(); } // end while in_file.close(); } catch (IOException e) { debug.dumpTrace("Class:session Method:constructor File open error or get parameters error."); } client_queue = new function_queue(max_client_functions, debug); c_queue = new function_queue(max_c_functions, debug); if ((session_execution_file_name == null) || session_execution_file_name.equals("")) { se = new session_execution(this, debug); } else { se = new session_execution(dir_name.concat(session_execution_file_name), this, debug); } mark_access_time(); se.start(); return; } /** method description: this constructor will create a session object, this session belongs to the specified session table, has the specified id and will use the specified resource manager. uses the services of class(es): input parameter(s): st -- the session table this session belongs to session_id -- the id of this sesion, it's uniq in the session table rm -- this session will use this resource manager to log data and it also pass the resource manager to all the queries it created debug -- used for debugging output parameter(s): none return value: none synchronization: none */ public session(session_table st, int session_id, resource_manager rm, Debug debug) { init(); this.debug = debug; this.st = st; if (st == null) { debug.dumpTrace("Class:session Method:constructor Session_table is null."); } set_id(session_id); this.rm = rm; if (rm == null) { debug.dumpTrace("Class:session Method:constructor Resource_manager is null."); } client_queue = new function_queue(max_client_functions, debug); c_queue = new function_queue(max_c_functions, debug); se = new session_execution(this, debug); mark_access_time(); se.start(); return; } /** method description: this method will return the inactive time of this session object, this is the time interval between the last time a function is processed and the time this method is called. uses the services of class(es): input parameter(s): none output parameter(s): none return value: the inactive time of this object as a long integer, the unit is ms. synchronization: none */ public long get_inactive_time() { Date date = new Date(); return date.getTime()-last_access_time; } /** method description: this method will let the session object exit smoothly, release the resources it occupied and kill all the threads it created. uses the services of class(es): input parameter(s): condition -- specifies under what condition this method is called output parameter(s): none return value: OK -- the exit is smooth CLIENT_QUEUE_SIZE_NOT_EQUAL_0 -- client function queue length is not 0 C_QUEUE_SIZE_NOT_EQUAL_0 -- c function queue length is not 0 CLIENT_AND_C_QUEUES_SIZE_NOT_EQUAL_0 -- both function queue lengthes are not 0 synchronization: synchronized */ public synchronized int exit(String condition) { st.log_data_from_session(1,id,"exit under: "+condition); se.stop(); query query_obj = null; for (int i = queries.size() - 1; i >= 0; i--) { query_obj = (query)(queries.elementAt(i)); query_obj.exit(condition); queries.removeElementAt(i); } rpc_function rf = new rpc_function(debug); rf.set_name("close_session"); if (st.process_call_from_session_to_c(id, rf) == st.OK) { if (client_queue.get_number_functions() == 0) { if (c_queue.get_number_functions() == 0) { return OK; } else { return C_QUEUE_SIZE_NOT_EQUAL_0; } } else // client_queue.get_number_functions() != 0 { if (c_queue.get_number_functions() == 0) { return CLIENT_QUEUE_SIZE_NOT_EQUAL_0; } else { return CLIENT_AND_C_QUEUES_SIZE_NOT_EQUAL_0; } } } else // st.process_call_from_session_to_c(id, rf) != st.OK { return PROCESS_CALL_FROM_SESSION_TO_C_FAILED; } } /** method description: this method will process the function sent from client (currently webgate), in fact it just put the function into the corresponding queue object it created uses the services of class(es): input parameter(s): rf -- the rpc function need to be processed output parameter(s): none return value: OK -- the function has been processed correctly PROCESS_CALL_FROM_CLIENT_FAILED -- client function queue overflowed synchronization: none */ public int process_call_from_client(rpc_function rf) { mark_access_time(); if (client_queue.enter_function(rf) == client_queue.OK) { se.resume(); return OK; } return PROCESS_CALL_FROM_CLIENT_FAILED; } /** method description: this method will process the function sent from C/C++ marian server, in fact it just put the function into the corresponding function queue uses the services of class(es): input parameter(s): rf -- the rpc function need to be processed output parameter(s): none return value: OK -- the function has been processed correctly PROCESS_CALL_FROM_C_FAILED -- can not enter the function into the queue because the queue overflowed other -- synchronization: none */ public int process_call_from_c(rpc_function rf) { mark_access_time(); if (c_queue.enter_function(rf) == c_queue.OK) { se.resume(); return OK; } return PROCESS_CALL_FROM_C_FAILED; } /** method description: this method will take out a function from the client function queue and pass it to corresponding query object to process uses the services of class(es): input parameter(s): none output parameter(s): none return value: OK -- a function has been taken out from queue and processed by the corresponding query correctly NULL_RPC_FUNCTION -- the queue is empty NULL_PARAMETER -- No parameter is found in the rpc_function INVALID_PARAMETER_TYPE -- The parameter's type of rpc_function is invalid PROCESS_FUNCTION_FROM_CLIENT_FAILED -- error happens when query process the function QUERIES_OVERFLOW -- Queries overflowed synchronization: synchronized */ public synchronized int execute_next_call_from_client() { rpc_function rf = (rpc_function)client_queue.get_next_function(); if (rf == null) { return NULL_RPC_FUNCTION; } debug.dumpTrace("session.execute_next_call_from_client(): call is " + rf.get_name() + "()."); ////DEBUG parameter p = rf.get_parameter(0); rf.delete_parameter(0); if (p == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_client Parameter is null."); return NULL_PARAMETER; } if (!p.get_type().equals("INTEGER")) { debug.dumpTrace("Class:session Method:execute_next_call_from_client Invalid parameter type."); return INVALID_PARAMETER_TYPE; } int q_id = ((Integer)p.get_value()).intValue(); query q = null; for (int i = 0; i < queries.size(); i++) { q = (query)queries.elementAt(i); if (q.get_id() == q_id) { if (q.process_call_from_client(rf) == q.SUCCESS) { return OK; } else { return PROCESS_FUNCTION_FROM_CLIENT_FAILED; } } } //Can't find the query corresponding to the rpc_function from client_queue, so new query must be created and added to queries Vector if (queries.size() >= max_number_queries) { debug.dumpTrace("Class:session Method:execute_next_call_from_client query overflowed."); return QUERIES_OVERFLOW; } query query_obj = new query(this, q_id, rm, debug); queries.addElement(query_obj); st.log_data_from_session(1,id,"Query with id "+Integer.toString(q_id)+" is created"); if (query_obj.process_call_from_client(rf) == query_obj.SUCCESS) { return OK; } else { return PROCESS_FUNCTION_FROM_CLIENT_FAILED; } } /** method description: this method will take out a function from C/C++ server function queue and pass it to corresponding query object to process uses the services of class(es): input parameter(s): none output parameter(s): none return value: OK -- a function has been taken out from queue and processed by the corresponding query correctly NULL_RPC_FUNCTION -- the queue is empty NULL_RPC_FUNCTION_NAME -- the rpc_function's name is null NULL_PARAMETER -- the parameter of rpc_function is null INVALID_PARAMETER_TYPE -- the parameter's type of rpc_function is invalid PROCESS_SHOW_INFORMATION_1_FAILED -- error happens when query process the function "show_information_1" PROCESS_FUNCTION_FROM_C_FAILED -- error happens when query process the function CANNOT_FIND_QUERY -- invalid query id PROCESS_ERROR_FOR_SESSION_MANAGER_FAILED -- error happens when session process the function synchronization: synchronized */ public synchronized int execute_next_call_from_c() { parameter p = null; String message = null; rpc_function rf = (rpc_function)c_queue.get_next_function(); if (rf == null) { return NULL_RPC_FUNCTION; } debug.dumpTrace("session.execute_next_call_from_client(): call is " + rf.get_name() + "()."); ////DEBUG if (rf.get_name() == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function_name is null."); return NULL_RPC_FUNCTION_NAME; } /* if (rf.get_name().equals("error_for_session_manager")) { p = rf.get_parameter(0); if ( p == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's first parameter is null."); return NULL_PARAMETER; } if (!p.get_type().equals("INTEGER")) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's first parameter is not an int."); return INVALID_PARAMETER_TYPE; } int module_id = ((Integer)p.get_value()).intValue(); p = rf.get_parameter(1); if ( p == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's second parameter is null."); return NULL_PARAMETER; } if (!p.get_type().equals("INTEGER")) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's second parameter is not an int."); return INVALID_PARAMETER_TYPE; } int err_code = ((Integer)p.get_value()).intValue(); p = rf.get_parameter(2); if ( p == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's third parameter is null."); return NULL_PARAMETER; } if (!p.get_type().equals("STRING")) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's third parameter is not a String."); return INVALID_PARAMETER_TYPE; } message = (String)(p.get_value()); if (process_error_for_session_manager(module_id, err_code, message) == OK) { return OK; } else { return PROCESS_ERROR_FOR_SESSION_MANAGER_FAILED; } } */ if (rf.get_name().equals("show_information_1")) { p = rf.get_parameter(0); if ( p == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's first parameter is null."); return NULL_PARAMETER; } if (!p.get_type().equals("STRING")) { debug.dumpTrace("Class:session Method:execute_next_call_from_c rpc_function's third parameter is not a String."); return INVALID_PARAMETER_TYPE; } message = (String)(p.get_value()); if (process_show_information_1(message) == OK) { return OK; } else { return PROCESS_SHOW_INFORMATION_1_FAILED; } } // if the rpc_function is not "error_for_session_manager" or "show_information_1", then find and execute the query corresponding to the rpc_function p = rf.get_parameter(0); rf.delete_parameter(0); if (p == null) { debug.dumpTrace("Class:session Method:execute_next_call_from_c Parameter is null."); return NULL_PARAMETER; } if (!p.get_type().equals("INTEGER")) { debug.dumpTrace("Class:session Method:execute_next_call_from_c Invalid parameter type."); return INVALID_PARAMETER_TYPE; } int q_id = ((Integer)p.get_value()).intValue(); query q = null; for (int i = 0; i < queries.size(); i++) { q = (query)queries.elementAt(i); if (q.get_id() == q_id) { if (q.process_call_from_c(rf) == q.SUCCESS) { return OK; } else { return PROCESS_FUNCTION_FROM_C_FAILED; } } } debug.dumpTrace("Class:session Method:execute_next_call_from_c Can't find a query with id"+Integer.toString(q_id)+"."); return CANNOT_FIND_QUERY; } /** method description: this method will tell the current number of functions in the client function queue. uses the services of class(es): function_queue input parameter(s): none output parameter(s): none return value: an integer specifies how many functions are there in the client function queue synchronization: none */ public int get_number_unprocessed_call_from_client() { return client_queue.get_number_functions(); } /** method description: this method will tell the current number of functions in the C/C++ server function queue. uses the services of class(es): function_queue input parameter(s): none output parameter(s): none return value: an integer specifies how many functions are there in the c/C++ marian server function queue synchronization: none */ public int get_number_unprocessed_call_from_c() { return c_queue.get_number_functions(); } /** method description: this method will process the function sent from one of it's query object to client (currently webgate), in fact it just insert the query id in the function and then pass it to session manager. uses the services of class(es): rpc_function, parameter input parameter(s): queyr_id -- specifies which query passed the function to this object rf -- the rpc function need to be processed output parameter(s): none return value: OK -- the function has been processed correctly NULL_RPC_FUNCTION -- the parameter rpc_function is null PROCESS_CALL_FROM_SESSION_TO_CLIENT_FAILED -- error happens when process call from session to client other -- synchronization: none */ public int process_call_from_query_to_client(int query_id, rpc_function rf) { if (rf == null) { debug.dumpTrace("Class:session Method:process_call_from_query_to_client rpc_function is null."); return NULL_RPC_FUNCTION; } parameter p = new parameter("query_id","INTEGER",new Integer(query_id),debug); rf.add_parameter(0,p); if (st.process_call_from_session_to_client(id,rf) == st.OK) { return OK; } else { return PROCESS_CALL_FROM_SESSION_TO_CLIENT_FAILED; } } /** method description: this method will process the function sent from one of its query object to C/C++ marian server, in fact it just insert the query id to the function and then pass it to session manager. uses the services of class(es): rpf_function, parameter input parameter(s): queyr_id -- specifies which query passed the function to this object rf -- the rpc function need to be processed output parameter(s): none return value: OK -- the function has been processed correctly NULL_RPC_FUNCTION -- the parameter rpc_function is null PROCESS_CALL_FROM_SESSION_TO_C_FAILED -- error happens when process call from session to c other -- synchronization: none */ public int process_call_from_query_to_c(int query_id, rpc_function rf) { if (rf == null) { debug.dumpTrace("Class:session Method:process_call_from_query_to_c rpc_function is null."); return NULL_RPC_FUNCTION; } parameter p = new parameter("query_id","INTEGER",new Integer(query_id),debug); rf.add_parameter(0,p); if (st.process_call_from_session_to_c(id,rf) == st.OK) { return OK; } else { return PROCESS_CALL_FROM_SESSION_TO_C_FAILED; } } /** method description: this method will return the id of this session object. uses the services of class(es): none input parameter(s): none output parameter(s): none return value: the id of this session as an integer synchronization: none */ public int get_id() { return id; } /** method description: this method will set the id of this session object. uses the services of class(es): input parameter(s): session_id -- this will be the new id of this session output parameter(s): none return value: OK -- the new id has been set successfully INVALID_SESSION_ID -- the parameter session_id is less than 0 other -- synchronization: none */ private int set_id(int session_id) { if (session_id < 0) { debug.dumpTrace("Class:session Method:set_id Invalid session_id."); return INVALID_SESSION_ID; } id = session_id; return OK; } /** method description: this method will return the number of queries currently in this session object. uses the services of class(es): none input parameter(s): none output parameter(s): none return value: the number of queries in this session object as an integer synchronization: none */ public int get_number_queries() { return queries.size(); } /** method description: this method will return the possible maximum number of queries allowed in this object uses the services of class(es): none input parameter(s): none output parameter(s): none return value: the maximum possible number of queries allowed in this session object as an integer synchronization: none */ public int get_max_number_queries() { return max_number_queries; } /** method description: this method will set the maximum possible number of queries allowed in this session object. uses the services of class(es): input parameter(s): number -- this will be the new maximum number output parameter(s): none return value: OK -- the new number has been set correctly INVALID_MAX_NUMBER_QUERIES -- the number is negative and doesn't make sense other -- synchronization: none */ public int set_max_number_queries(int number) { if ( number <= 0) { debug.dumpTrace("Class:session Method:set_max_number_queries Invalid number."); return INVALID_MAX_NUMBER_QUERIES; } max_number_queries = number; return OK; } /** method description: this method will process the error_for_session_manager function sent from C/C++ marian server. uses the services of class(es): input parameter(s): module_id -- specifies which module in C/C++ server send this function error_code -- specifies the type of error reported message -- specifies the message associated with the error output parameter(s): none return value: OK -- the function has been processed correctly other -- synchronization: none */ /* private int process_error_for_session_manager(int module_id, int error_code, String message) { st.log_data_from_session(1,id,"function error_for_session_manager received module_id: "+Integer.toString(module_id)+" error_code: "+Integer.toString(error_code)+" message:"+message); return OK; } */ /** method description: this method will process show_information_1 function sent from C/C++ marian server. uses the services of class(es): input parameter(s): message -- this is the message C/C++ server send to this session object output parameter(s): none return value: OK -- the function has been processed correctly NULL_MESSAGE -- the parameter message is null CANNOT_FIND_QUERY -- can't find query in the message PROCESS_CALL_FROM_SESSION_TO_CLIENT_FAILED -- error happens when process call from session to client other -- synchronization: none */ private int process_show_information_1(String message) { StringTokenizer token_message = null; int query_id; rpc_function rf = null; parameter p = null; String s = null, s1 = null; if (message == null) { debug.dumpTrace("Class:session Method:process_show_information_1 Null message."); return NULL_MESSAGE; } token_message = new StringTokenizer(message," ",false); if (token_message.countTokens() > 1) //ignore empty lines and lines with only one token { s = token_message.nextToken(); while (token_message.hasMoreTokens()) { if (s.equals("QUERY") && token_message.hasMoreTokens()) { s1 = token_message.nextToken(); try { if (s1.endsWith(",") || s1.endsWith(".") || s1.endsWith(":") || s1.endsWith(";")) { // strip the last separator s1 = s1.substring(0, s1.length() -1); } query_id = Integer.parseInt(s1); if (query_id < 0) { debug.dumpTrace("Class:session Method:process_show_information_1 query_id can't less than 0."); } } catch (Exception e) { s = s1; continue; } rf = new rpc_function(debug); rf.set_name("show_information"); p = new parameter(null,"STRING",message,debug); rf.add_parameter(0,p); p = new parameter(null,"INTEGER", new Integer(query_id), debug); rf.add_parameter(0,p); if (st.process_call_from_session_to_client(id, rf) == st.OK) { st.log_data_from_session(1,id,"function show_information sent to client."); return OK; } else { return PROCESS_CALL_FROM_SESSION_TO_CLIENT_FAILED; } } else { if (token_message.hasMoreTokens()) { s = token_message.nextToken(); } } } // end -- while (token_message.hasMoreTokens()) } // end -- if (token_message.countTokens() > 1) st.log_data_from_session(1,id,"function show_information_1 received, message: "+message); return CANNOT_FIND_QUERY; } /** method description: this method will set the last access time of this session object to the current time uses the services of class(es): none input parameter(s): none output parameter(s): none return value: none synchronization: none */ private void mark_access_time() { Date date = new Date(); last_access_time = date.getTime(); } /** method description: this method will initialize the data members of this object uses the services of class(es): none input parameter(s): none output parameter(s): none return value: none synchronization: none */ private void init() { Date date = new Date(); id = -1; queries = new Vector(); st = null; se = null; rm = null; last_access_time = date.getTime(); client_queue = null; c_queue = null; session_execution_file_name = null; max_number_queries = 1000; max_client_functions = 100; max_c_functions = 100; return; } /** method description: this method log the data sent from the specified query of this session uses the services of class(es): none input parameter(s): log_level -- specifies the depth of the message, 1 means it's the query itself query_id -- identifies the query sent the message message message -- the message the query want the session to log generator relative to the session output parameter(s): none return value: OK -- the message has been logged correctly other -- synchronization: none */ public int log_data_from_query(int log_level, int query_id, String message) { log_level++; message = "from query:"+Integer.toString(query_id)+"\n"+message; return st.log_data_from_session(log_level,id,message); } }