fixed regex to remove all kinds of file separators ('\' must be escaped correctly)
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / SimpleClient.java
index 677094c..9cbdcb7 100644 (file)
@@ -6,14 +6,14 @@
  */
 package uk.ac.vamsas.client.simpleclient;
 
-import java.beans.EventHandler;
-import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
-import java.net.MalformedURLException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
+import java.nio.channels.OverlappingFileLockException;
 import java.util.Hashtable;
 import java.util.Vector;
 
@@ -29,13 +29,9 @@ import uk.ac.vamsas.client.InvalidSessionUrnException;
 import uk.ac.vamsas.client.SessionHandle;
 import uk.ac.vamsas.client.UserHandle;
 import uk.ac.vamsas.client.picking.IPickManager;
-import uk.ac.vamsas.objects.core.ApplicationData;
 import uk.ac.vamsas.objects.core.Entry;
-import uk.ac.vamsas.objects.core.LockFile;
 import uk.ac.vamsas.objects.core.VamsasDocument;
-import uk.ac.vamsas.objects.utils.AppDataReference;
 import uk.ac.vamsas.objects.utils.ProvenanceStuff;
-import uk.ac.vamsas.objects.utils.document.VersionEntries;
 
 /**
  * @author jimp
@@ -51,6 +47,15 @@ public class SimpleClient implements IClient {
   protected ClientHandle client = null;
   protected EventGeneratorThread evgen = null;
   protected ClientDocument cdocument = null;
+  
+  
+  
+  
+  private java.nio.channels.FileLock activeClientFilelock = null;
+  
+  private FileChannel activeClientFileChannel = null;
+  private  File clientlockFile = null;
+  
   /**
    * object hash table that persists in each client holding vorbaIds and hash values after a document write
    */
@@ -61,7 +66,9 @@ public class SimpleClient implements IClient {
    * @return
    */
   private IdFactory makeVorbaIdFactory() {
-    return new IdFactory(getSessionHandle(), client, user);
+    if (extantobjects==null)
+      extantobjects=new Hashtable();
+    return new IdFactory(getSessionHandle(), client, user, extantobjects);
   }
   
   /**
@@ -211,7 +218,7 @@ public class SimpleClient implements IClient {
       new Thread() {
         public void run() {
           SimpleClient.log.debug("Stopping pickManager..");
-          dying.pickmanager.haltPickManager();
+          dying.pickmanager.shutdown();
           SimpleClient.log.debug("pickManager halted.");
         }
       }.start();
@@ -236,12 +243,15 @@ public class SimpleClient implements IClient {
     // if (handlers.containsKey(Events.))
     // if (handlers.containsKey(Events.CLIENT_FINALIZATION))
     // deregister listeners.
+    log.debug("Stopping pickManager");
     haltPickmanager();
-    SimpleClient.log.debug("Stopping EventGenerator..");
-    evgen.stopWatching();
-    SimpleClient.log.debug("EventGenerator halted.");
+    
     log.debug("Deregistering Client");
     _session.removeClient(this);
+    //log.debug("Stopping EventGenerator..");
+    //evgen.stopWatching();
+    SimpleClient.log.debug("EventGenerator halted.");
+    this.cdocument = null;
     log.debug("finalization Complete.");
   }
   
@@ -315,12 +325,14 @@ public class SimpleClient implements IClient {
         log.debug("updateDocument for "+session.getSessionUrn()+" with unmodified IClientDocument (skipping the write)");
     } else {
       try {
-        if (!cdocument.updateSessionDocument()) {
+        boolean updated=cdocument.updateSessionDocument();
+        if (!updated) {
           log.warn("Session document did not update properly for session directory "+_session.sessionDir);
           // cdocument.archive.cancelArchive(); // LATER: could be done - would need to prevent updateSessionDocument closing the iohandler.
           _session.slog.warn("Session Document updated but may not be valid (false return from org.vamsas.simpleclient.ClientDocument.updateSessionDocument()");
+        } else {
+               log.debug("Document update successful.");
         }
-        log.debug("Document update successful.");
         _session.setUnsavedFlag();
       }
       catch (IOException e) {
@@ -360,11 +372,10 @@ public class SimpleClient implements IClient {
     // Events.DOCUMENT_FINALIZEAPPDATA
     try {
       _session.writeVamsasDocument(location, vamlock);
-      _session.clearUnsavedFlag();
+       _session.clearUnsavedFlag();
     } catch (Exception e) {
       log.warn("Exception whilst trying to store document in "+location,e);
     }
-    
     vamlock.release();
   }
   
@@ -443,7 +454,15 @@ public class SimpleClient implements IClient {
    */
   public void importDocument(File location) {
     // TODO LATER: implement SimpleClient.importDocument()
+    // if (numberOfClients<1 or document file is empty/new, then can import directly.)
+    // more complex if data is already present in document. Could have a 'clearSession' method, too, or dump and overwrite instead.
     log.error("importDocument is not yet implemented for a SimpleClient Session.");
+    
+    /*try {
+      this._session.setVamsasDocument(location);
+    } catch (IOException e) {
+      log.error("importDocument failed.");
+    }*/
   }
 
   public IObjectUpdate getUpdateHandler(Class rootObject) {
@@ -489,4 +508,102 @@ public class SimpleClient implements IClient {
       pickmanager = new SimplePickManager(new uk.ac.vamsas.client.picking.SocketManager());
     }
   }
+  
+  
+  protected void releaseActiveClientFile() throws IOException
+  {
+   
+    log.debug("Releasing active client file");
+    if( activeClientFilelock != null)
+    // Release the lock
+      activeClientFilelock.release();
+          
+    if (activeClientFileChannel != null)
+        // Close the file
+        activeClientFileChannel.close();
+    if (this.clientlockFile != null)
+    {
+      this.clientlockFile.delete();
+      log.debug("deleted active client lock file");
+    }
+
+  }
+  
+  protected void  createActiveClientFile() throws IOException
+  {
+    if(this.clientlockFile != null )return; 
+   log.debug("createActiveClientFile");
+    //create, if need,  subdirectory to contain client files
+   File clientlockFileDir = new File ( this.get_session().sessionDir, this.get_session().clientFileDirectory);
+    if( !clientlockFileDir.exists())
+      {//the directory does not exist, create it
+        if (! clientlockFileDir.mkdirs())
+        {
+          throw new IOException("Failed to create sub directory to session directory  for client lock files'"+clientlockFileDir.getAbsolutePath()+"'");
+        }
+      }
+    else
+    {
+      if (!(clientlockFileDir.isDirectory() && clientlockFileDir.canWrite()))
+      {
+        throw new IOException("Directory  for client lock files is not a directory or is not accessibl: '"+clientlockFileDir.getAbsolutePath()+"'");
+       }
+    }
+    this.clientlockFile = new File (clientlockFileDir, this.getClientHandle().getClientUrn().replaceAll("[:;/\\\\]+",""));
+   
+    log.debug("Creating active client lock file "+ this.clientlockFile.getAbsolutePath());
+    if (clientlockFile.exists())
+     {//should not happen, file should be deleted when the application closes or when a crashed application has been detected
+       log.error("client lock file already exits");
+     }
+   try {
+     //create the empty file
+     if(! clientlockFile.createNewFile())
+       {
+       log.error("Unable to create active client lock file");
+       
+         return;
+       }
+     else
+       log.debug("file created");
+       // Get a file channel for the file
+       FileChannel channel = new RandomAccessFile(clientlockFile, "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
+          {
+           activeClientFilelock = channel.tryLock();
+           log.debug("Got lock");
+          }
+       catch (OverlappingFileLockException e) 
+       {
+         // File is already locked in this thread or virtual machine
+         log.error("Oups the file is already locked",e);
+         
+       }
+     // Release the lock
+ /*    lock.release();
+       
+     // Close the file
+     channel.close();*/
+ } catch (Exception e) {
+   log.error("Error  during lock file creation",e);
+ }
+
+
+    
+  }
+
+  /**
+   * @return the clientlockFile
+   */
+  protected File getClientlockFile() {
+    return clientlockFile;
+  }
 }