Added support for crashed client.
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / VamsasSession.java
index b30be93..b066f88 100644 (file)
@@ -2,21 +2,16 @@ package uk.ac.vamsas.client.simpleclient;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
 import java.io.RandomAccessFile;
-import java.io.Writer;
-import java.util.Enumeration;
-import java.util.Vector;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.log4j.Appender;
-import org.apache.log4j.Logger;
 import org.apache.log4j.FileAppender;
+import org.apache.log4j.Logger;
 import org.apache.log4j.PatternLayout;
 
 import uk.ac.vamsas.client.ClientHandle;
+import uk.ac.vamsas.client.Events;
 import uk.ac.vamsas.client.IClient;
 import uk.ac.vamsas.client.UserHandle;
 /**
@@ -86,6 +81,16 @@ public class VamsasSession {
   private SimpleSessionManager sessionManager = null;
   
   /**
+   * Count of cycles before considering the current client as the last one of the session (if no other client registered as active )
+   */
+  private final int watchCycleCountBeforeLastClient = 2 ;
+  
+  /**
+   * time between checking 
+   */
+  public int WATCH_SLEEP=30; 
+  
+  /**
    * called to clear update flag after a successful offline storage event
    */
   protected void clearUnsavedFlag() {
@@ -364,9 +369,65 @@ public class VamsasSession {
       clist.addClient(client.getClientHandle());
       getClientWatcherElement().enableWatch();
       log.debug("Added.");
+      log.debug("Register Client as Active.");
+      
+      //tracks modification to the client list and readds client to the list
+      getClientWatcherElement().setHandler(new AddClientWatchCallBack(client));
     }
   }
   
+  /**
+   * Handler for the client watcher.
+   * 
+   * If (the current client is not in the client list, it is added again;)
+   */  
+  private class AddClientWatchCallBack  implements WatcherCallBack
+  {
+   
+    private IClient client ;
+    
+    /**
+    *Inits the handler with the client to check in the list
+     * @param client client to monitor in the client list
+     */
+    protected  AddClientWatchCallBack (IClient client)
+      {
+        this.client = client;
+      }
+    
+      /**
+       * If the client list is modified, checks if the current is still in the list. otherwise, readds ti.
+       * @return true to enable watcher, or false to disable it in future WatcherThread cycles.
+       */
+      public boolean handleWatchEvent(WatcherElement watcher, Lock lock)
+        {
+          boolean isWatchEnable = watcher.isWatchEnabled();
+          if (client != null)
+            {
+          
+            
+            //checks if the client is not already in the lists
+              ClientHandle[] cl = clist.retrieveClientList(lock);//clist.retrieveClientList();
+              boolean found = false;
+              if (cl != null)
+                {
+                  for (int chi = cl.length-1; !found && chi > -1; chi--) {
+                    found =  cl[chi].equals(this.client.getClientHandle());
+                  }
+                } else 
+              if (! found) 
+                {
+                if( log.isDebugEnabled())
+                  log.debug("the client has not been found in the list. Adding it again :"+cl);
+                  addClient(client);
+                }
+
+            }
+          
+          return isWatchEnable;
+        }
+      }
+  
 /**
  *  
  * removes a client from the current session
@@ -376,18 +437,32 @@ public class VamsasSession {
  *  
  * @param client client to remove
  */
-  protected void removeClient(IClient client)
+  protected void removeClient(SimpleClient client)//IClient client)
   {
     if (client == null)
       {
         log.error("Null client passed to removeClient");
         return;
       }
-    SessionFileWatcherElement cwe=getClientWatcherElement();
+    ClientSessionFileWatcherElement cwe=getClientWatcherElement();
     if (cwe!=null && cwe.isWatchEnabled()) {
       cwe.haltWatch();
     };
-    clist.removeClient(client.getClientHandle(),null);
+    //set handler to check is the the last active client of the session
+    //Wait for several watchers cycle to see if the current client was the last client active in the session.
+    //if yes, close the session
+    
+    getClientWatcherElement().setHandler(new RemoveClientWatchCallBack (client));
+    getClientWatcherElement().setTimeoutBeforeLastCycle(this.watchCycleCountBeforeLastClient);
+    log.info("remove client from list");
+    clist.clearList();
+    if (cwe!=null) {
+      cwe.enableWatch();
+    }
+   
+  
+   
+    /*clist.removeClient(client.getClientHandle(),null);
     if (this.clist.retrieveClientList() == null|| this.clist.retrieveClientList().length<1)
       {//assume it is the last client has been removed shutting down session
         slog.info("last client removed: removing session");
@@ -395,15 +470,81 @@ public class VamsasSession {
         this.getSessionManager().removeSession(client.getSessionHandle());
       }
     else
-    {
-      int active=clist.retrieveClientList().length;
-      log.debug("Still "+active+" active clients");
-      slog.info("Still "+active+" active clients");
-    }
-    if (cwe!=null) {
-      cwe.enableWatch();
-    }
+      {
+        int active=clist.retrieveClientList().length;
+        log.debug("Still "+active+" active clients");
+        slog.info("Still "+active+" active clients");
+      }*/
+   
   }
+  
+  /**
+   * Handler for the client watcher. after a client have been removed
+   * 
+   * Checks if the client is not the last active one.
+   * 
+   * If (the current client is not in the client list readd it;)
+   */  
+  private class RemoveClientWatchCallBack  implements WatcherCallBack
+  {
+   
+    private SimpleClient client ;
+    
+    /**
+    *Inits the handler with the client to check in the list
+     * @param client client to monitor in the client list
+     */
+    protected  RemoveClientWatchCallBack (SimpleClient client)
+      {
+        this.client = client;
+      }
+    
+      /**
+       * If the client list is modified, checks if the current is still in the list. otherwise, readds ti.
+       * @return true to enable watcher, or false to disable it in future WatcherThread cycles.
+       */
+      public boolean handleWatchEvent(WatcherElement watcher, Lock lock)
+        {
+         // boolean isWatchEnable = watcher.isWatchEnabled();
+          if (client != null)
+            {
+            
+            //checks if the client is not already in the lists
+              ClientHandle[] cl = clist.retrieveClientList(lock);//clist.retrieveClientList();
+//            ask to the client to cpoy application data into the document
+              client.evgen._raise(Events.DOCUMENT_FINALIZEAPPDATA, null, client,null);
+
+              if(cl == null || cl.length<1 )
+                {//no client has registered as active
+                //the client is the last one, so close current session
+                  log.info("last client removed: closing session");
+
+//                close document 
+                  client.evgen._raise(Events.DOCUMENT_REQUESTTOCLOSE, null, client,null);
+                  log.debug("close document request done");
+                  
+                  getSessionManager().removeSession(client.getSessionHandle());
+                  log.debug("Session removed");
+                }
+              else
+                {
+                log.debug("not the last client found ");
+//              ask to the client to cpoy application data into the document
+       //         client.evgen._raise(Events.DOCUMENT_FINALIZEAPPDATA, null, client,null);
+
+                }
+             // watcher.haltWatch();
+              log.debug("Stopping EventGenerator..");
+              client.evgen.stopWatching();
+            
+
+            }
+          watcher.setHandler(null);//Do not check if the client is the last client. watcher will shutdown anyway
+         
+          return false;
+        }
+      }
+
 /**
  * @return the sessionManager
  */
@@ -422,10 +563,11 @@ public ClientsFile getStoreDocFile() {
   }
   return storedocfile;
 }
-SessionFileWatcherElement clistWatchElement=null;
-public SessionFileWatcherElement getClientWatcherElement() {
+
+ClientSessionFileWatcherElement clistWatchElement=null;
+public ClientSessionFileWatcherElement getClientWatcherElement() {
   if (clistWatchElement==null) {
-    clistWatchElement=new SessionFileWatcherElement(clist,null);
+    clistWatchElement=new ClientSessionFileWatcherElement(clist,null);
   }
   return clistWatchElement;
 }