X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fuk%2Fac%2Fvamsas%2Fclient%2Fsimpleclient%2FVamsasSession.java;h=2ae181de7da08e4eed3aca7e16694b338d311a1d;hb=b4dc48a6b8be7fa6628bc61599b4678030c4084e;hp=b066f8810d9ef02d068cb2dd20a4238298bb3c5f;hpb=22a4a706dd9c2081f614577235224574bb37fe91;p=vamsas.git diff --git a/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java b/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java index b066f88..2ae181d 100644 --- a/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java +++ b/src/uk/ac/vamsas/client/simpleclient/VamsasSession.java @@ -1,8 +1,11 @@ package uk.ac.vamsas.client.simpleclient; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.OverlappingFileLockException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -13,6 +16,7 @@ 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.SessionHandle; import uk.ac.vamsas.client.UserHandle; /** * Does all the IO operations for a SimpleClient instance accessing @@ -83,13 +87,15 @@ public class VamsasSession { /** * 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 ; + private final int watchCycleCountBeforeLastClient = 1220 ; /** * time between checking */ public int WATCH_SLEEP=30; + protected String clientFileDirectory = "clients"; + /** * called to clear update flag after a successful offline storage event */ @@ -228,7 +234,7 @@ public class VamsasSession { * make a new watcher object for the clientFile * @return new ClientFile watcher instance */ - public FileWatcher getClientWatcher() { + public FileWatcher getClientWatcher() { return new FileWatcher(clist.sessionFile); } /** @@ -359,7 +365,7 @@ public class VamsasSession { * add the client to the client list file * @param client client to add to the session */ - protected void addClient(IClient client) + protected void addClient(SimpleClient client) { if (client == null) slog.error("Try to add a null client to the session "); @@ -367,12 +373,18 @@ public class VamsasSession { log.debug("Adding client "+client.getClientHandle().getClientUrn()); getClientWatcherElement().haltWatch(); clist.addClient(client.getClientHandle()); - getClientWatcherElement().enableWatch(); + log.debug("Added."); log.debug("Register Client as Active."); - + try { + client.createActiveClientFile(); + } catch (IOException e) { + log.debug("Error during active client file creation."); + } //tracks modification to the client list and readds client to the list getClientWatcherElement().setHandler(new AddClientWatchCallBack(client)); + getClientWatcherElement().enableWatch(); + } } @@ -384,13 +396,13 @@ public class VamsasSession { private class AddClientWatchCallBack implements WatcherCallBack { - private IClient client ; + private SimpleClient 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) + protected AddClientWatchCallBack (SimpleClient client) { this.client = client; } @@ -402,9 +414,12 @@ public class VamsasSession { public boolean handleWatchEvent(WatcherElement watcher, Lock lock) { boolean isWatchEnable = watcher.isWatchEnabled(); + if (lock== null)//no update on the list + return isWatchEnable; + log.debug("change on the client list "); if (client != null) { - + //checks if the client is not already in the lists ClientHandle[] cl = clist.retrieveClientList(lock);//clist.retrieveClientList(); @@ -414,16 +429,19 @@ public class VamsasSession { 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); - } + {log.debug("client not in the list "); + if( log.isDebugEnabled()) + log.debug("the client has not been found in the list. Adding it again :"+cl); + addClient(client); + } + else + log.debug("client is in the list"); } - + log.debug("isWatchEnable "+isWatchEnable); return isWatchEnable; } } @@ -435,6 +453,9 @@ public class VamsasSession { * if the client is the last one from the session (ClientList), the current session is removed * from active session list. * + * The active should add them self to the client list. To insure to close the session,when the current client is the lact active client, + * clears the list of clients and when two cycles to insure there is no more active client, that otherwise would have readd themself to the list + * * @param client client to remove */ protected void removeClient(SimpleClient client)//IClient client) @@ -452,32 +473,139 @@ public class VamsasSession { //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().setHandler(new RemoveClientWatchCallBack (client)); getClientWatcherElement().setTimeoutBeforeLastCycle(this.watchCycleCountBeforeLastClient); log.info("remove client from list"); clist.clearList(); + log.info("list cleared"); 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"); - log.debug("last client removed: removing session"); - this.getSessionManager().removeSession(client.getSessionHandle()); + + + log.debug("Stopping EventGenerator.."); + client.evgen.stopWatching(); + cwe.setHandler(null); + + // ask to the client to copy application data into the document + client.evgen._raise(Events.DOCUMENT_FINALIZEAPPDATA, null, client,null); + boolean closeSession=isLastActiveClient(client); + if (closeSession) + { + log.debug("Raising request-to-save event"); + client.evgen._raise(Events.DOCUMENT_REQUESTTOCLOSE, null, client, null); + client.evgen._raise(Events.SESSION_SHUTDOWN, null, client.getSessionHandle(), null); } - else + try + { + log.debug("Attempting to release active client locks"); + client.releaseActiveClientFile(); + } + catch (IOException e) + { + log.error("error during active file client release"); + } + if (closeSession) { - int active=clist.retrieveClientList().length; - log.debug("Still "+active+" active clients"); - slog.info("Still "+active+" active clients"); - }*/ - + log.debug("Last active client: closing session"); + log.info("Closing session"); + getSessionManager().removeSession(client.getSessionHandle()); + } + } } + + private boolean isLastActiveClient(SimpleClient client) + { + log.debug("Testing if current client is the last one."); + log.debug("current client lockfile is '"+client.getClientlockFile()+"'"); + boolean noOtherActiveClient = true; + //create, if need, subdirectory to contain client files + File clientlockFileDir = new File (this.sessionDir, clientFileDirectory); + if( !clientlockFileDir.exists()) + { + log.error("Something wrong the active client file does not exits... should not happen"); + return false; + } + + try { + + //no check every file in the directory and try to get lock on it. + File [] clientFiles = clientlockFileDir.listFiles(); + if(clientFiles == null || clientFiles.length==0) + {//there is not file on the directory. the current client should be the last one. + return true; + } + + for (int i = clientFiles.length - 1; i>-1&& noOtherActiveClient ;i--) + { + File clientFile = clientFiles[i]; + log.debug("testing file for lock: "+clientFile.getAbsolutePath()); + if(client.getClientLock().isTargetLockFile(clientFile)) + { + log.debug("current client file found"); + continue; + } + if (clientFile != null && clientFile.exists() ) + { + try + { + log.debug("Try to acquire a lock on the file"); + // Get a file channel for the file + FileChannel channel = new RandomAccessFile(clientFile, "rw").getChannel(); + + // Use the file channel to create a lock on the file. + // This method blocks until it can retrieve the lock. + // java.nio.channels.FileLock activeClientFilelock = channel.lock(); + + // Try acquiring the lock without blocking. This method returns + // null or throws an exception if the file is already locked. + try + { + java.nio.channels.FileLock activeClientFilelock = channel.tryLock(); + + //the lock has been acquired. + //the file was not lock and so the corresponding application seems to have die + if(activeClientFilelock != null) + { + log.debug("lock obtained : file must be from a crashed application"); + + + activeClientFilelock.release(); + log.debug("lock released"); + + channel.close(); + log.debug("channel closed"); + + //delete file + clientFile.delete(); + log.debug("crashed application file deleted"); + + } + else + { + noOtherActiveClient = false; + log.debug("lock not obtained : another application is active"); + } + } + catch (OverlappingFileLockException e) + { + // File is already locked in this thread or virtual machine + //that the expected behaviour + log.debug("lock not accessible ",e); + } + } + catch (Exception e) + { + log.debug("error during lock testing ",e); + } + } + } + + } catch (Exception e) { + log.error("error during counting active clients"); + } + return noOtherActiveClient; + } /** * Handler for the client watcher. after a client have been removed * @@ -489,7 +617,7 @@ public class VamsasSession { { private SimpleClient client ; - + private boolean manualCheckOfClientCount = false; /** *Inits the handler with the client to check in the list * @param client client to monitor in the client list @@ -504,47 +632,85 @@ public class VamsasSession { * @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 lock is null, no client has been added since last, clear. + //the client is then the last client if (client != null) { + + if (lock == 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); + // ClientHandle[] cl = clist.retrieveClientList();//lock);//clist.retrieveClientList(); - if(cl == null || cl.length<1 ) - {//no client has registered as active + boolean islastClient = true; + if (manualCheckOfClientCount) + { + log.debug("manual checking of count of client"); + //checks if the client is not already in the lists + ClientHandle[] cl = clist.retrieveClientList();//lock);//clist.retrieveClientList(); + if(cl == null || cl.length<1 ) + // {//no client has registered as active + { + islastClient = true; + log.debug("list is empty"); + } + else + islastClient = false; + log.debug("list is not empty"); + } + // if(cl == null || cl.length<1 ) + // {//no client has registered as active + if (islastClient) + { //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"); - } + closeSession(client); + } + } 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(); - - + // / } + } + log.debug("Stopping EventGenerator.."); + // TODO: ensure ClientsFile lock is really released!! clist.unlockFile(); + client.evgen.stopWatching(); + } watcher.setHandler(null);//Do not check if the client is the last client. watcher will shutdown anyway - + // watcher.haltWatch(); + // watcher. return false; } } + /** + * closes the current session, + * and send an event to the last client to close the document + * @param client the last client of the client + */ + private void closeSession(SimpleClient client) + { +// close document + client.evgen._raise(Events.DOCUMENT_REQUESTTOCLOSE, null, client,null); + log.debug("close document request done"); + closeSession(client.getSessionHandle()); + } + + /** + * CLoses the current session + * @param sessionHandle sessionHandle of the session to remove + */ + private void closeSession(SessionHandle sessionHandle) + { + getSessionManager().removeSession(sessionHandle); + log.debug("Session removed"); + } /** * @return the sessionManager */