Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/LibraryServlet.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/LibraryServlet.java	(revision 14497)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/LibraryServlet.java	(revision 14498)
@@ -12,8 +12,10 @@
 import javax.servlet.http.*;
 import java.util.Enumeration;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.io.File;
-
+import java.util.Hashtable;
 import org.apache.log4j.*;
+
 
 /** a servlet to serve the greenstone library - we are using servlets instead
@@ -22,354 +24,526 @@
  * are loaded. Each time a request comes in to the servlet, the session()
  * method is called in a new thread (calls doGet/doPut etc)
- * takes the a=p&p=home type args and builds a simple request to send to 
+ * takes the a=p&p=home type args and builds a simple request to send to
  * its receptionist, which returns a result in html, cos output=html
  * is set in the request
+ * 
+ * 18/Jul/07 xiao
+ * modify to make the cached parameters collection-specific.
+ * Most of the work is done in doGet(), except adding an inner class UserSessionCache.
+ * 
  * @see Receptionist
  */
 public class LibraryServlet extends HttpServlet {
-    
-    /** the receptionist to send messages to */
-    protected Receptionist recept=null;
-    /** the default language - is specified by setting a servlet param,
-     * otherwise DEFAULT_LANG is used*/
-    protected String default_lang= null;
-    /** The default default - used if a default lang is not specified 
-     * in the servlet params */
-    protected final String DEFAULT_LANG = "en";
-    /** container Document to create XML Nodes */
-    protected Document doc=null;    
-    /** a converter class to parse XML and create Docs */
-    protected XMLConverter converter=null;
-    /** the cgi stuff - the Receptionist can add new args to this
-     * its used by the servlet to determine what args to save */
-    protected GSParams params = null;
-
-    /** user id - new one per session. This doesn't work if session state is saved between restarts - this requires this value to be saved too. */
-    protected int next_user_id = 0;
-
-    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.LibraryServlet.class.getName());
-
-    /** initialise the servlet
+  
+  /** the receptionist to send messages to */
+  protected Receptionist recept=null;
+  /** the default language - is specified by setting a servlet param,
+   * otherwise DEFAULT_LANG is used*/
+  protected String default_lang= null;
+  /** The default default - used if a default lang is not specified
+   * in the servlet params */
+  protected final String DEFAULT_LANG = "en";
+  /** container Document to create XML Nodes */
+  protected Document doc=null;
+  /** a converter class to parse XML and create Docs */
+  protected XMLConverter converter=null;
+  /** the cgi stuff - the Receptionist can add new args to this
+   *
+   * its used by the servlet to determine what args to save */
+  protected GSParams params = null;
+  
+  /** user id - new one per session. This doesn't work if session state is saved between restarts - this requires this value to be saved too. */
+  protected int next_user_id = 0;
+
+  /** a hash that contains all the active session IDs mapped to the cached items
+   *  It is updated whenever the whole site or a particular collection is reconfigured
+   *  using the command a=s&sa=c or a=s&sa=c&c=xxx
+   *  It is in the form: sid -> (UserSessionCache object)
+   */
+  protected Hashtable session_ids_table = new Hashtable();
+  //this name is combined with the collection name and used for caching 
+  protected String valid_site_name = "";
+  
+  /** the maximum interval that the cached info remains in session_ids_table (in seconds) 
+   *  This is set in web.xml
+   */
+  protected int session_expiration = 1800;
+  
+  static Logger logger = Logger.getLogger(org.greenstone.gsdl3.LibraryServlet.class.getName());
+  
+  /** initialise the servlet
+   */
+  public void init(ServletConfig config) throws ServletException {
+    // always call super.init;
+    super.init(config);
+    // disable preferences - does this work anyway??
+    //System.setProperty("java.util.prefs.PreferencesFactory", "org.greenstone.gsdl3.util.DisabledPreferencesFactory");
+    
+    
+    String library_name = config.getInitParameter(GSConstants.LIBRARY_NAME);
+    String gsdl3_home = config.getInitParameter(GSConstants.GSDL3_HOME);
+    String interface_name = config.getInitParameter(GSConstants.INTERFACE_NAME);
+    this.default_lang = config.getInitParameter(GSConstants.DEFAULT_LANG);
+    String sess_expire = config.getInitParameter(GSXML.SESSION_EXPIRATION);
+    if (sess_expire != null && !sess_expire.equals("")) {
+        this.session_expiration = Integer.parseInt(sess_expire);
+    }
+    
+    if (library_name == null || interface_name ==null) {
+      // must have this
+      System.err.println("initialisation parameters not all set!");
+      System.err.println(" you must have libraryname and interfacename");
+      System.exit(1);
+    }
+    
+    String site_name = config.getInitParameter(GSConstants.SITE_NAME);
+    String remote_site_name = null;
+    String remote_site_type = null;
+    String remote_site_address = null;
+    
+    if (site_name == null) {
+      // no site, try for communicator
+      remote_site_name = config.getInitParameter("remote_site_name");
+      remote_site_type = config.getInitParameter("remote_site_type");
+      remote_site_address = config.getInitParameter("remote_site_address");
+      if (remote_site_name == null || remote_site_type == null || remote_site_address == null) {
+        System.err.println("initialisation paramters not all set!");
+        System.err.println("if site_name is not set, then you must have remote_site_name, remote_site_type and remote_site_address set");
+        System.exit(1);
+      }
+    }
+    valid_site_name = (site_name != null)? site_name : remote_site_name;
+    
+    if (this.default_lang == null) {
+      // choose english
+      this.default_lang = DEFAULT_LANG;
+    }
+    
+    HashMap config_params = new HashMap();
+    
+    config_params.put(GSConstants.LIBRARY_NAME, library_name);
+    config_params.put(GSConstants.INTERFACE_NAME, interface_name);
+    if (site_name != null) {
+      config_params.put(GSConstants.SITE_NAME, site_name);
+    }
+    this.converter = new XMLConverter();
+    this.doc = this.converter.newDOM();
+    
+    // the receptionist -the servlet will talk to this
+    String recept_name = (String)config.getInitParameter("receptionist_class");
+    if (recept_name == null) {
+      this.recept = new DefaultReceptionist();
+    } else {
+      try {
+        this.recept = (Receptionist)Class.forName("org.greenstone.gsdl3.core."+recept_name).newInstance();
+      } catch (Exception e) { // cant use this new one, so use normal one
+        System.err.println("LibraryServlet configure exception when trying to use a new Receptionist "+recept_name+": "+e.getMessage());
+        e.printStackTrace();
+        this.recept = new DefaultReceptionist();
+      }
+    }
+    this.recept.setConfigParams(config_params);
+    
+    // the receptionist uses a MessageRouter or Communicator to send its requests to. We either create a MessageRouter here for the designated site (if site_name set), or we create a Communicator for a remote site. The is given to teh Receptionist, and the servlet never talks to it again.directly.
+    if (site_name != null) {
+      String mr_name = (String)config.getInitParameter("messagerouter_class");
+      MessageRouter message_router = null;
+      if (mr_name == null) { // just use the normal MR
+        message_router = new MessageRouter();
+      } else { // try the specified one
+        try {
+          message_router = (MessageRouter)Class.forName("org.greenstone.gsdl3.core."+mr_name).newInstance();
+        } catch (Exception e) { // cant use this new one, so use normal one
+          System.err.println("LibraryServlet configure exception when trying to use a new MessageRouter "+mr_name+": "+e.getMessage());
+          e.printStackTrace();
+          message_router = new MessageRouter();
+        }
+      }
+      
+      message_router.setSiteName(site_name);
+      message_router.configure();
+      this.recept.setMessageRouter(message_router);
+    } else {
+      // talking to a remote site, create a communicator
+      Communicator communicator = null;
+      // we need to create the XML to configure the communicator
+      Element site_elem = this.doc.createElement(GSXML.SITE_ELEM);
+      site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
+      site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
+      site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
+      
+      if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
+        communicator = new SOAPCommunicator();
+      } else {
+        System.err.println("LibraryServlet.init Error: invalid Communicator type: "+remote_site_type);
+        System.exit(1);
+      }
+      
+      if (!communicator.configure(site_elem)) {
+        System.err.println("LibraryServlet.init Error: Couldn't configure communicator");
+        System.exit(1);
+      }
+      this.recept.setMessageRouter(communicator);
+    }
+    
+    // the params arg thingy
+    
+    String params_name = (String)config.getInitParameter("params_class");
+    if (params_name == null) {
+      this.params = new GSParams();
+    } else {
+      try {
+        this.params = (GSParams)Class.forName("org.greenstone.gsdl3.util."+params_name).newInstance();
+      } catch (Exception e) {
+        System.err.println("LibraryServlet configure exception when trying to use a new params thing "+params_name+": "+e.getMessage());
+        e.printStackTrace();
+        this.params = new GSParams();
+      }
+    }
+    // pass it to the receptionist
+    this.recept.setParams(this.params);
+    this.recept.configure();
+    
+  }
+  
+  
+  private void logUsageInfo(HttpServletRequest request){
+    String usageInfo = "";
+    
+    //session-info: get params stored in the session
+    HttpSession session = request.getSession(true);
+    Enumeration attributeNames = session.getAttributeNames();
+    while(attributeNames.hasMoreElements()) {
+      String name = (String)attributeNames.nextElement();
+      usageInfo +=name+"="+session.getAttribute(name)+" ";
+    }
+    
+    //logged info = general-info + session-info
+    usageInfo =
+      request.getServletPath()+" "+ //serlvet
+      "["+request.getQueryString()+"]" +" "+ //the query string
+      "["+usageInfo.trim()+"]" +" "+ // params stored in a session
+      request.getRemoteAddr()+" "+   //remote address
+      request.getRequestedSessionId()+" "+ //session id
+      request.getHeader("user-agent")+" "; //the remote brower info
+    
+    logger.info(usageInfo);
+    
+  }
+  
+  public class UserSessionCache implements HttpSessionBindingListener {
+
+    String session_id = "";
+    
+    /** a hash that maps the session ID to a hashtable that maps the coll_name to its parameters 
+     *  coll_name -> Hashtable (param_name -> param_value)
      */
-    public void init(ServletConfig config) throws ServletException {
-	// always call super.init;
-	super.init(config);
-	// disable preferences - does this work anyway??
-	//System.setProperty("java.util.prefs.PreferencesFactory", "org.greenstone.gsdl3.util.DisabledPreferencesFactory");
-
-    
-	String library_name = config.getInitParameter(GSConstants.LIBRARY_NAME);
-	String gsdl3_home = config.getInitParameter(GSConstants.GSDL3_HOME);
-	String interface_name = config.getInitParameter(GSConstants.INTERFACE_NAME);
-	this.default_lang = config.getInitParameter(GSConstants.DEFAULT_LANG);
-
-	if (library_name == null || interface_name ==null) {
-	    // must have this
-	    System.err.println("initialisation parameters not all set!");
-	    System.err.println(" you must have libraryname and interfacename");
-	    System.exit(1);
+    protected Hashtable coll_name_params_table = null;
+    
+    public UserSessionCache(String id, Hashtable table) {
+      session_id = id;      
+      coll_name_params_table = (table == null)? new Hashtable() : table;      
+    }
+
+    protected void cleanupCache(String coll_name) {
+      if (coll_name_params_table.containsKey(coll_name)) {
+    	  coll_name_params_table.remove(coll_name);
+      }
+    }
+    protected Hashtable getParamsTable() {
+    	return coll_name_params_table;
+    }
+    public void valueBound(HttpSessionBindingEvent event) {
+    // Do nothing
+    }
+
+    public void valueUnbound(HttpSessionBindingEvent event) {
+      if(session_ids_table.containsKey(session_id)) {
+        session_ids_table.remove(session_id);
+      }
+    }
+    public int tableSize() {
+    	return (coll_name_params_table == null)? 0 : coll_name_params_table.size();
+    }
+  }
+  
+  public void doGet (HttpServletRequest request,
+    HttpServletResponse response)
+    throws ServletException, IOException {
+    logUsageInfo (request);
+    //logger.info("---------------------------------------------------");
+    // Nested Diagnostic Configurator to identify the client for
+    
+    HttpSession session = request.getSession (true);
+    String uid = (String)session.getAttribute (GSXML.USER_ID_ATT);
+    if (uid ==null) {
+      uid = ""+getNextUserId ();
+      session.setAttribute (GSXML.USER_ID_ATT, uid);
+    }
+    request.setCharacterEncoding ("UTF-8");
+    response.setContentType ("text/html;charset=UTF-8");
+    PrintWriter out = response.getWriter ();
+    
+    String lang = request.getParameter (GSParams.LANGUAGE);
+    if (lang==null || lang.equals ("")) {
+      // try the session cached lang
+      lang = (String)session.getAttribute (GSParams.LANGUAGE);
+      if (lang==null || lang.equals ("")) {
+        // still not set, use the default
+        lang = this.default_lang;
+      }
+    }
+    
+    // set the lang in the session
+    session.setAttribute (GSParams.LANGUAGE, lang);
+    
+    String output = request.getParameter (GSParams.OUTPUT);
+    if (output==null || output.equals ("")) {
+      output = "html"; // uses html by default
+    }
+    
+    // the request to the receptionist
+    Element xml_message = this.doc.createElement (GSXML.MESSAGE_ELEM);
+    Element xml_request = GSXML.createBasicRequest (this.doc, GSXML.REQUEST_TYPE_PAGE, "", lang, uid);
+    xml_request.setAttribute (GSXML.OUTPUT_ATT, output);
+    xml_message.appendChild (xml_request);
+    
+    String action = request.getParameter (GSParams.ACTION);
+    String subaction = request.getParameter (GSParams.SUBACTION);
+    String collection = request.getParameter(GSParams.COLLECTION);
+
+  	//specifically we clean up the cache session_ids_table if the two reconfigure command
+   	//are issued: a=s&sa=c and a=s&sa=c&c=coll_name, in which case there is no caching action to be taken
+    boolean should_cache = true;
+	if(action != null && action.equals(GSParams.SYSTEM) 
+			&& subaction != null && subaction.equals(GSParams.CONFIGURE)) {
+		if (collection == null || collection.equals("")) {
+		    //user reconfiugred the whole site, clean up all cached info
+			//logger.info("clear cache for the whole site.");
+		    session_ids_table = new Hashtable(); 
+		    
+		} else {
+			//clean up all cache info related to the collection
+			//logger.info("clear cache for collection: " + collection);
+			ArrayList cache_list = new ArrayList(session_ids_table.values());
+			for (int i=0; i<cache_list.size(); i++) {
+				UserSessionCache cache = (UserSessionCache)cache_list.get(i);
+				cache.cleanupCache(collection);
+			}
+		}
+		should_cache = false;
 	}
 
-	String site_name = config.getInitParameter(GSConstants.SITE_NAME);
-	String remote_site_name = null;
-	String remote_site_type = null;
-	String remote_site_address = null;
-	
-	if (site_name == null) {
-	    // no site, try for communicator
-	    remote_site_name = config.getInitParameter("remote_site_name");
-	    remote_site_type = config.getInitParameter("remote_site_type");
-	    remote_site_address = config.getInitParameter("remote_site_address");
-	    if (remote_site_name == null || remote_site_type == null || remote_site_address == null) {
-		System.err.println("initialisation paramters not all set!");
-		System.err.println("if site_name is not set, then you must have remote_site_name, remote_site_type and remote_site_address set");
-		System.exit(1); 
-	    }
-	}
-	
-	if (this.default_lang == null) {
-	    // choose english
-	    this.default_lang = DEFAULT_LANG;
-	}
-	
-	HashMap config_params = new HashMap();
-	
-	config_params.put(GSConstants.LIBRARY_NAME, library_name);
-	config_params.put(GSConstants.INTERFACE_NAME, interface_name);
-	if (site_name != null) {
-	    config_params.put(GSConstants.SITE_NAME, site_name);
-	}
-	this.converter = new XMLConverter();
-	this.doc = this.converter.newDOM();
-	
-	// the receptionist -the servlet will talk to this
-	String recept_name = (String)config.getInitParameter("receptionist_class");
-	if (recept_name == null) {
-	    this.recept = new DefaultReceptionist();
-	} else {
-	    try {
-		this.recept = (Receptionist)Class.forName("org.greenstone.gsdl3.core."+recept_name).newInstance();
-	    } catch (Exception e) { // cant use this new one, so use normal one
-		System.err.println("LibraryServlet configure exception when trying to use a new Receptionist "+recept_name+": "+e.getMessage());
-		e.printStackTrace();
-		this.recept = new DefaultReceptionist();
-	    }
-	}
-	this.recept.setConfigParams(config_params);
-
-	// the receptionist uses a MessageRouter or Communicator to send its requests to. We either create a MessageRouter here for the designated site (if site_name set), or we create a Communicator for a remote site. The is given to teh Receptionist, and the servlet never talks to it again.directly.
-	if (site_name != null) {
-	    String mr_name = (String)config.getInitParameter("messagerouter_class");
-	    MessageRouter message_router = null;
-	    if (mr_name == null) { // just use the normal MR
-		message_router = new MessageRouter();
-	    } else { // try the specified one
-		try {
-		    message_router = (MessageRouter)Class.forName("org.greenstone.gsdl3.core."+mr_name).newInstance();
-		} catch (Exception e) { // cant use this new one, so use normal one
-		    System.err.println("LibraryServlet configure exception when trying to use a new MessageRouter "+mr_name+": "+e.getMessage());
-		    e.printStackTrace();
-		    message_router = new MessageRouter();
-		}   
-	    }
-	    
-	    message_router.setSiteName(site_name);
-	    message_router.configure();
-	    this.recept.setMessageRouter(message_router);
-	} else {
-	    // talking to a remote site, create a communicator
-	    Communicator communicator = null;
-	    // we need to create the XML to configure the communicator
-	    Element site_elem = this.doc.createElement(GSXML.SITE_ELEM);
-	    site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
-	    site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
-	    site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
-
-	    if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
-		communicator = new SOAPCommunicator();
-	    } else {
-		System.err.println("LibraryServlet.init Error: invalid Communicator type: "+remote_site_type);
-		System.exit(1);
-	    }
-	    
-	    if (!communicator.configure(site_elem)) {
-		System.err.println("LibraryServlet.init Error: Couldn't configure communicator");
-		System.exit(1);
-	    }
-	    this.recept.setMessageRouter(communicator);
-	}
-	
-	// the params arg thingy
-	
-	String params_name = (String)config.getInitParameter("params_class");
-	if (params_name == null) {
-	    this.params = new GSParams();
-	} else {
-	    try {
-		this.params = (GSParams)Class.forName("org.greenstone.gsdl3.util."+params_name).newInstance();
-	    } catch (Exception e) {
-		System.err.println("LibraryServlet configure exception when trying to use a new params thing "+params_name+": "+e.getMessage());
-		e.printStackTrace();
-		this.params = new GSParams();
-	    }
-	}
-	// pass it to the receptionist
-	this.recept.setParams(this.params);
-	this.recept.configure();
-	
-    }
-
-
-    private void logUsageInfo(HttpServletRequest request){
-	String usageInfo = "";
-
-	//session-info: get params stored in the session
-	HttpSession session = request.getSession(true);
-        Enumeration attributeNames = session.getAttributeNames();
-	while(attributeNames.hasMoreElements()) {
-	    String name = (String)attributeNames.nextElement();
-	    usageInfo +=name+"="+session.getAttribute(name)+" ";
-	}
-	
-	//logged info = general-info + session-info
-	usageInfo = 
-	    request.getServletPath()+" "+ //serlvet
-	    "["+request.getQueryString()+"]" +" "+ //the query string
-	    "["+usageInfo.trim()+"]" +" "+ // params stored in a session
-	    request.getRemoteAddr()+" "+   //remote address                  
-	    request.getRequestedSessionId()+" "+ //session id
-	    request.getHeader("user-agent")+" "; //the remote brower info                      
-                         
-	logger.info(usageInfo);
-
-    }
-
-       
-    public void doGet(HttpServletRequest request,
-		      HttpServletResponse response)
-	throws ServletException, IOException {
-
-	logUsageInfo(request);
-          
-	// Nested Diagnostic Configurator to identify the client for
-       
-	HttpSession session = request.getSession(true);
-        String uid = (String)session.getAttribute(GSXML.USER_ID_ATT);
-	if (uid ==null) {
-	    uid = ""+getNextUserId();
-	    session.setAttribute(GSXML.USER_ID_ATT, uid);
-	}
-	request.setCharacterEncoding("UTF-8");
-	response.setContentType("text/html;charset=UTF-8");
-	PrintWriter out = response.getWriter();
-
-	String lang = request.getParameter(GSParams.LANGUAGE);
-	if (lang==null || lang.equals("")) {
-	    // try the session cached lang
-	    lang = (String)session.getAttribute(GSParams.LANGUAGE);
-	    if (lang==null || lang.equals("")) {
-		// still not set, use the default
-		lang = this.default_lang;
-	    }
-	}
-	
-	// set the lang in the session
-	session.setAttribute(GSParams.LANGUAGE, lang);
-
-	String output = request.getParameter(GSParams.OUTPUT);
-	if (output==null || output.equals("")) {
-	    output = "html"; // uses html by default
-	}
-
-	// the request to the receptionist	
-	Element xml_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
-	Element xml_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", lang, uid);
-	xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
-	xml_message.appendChild(xml_request);
-	
-	
-	String action = request.getParameter(GSParams.ACTION);
-	String subaction = request.getParameter(GSParams.SUBACTION);
-	if (action==null || action.equals("")) {
-	    // should we do all the following stuff if using default page?
-	    // display the home page  - the default page
-	    action = "p";
-	    subaction = PageAction.HOME_PAGE;
-	    xml_request.setAttribute(GSXML.ACTION_ATT, action);
-	    xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
-	    
-	} else {
-	
-	    xml_request.setAttribute(GSXML.ACTION_ATT, action);
-	    if (subaction != null) {
-		xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
-	    }
-
-	    //  create the param list for the greenstone request - includes
-	    // the params from the current request and any others from the saved session
-	    Element xml_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
-	    xml_request.appendChild(xml_param_list);
-	    
-	    Enumeration params = request.getParameterNames();
-	    while(params.hasMoreElements()) {
-		String name = (String)params.nextElement();
-		if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT)) {// we have already dealt with these 
-		    String value="";
-		    String [] values = request.getParameterValues(name);
-		    value = values[0];
-		    if (values.length > 1) {
-			for (int i=1; i< values.length; i++) {
-			    value += ","+values[i];
-			}
-		    }
-		    // either add it to the param list straight away, or save it to the session and add it later
-		    if (this.params.shouldSave(name)) {			
-			session.setAttribute(name, value);
-		    } else { 
-			Element param = this.doc.createElement(GSXML.PARAM_ELEM);
-			param.setAttribute(GSXML.NAME_ATT, name);
-			param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
-			xml_param_list.appendChild(param);
-		    }
+    //	logger.info("should_cache= " + should_cache);
+    //clear the collection-specific cache in the session, since we have no way to know whether this session is 
+    //about the same collection as the last session or not.
+    Enumeration attributeNames = session.getAttributeNames();
+    while(attributeNames.hasMoreElements()) {
+    	String name = (String)attributeNames.nextElement();
+    	if (!name.equals (GSXML.USER_SESSION_CACHE_ATT)
+    			&& !name.equals (GSParams.LANGUAGE) 
+    			&& !name.equals (GSXML.USER_ID_ATT)) {
+    		session.removeAttribute(name);
+    	}
+    }
+    
+    UserSessionCache session_cache = null;
+    Hashtable param_table = null;    
+    Hashtable table = null;
+    String sid = session.getId();
+    if (should_cache == true && collection != null && !collection.equals("")) {
+    	String key_str = valid_site_name + collection;
+    	if (session_ids_table.containsKey(sid)) {
+    		session_cache = (UserSessionCache)session_ids_table.get(sid);
+    		param_table = session_cache.getParamsTable();
+    		logger.info("collections in table: " + tableToString(param_table));
+    			if (param_table.containsKey(key_str)) {
+    				//logger.info("existing table: " + collection);
+    				table = (Hashtable)param_table.get(key_str);
+    			} else {
+    				table = new Hashtable();
+    				param_table.put(key_str, table);
+    				//logger.info("new table: " + collection);
+    			}
+    	} else {
+    		param_table = new Hashtable();
+    		table = new Hashtable();
+    		param_table.put(key_str, table);
+    		session_cache = new UserSessionCache(sid, param_table);
+    		session_ids_table.put(sid, session_cache);
+    		//logger.info("new session id");
+    	}
+    }
+
+    if (action==null || action.equals ("")) {
+      // should we do all the following stuff if using default page?
+      // display the home page  - the default page
+      action = "p";
+      subaction = PageAction.HOME_PAGE;
+      
+      xml_request.setAttribute (GSXML.ACTION_ATT, action);
+      xml_request.setAttribute (GSXML.SUBACTION_ATT, subaction);
+      
+    } else {
+      
+      xml_request.setAttribute (GSXML.ACTION_ATT, action);
+      if (subaction != null) {
+        xml_request.setAttribute (GSXML.SUBACTION_ATT, subaction);
+      }
+      
+      //  create the param list for the greenstone request - includes
+      // the params from the current request and any others from the saved session
+      Element xml_param_list = this.doc.createElement (GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+      xml_request.appendChild (xml_param_list);
+      
+      Enumeration params = request.getParameterNames ();
+      while(params.hasMoreElements ()) {
+        String name = (String)params.nextElement ();
+        if (!name.equals (GSParams.ACTION) 
+        		&& !name.equals (GSParams.SUBACTION) 
+        		&& !name.equals (GSParams.LANGUAGE) 
+        		&& !name.equals (GSParams.OUTPUT)) {// we have already dealt with these
+          String value="";
+          String [] values = request.getParameterValues (name);
+          value = values[0];
+          if (values.length > 1) {
+            for (int i=1; i< values.length; i++) {
+              value += ","+values[i];
+            }
+          }
+          // either add it to the param list straight away, or save it to the session and add it later
+          if (this.params.shouldSave (name)) {
+        	  if (table != null) {        		
+        		  table.put(name, value);        			 
+        	  }
+          } else {
+            Element param = this.doc.createElement (GSXML.PARAM_ELEM);
+            param.setAttribute (GSXML.NAME_ATT, name);
+            param.setAttribute (GSXML.VALUE_ATT, GSXML.xmlSafe (value));
+            xml_param_list.appendChild (param);
+          }
+        }
+      }
+      //put everything in the table into the session
+      if (table != null) {
+    	  Enumeration keys = table.keys ();
+          while(keys.hasMoreElements ()) {
+        	  String name = (String)keys.nextElement();
+        	  session.setAttribute(name, (String)table.get(name));
+          }
+      }
+      
+      // put in all the params from the session cache
+      params = session.getAttributeNames ();
+      while(params.hasMoreElements ()) {
+        String name = (String)params.nextElement ();
+        
+        if ( !name.equals (GSXML.USER_SESSION_CACHE_ATT) 
+        		&& !name.equals (GSParams.LANGUAGE) 
+        		&& !name.equals (GSXML.USER_ID_ATT)) { 
+        // lang and uid are stored but we dont want it in the param list cos its already in the request
+          Element param = this.doc.createElement (GSXML.PARAM_ELEM);
+          param.setAttribute (GSXML.NAME_ATT, name);
+          String value =  GSXML.xmlSafe ((String)session.getAttribute (name));
+          // ugly hack to undo : escaping
+          value = value.replaceAll ("%3A", "\\:");
+          param.setAttribute (GSXML.VALUE_ATT,value);
+          xml_param_list.appendChild (param);
+        }
+      }
+        
+      //now set the UserSessionCache object into the session with its life expectancy
+      if (session_cache != null) {
+          session.setAttribute(GSXML.USER_SESSION_CACHE_ATT, session_cache);
+          session.setMaxInactiveInterval(session_expiration);
+      }
+    }
+    
+    if (!output.equals ("html")) {
+      response.setContentType ("text/xml"); // for now use text
+    }
+    
+    //GSXML.printXMLNode(xml_message);
+    
+    Element xml_result = this.recept.process (xml_message);
+    encodeURLs (xml_result, response);
+    out.println (this.converter.getPrettyString (xml_result));
+    
+    displaySize(session_ids_table);
+  }
+  //a debugging method
+  private void displaySize(Hashtable table) {
+	  if(table == null) {
+		  logger.info("cached table is null");
+		  return;
+	  }
+	  if (table.size() == 0) {
+		  logger.info("cached table size is zero");
+		  return;
+	  }
+	  int num_cached_coll = 0;
+		ArrayList cache_list = new ArrayList(table.values());
+		for (int i=0; i<cache_list.size(); i++) {
+			num_cached_coll += ((UserSessionCache)cache_list.get(i)).tableSize();			
 		}
-	    }
-	    
-	    // put in all the params from the session cache
-	    params = session.getAttributeNames();
-	    while(params.hasMoreElements()) {
-		String name = (String)params.nextElement();
-		
-		if ( !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT)) { // lang and uid are stored but we dont want it in the param list cos its already in the request
-		    
-		    Element param = this.doc.createElement(GSXML.PARAM_ELEM);
-		    param.setAttribute(GSXML.NAME_ATT, name);
-		    String value =  GSXML.xmlSafe((String)session.getAttribute(name));
-		    // ugly hack to undo : escaping
-		    value = value.replaceAll("%3A", "\\:");
-		    param.setAttribute(GSXML.VALUE_ATT,value);
-		    xml_param_list.appendChild(param);
-		}
-	    }
-
-	
-	}
-	
-	if (!output.equals("html")) {
-	    response.setContentType("text/xml"); // for now use text
-	}
-
-	//GSXML.printXMLNode(xml_message);	
-
-	Element xml_result = this.recept.process(xml_message);
-	encodeURLs(xml_result, response);
-	out.println(this.converter.getPrettyString(xml_result));
-    }
-
-    /** this goes through each URL and adds in a session id if needed--
-     * its needed if the browser doesn't accept cookies
-     * also escapes things if needed
-     */
-    protected void encodeURLs(Element data, HttpServletResponse response) {
-	
-	if (data == null) {
-	    return;
-	}
-	// get all the <a> elements
-	NodeList hrefs = data.getElementsByTagName("a");
-	for (int i=0; i<hrefs.getLength(); i++) {
-	    Element a = (Element)hrefs.item(i);
-	    // ugly hack to get rid of : in the args - interferes with session handling
-	    String href = a.getAttribute("href");
-	    if (!href.equals("")) {
-		if (href.indexOf("?")!=-1) {
-		    String[] parts = href.split("\\?", -1);
-		    parts[1]=parts[1].replaceAll(":", "%3A");
-		    href = parts[0]+"?"+parts[1];
-		}
-		a.setAttribute("href", response.encodeURL(href));
-	    }
-	}
-	
-	// now find any submit bits - get all the <form> elements
-	NodeList forms = data.getElementsByTagName("form");
-	for (int i=0; i<forms.getLength(); i++) {
-	    Element form = (Element)forms.item(i);
-	    form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
-	}
-	// are these the only cases where URLs occur??
-	// we should only do this for greenstone urls?
-	
-    }
-
-    synchronized protected int getNextUserId() {
-	next_user_id++;
-	return next_user_id;
-    }
-
-    public void doPost(HttpServletRequest request,
-		      HttpServletResponse response)
-	throws ServletException, IOException {
-	doGet(request,response);
-
-    }
+	  logger.info("Number of sessions : total number of cached collection info = " + table.size() + " : " + num_cached_coll);
+  }  
+  /** merely a debugging method! */
+  private String tableToString(Hashtable table) {
+	 String str = "";
+	 Enumeration keys = table.keys ();
+     while(keys.hasMoreElements ()) {
+   	  String name = (String)keys.nextElement();
+   	  str += name + ", ";
+     }
+	 return str;
+  }
+
+  /** this goes through each URL and adds in a session id if needed--
+   * its needed if the browser doesn't accept cookies
+   * also escapes things if needed
+   */
+  protected void encodeURLs(Element data, HttpServletResponse response) {
+    
+    if (data == null) {
+      return;
+    }
+    // get all the <a> elements
+    NodeList hrefs = data.getElementsByTagName("a");
+    for (int i=0; i<hrefs.getLength(); i++) {
+      Element a = (Element)hrefs.item(i);
+      // ugly hack to get rid of : in the args - interferes with session handling
+      String href = a.getAttribute("href");
+      if (!href.equals("")) {
+        if (href.indexOf("?")!=-1) {
+          String[] parts = href.split("\\?", -1);
+          parts[1]=parts[1].replaceAll(":", "%3A");
+          href = parts[0]+"?"+parts[1];
+        }
+        a.setAttribute("href", response.encodeURL(href));
+      }
+    }
+    
+    // now find any submit bits - get all the <form> elements
+    NodeList forms = data.getElementsByTagName("form");
+    for (int i=0; i<forms.getLength(); i++) {
+      Element form = (Element)forms.item(i);
+      form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
+    }
+    // are these the only cases where URLs occur??
+    // we should only do this for greenstone urls?
+    
+  }
+  
+  synchronized protected int getNextUserId() {
+    next_user_id++;
+    return next_user_id;
+  }
+  
+  public void doPost(HttpServletRequest request,
+    HttpServletResponse response)
+    throws ServletException, IOException {
+    doGet(request,response);
+    
+  }
 }
