added SimpleClientFactory implementation and new class SessionsFile to deal with...
authorpmarguerite <pmarguerite@issues.jalview.org>
Thu, 14 Dec 2006 16:19:27 +0000 (16:19 +0000)
committerpmarguerite <pmarguerite@issues.jalview.org>
Thu, 14 Dec 2006 16:19:27 +0000 (16:19 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@258 be28352e-c001-0410-b1a7-c7978e42abec

src/org/vamsas/client/simpleclient/SessionsFile.java [new file with mode: 0644]
src/org/vamsas/client/simpleclient/SimpleClientFactory.java

diff --git a/src/org/vamsas/client/simpleclient/SessionsFile.java b/src/org/vamsas/client/simpleclient/SessionsFile.java
new file mode 100644 (file)
index 0000000..eb80f45
--- /dev/null
@@ -0,0 +1,342 @@
+/* EMBL - The European Bioinformatics institute
+* MSD Group
+* VAMSAS Project
+*
+*  Copyright (c) 2005-2006 Thr European Bioinformatics Institute. All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*  
+*   1. Redistributions of source code must retain the above copyright
+*      notice, this list of conditions and the following disclaimer. 
+*  
+*   2. Redistributions in binary form must reproduce the above copyright
+*      notice, this list of conditions and the following disclaimer in
+*      the documentation and/or other materials provided with the
+*      distribution.
+*  
+*   3. The name MSD must not be used to endorse or promote products 
+*      derived from this software without prior written permission. For 
+*      written permission, please contact msd-help@ebi.ac.uk
+*  
+*   4. Products derived from this software may not be called "MSD"
+*      nor may "MSD" appear in their names without prior written
+*      permission of the MSD developers.
+*  
+*   5. Redistributions of any form whatsoever must retain the following
+*      acknowledgment:
+*      "This product includes software developed by MSD 
+*       (http://www.ebi.ac.uk/)"
+*  
+*   THIS SOFTWARE IS PROVIDED BY THE MSD GROUP ``AS IS'' AND ANY
+*   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+*   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+*   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ENSEMBL GROUP OR
+*   ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+*   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+*   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+*   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+*   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+*   OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+* The European Bioinformatics Institute may publish revised and/or new
+* versions of this license with new releases of VAMSAS software.
+*==============================================================================
+*
+*  @author <a href="mailto:pierre@ebi.ac.uk">Pierre MARGUERITE</a>
+* 
+* Dec 13, 2006  - VamsasClientV4
+*
+*/
+package org.vamsas.client.simpleclient;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.vamsas.client.SessionHandle;
+
+/**
+ * @author <a href="mailto:pierre@ebi.ac.uk">Pierre MARGUERITE</a>
+ * 
+ * 
+ */
+public class SessionsFile extends ListFile {
+  
+  private static Log log = LogFactory.getLog(SessionsFile.class);
+  /**
+   * when set true - get FileNotFoundExceptions on WinXP when writing to locked stream after the backup has been made (via the backupFile method)
+   */
+  boolean backup=false;
+  /**
+   * number of my session in list - passed back when a session 
+   * is added to list, and used (if valid) for quickly 
+   * looking up presence of session handle in the list.
+   */
+  private int syncnum = 1;
+  /**
+   * @param file
+   */
+  public SessionsFile(File file) throws java.io.IOException {
+    super(file);
+  }
+  
+  
+  /**
+   * internal method for getting sessionsList - ensures a lock has been made but
+   * does not release it.
+   * 
+   * @return list of clients
+   */
+  private SessionHandle[] retrieveSessionHandles() {
+    if (lockFile()) {
+      try {
+        SessionHandle[] clients=null;
+        if (this.fileLock.length()>0) {
+          
+          ObjectInputStream is = new ObjectInputStream(this.fileLock.getBufferedInputStream(true));
+          Object o;
+          o=is.readObject();
+          if (o!=null) {
+            try {
+              clients = (SessionHandle[]) o;
+            }
+            catch (Exception e) {
+              log.error("Garbage in the clientHandle list "+this.sessionFile,e);
+            }
+          }
+        }
+        return clients;
+      } catch (FileNotFoundException e) {
+       // e.printStackTrace(System.err);
+        log.error(e);
+      } catch (Exception e) {
+        log.error(e);
+        //e.printStackTrace(System.err);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * get the SessionsList from the file. May return null if lock failed!
+   * @return sessionsList
+   */
+  public SessionHandle[] retrieveSessionsList() {
+    if (lockFile()) {
+      SessionHandle[] clients = retrieveSessionHandles();
+      unlockFile();
+      return clients;
+    }
+    return null;
+  }
+
+  /**
+   * get list from the locked ClientList.
+   * @param extantlock
+   * @return clientList or null if lock failed (or file was empty)
+   */
+  public SessionHandle[] retrieveSessionsList(Lock extantlock) {
+    if (lockFile(extantlock)) {
+     SessionHandle[] clients = retrieveSessionHandles();
+      unlockFile();
+      return clients;
+    }
+    return null;
+  }
+  
+  /**
+   * adds clientHandle me to the clientList under an existing lock extantLock.
+   * @param me
+   * @param extantLock
+   * @return client index in list or 0 if lock was invalid or addClient operation failed.
+   */
+  public int addSession(SessionHandle me, Lock extantLock) {
+    return addSession(me, true, extantLock);
+  }
+  
+  /**
+   * adds SessionsHandle me to the sessionsList under an existing lock.
+   * @param me - sessionsHandle
+   * @param disambig - if true then add will fail if an identical clientHandle already exists
+   * @param extantLock - existing lock
+   * @return client index in list or 0 if addClient (or the lock) failed.
+   */
+  
+  public int addSession(SessionHandle session, boolean disambig, Lock extantLock) {
+    if (lockFile(extantLock)) {
+      this.syncnum = addSession(session, disambig);
+      unlockFile();
+      return this.syncnum;
+    }
+    return 0;
+  }
+  
+  /**
+   * removes the current session from the  SessionsList without complaint if the session isn't in the sessionsList already.
+   * @param me client handle to be removed
+   * @param clientlock existing lock passed from watcher.
+   */
+  public void removeSession(SessionHandle session, Lock clientlock) {
+    int mynum =-1;
+    if (lockFile(clientlock)) {
+      SessionHandle[] sessions = retrieveSessionHandles();
+      if (sessions != null) {
+        if ((this.syncnum<=0 || this.syncnum>sessions.length) || sessions[this.syncnum-1]!=session) {
+          for (int i = 0, j = sessions.length; i < j; i++) 
+            if (sessions[i].equals(session)) {
+              mynum=i;
+              break;
+            }
+        } else {
+          mynum=this.syncnum-1;
+        }
+        if (mynum>-1) {
+          SessionHandle[] newlist = new SessionHandle[sessions.length - 1];
+          for (int k=0,i = 0, j = sessions.length; i < j; i++)
+            if (i!=mynum)
+              newlist[k++] = sessions[i];
+          if (!putSessionsList(newlist))
+            throw new Error("Failed to write new sessionsList!"); // failed to put the sessionList to disk.
+        }
+      }
+      unlockFile();
+    } else {
+      throw new Error("Couldn't get lock for "+((sessionFile==null) ? "Unitialised sessionFile in SessionsFile" : this.sessionFile.getAbsolutePath()));
+    }
+  }
+  /**
+   * Adds a SessionHandle to the SessionList file - optionally disambiguating 
+   * the SessionHandle (modifes the URN). 
+   * Note: Caller is left to release the lock on the SessionList.
+   * @param me
+   * @param disambiguate -
+   *          flag indicating if the URN for me should be disambiguated to
+   *          differentiate between sessions.
+   * @return index of sessionHandle in new list, or -1-position of existing
+   *         sessionHandle (if disambiguate is true)
+   */
+  protected int addSession(SessionHandle session, boolean disambiguate) {
+    int newsession = 0;
+    int tries=5;
+    while (tries-->0 && !lockFile())
+      try { Thread.sleep(1); } catch (Exception e){};
+    if (lockFile()) {
+      SessionHandle[] sessions = retrieveSessionHandles();
+
+      if (sessions == null) {
+        sessions = new SessionHandle[1];
+        sessions[0] = session;
+        newsession = 1;
+      } else {
+        int k = 0;
+        for (int i = 0, j = sessions.length; i < j; i++) {
+          if ( sessions[i].equals(session)) {
+            if (disambiguate) {
+              while (sessions[i].equals(session)) {
+               // me.setClientUrn(me.getClientUrn() + k++); // TODO: make a better
+                                                          // disambiguation of
+                                                          // urn.
+              }
+            } else {
+              // will not write the ambiguous clientHandle to disk, just return
+              // its index.
+              return -1 - i;
+            }
+          }
+        }
+        int i, j;
+        SessionHandle[] newlist = new SessionHandle[sessions.length + 1];
+        for (i = 0, j = sessions.length; i < j; i++)
+          newlist[i] = sessions[i];
+        newlist[j] = session;
+        sessions = newlist;
+        newsession = j+1;
+      }
+      if (!putSessionsList(sessions))
+        return 0; // failed to put the clientList to disk.
+    }
+    return newsession;
+  }
+  
+  
+  /**
+   * safely writes sessions array to the file referred to by sessionFile.
+   * 
+   * @param clients
+   * @return true if successful write. Throws Errors otherwise.
+   */
+  protected boolean putSessionsList(SessionHandle[] clients) {
+    if (lockFile()) {
+      File templist=null;
+      if (!this.backup || (templist = backupSessionFile()) != null) {
+        int retries=3;
+        while (retries-->0) {
+          try {
+            ObjectOutputStream os = 
+              new ObjectOutputStream(this.fileLock.getBufferedOutputStream(true));
+            log.debug("About to write "+clients.length+" sessionHandles to output stream.");
+            os.writeObject(clients);
+            os.close();
+          // All done - remove the backup.
+          if (this.backup)
+            templist.delete();
+          templist = null;
+          retries=-1;
+          } catch (Exception e) {
+           // System.err
+            //.println("Serious - problems writing to sessionFile.");
+            log.error("Serious - problems writing to sessionFile.",e);
+            if (retries>0 && templist != null) {
+            //  System.err.println("Recovering from Backup in "
+              //        + templist.getAbsolutePath());
+              log.error("Recovering from Backup in "+ templist.getAbsolutePath());
+              templist.renameTo(this.fileLock.target);
+            }
+            //e.printStackTrace(System.err);
+            log.error(e);
+          }
+        }
+        if (retries>-2) {
+         // System.err
+         // .println("Serious - problems writing to sessionFile. Giving Up.");
+          log.error("Serious - problems writing to sessionFile. Giving Up.");
+          return false;
+        }
+      } else {
+        throw new Error(
+            "Couldn't create backup of the clientList before writing to it!");
+      }
+    } else {
+      throw new Error("Could not lock the clientList: "
+          + ((this.sessionFile == null) ? "Unitialized ClientsFile"
+              : " failed to get lock on " + this.sessionFile.getAbsolutePath()));
+    }
+    // successful!
+    return true;
+  }
+
+  public void clearList() {
+    if (lockFile()) {
+      try {
+        FileOutputStream fout = this.fileLock.getFileOutputStream(true);
+        fout.flush();
+        fout.close();
+      } catch (Exception e) {
+        throw new Error("Problems trying to clear clientlist!",e);
+        
+      }
+    }
+    
+  }
+}
index 640ad78..6f5509a 100644 (file)
+/*
+* VAMSAS Project
+*
+
+* 
+* Dec 13, 2006 
+*
+*/
 package org.vamsas.client.simpleclient;
 
 import java.io.File;
+
 import java.io.IOException;
 
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.vamsas.client.ClientHandle;
 import org.vamsas.client.IClient;
 import org.vamsas.client.IClientFactory;
+import org.vamsas.client.InvalidSessionUrnException;
 import org.vamsas.client.NoDefaultSessionException;
+import org.vamsas.client.SessionHandle;
 import org.vamsas.client.UserHandle;
 
 /**
- * TODO document type SimpleClientFactory
- * @author jimp
- *
+ * 
+ * 
  */
 public class SimpleClientFactory implements IClientFactory {
+
   private static Log log = LogFactory.getLog(SimpleClientFactory.class);
 
-  File sessionArena;
+  private File sessionArena = null;
+  
+  private String vamsasSubdirectoryName = ".vamsas";
+  
+  private SessionsFile sessionFile = null;
+  private static final String SESSION_LIST="sessions.obj";
+  
+  //private   String[] currentlyAvailableDessions = null; 
   
   /**
    * default constructor - called by CreateClientFactory only.
    *
+   *Inits the sessionarena to the directory .vamsas of the user home directory. 
+   *
    */
-  public SimpleClientFactory() {
-    sessionArena = null;
+  public SimpleClientFactory() throws IOException
+  {
+   // sessionArena
+    
+    //retrieves user home directory
+    String userHomeDirectory = System.getProperty("user.home");
+    if (userHomeDirectory == null || userHomeDirectory.length()<1)
+      {
+        new IOException("Unable to detect user home directory");
+      }
+    String sessionArenaPath =  userHomeDirectory.concat(File.separator.concat(this.vamsasSubdirectoryName));
+    
+    this.initSessionArena(sessionArenaPath);
+    this.initFactoryObjects();
   }
+  
+  
   /**
    * Create a client factory that works with sessions at the given
    * path.
-   * @param path
+   * @param path path to directory called  session arena, where will be created session directories and session files.
    */
-  public SimpleClientFactory(String path) throws IOException {
+  public SimpleClientFactory(String path) throws IOException
+  {
+    this.initSessionArena(path);
+  }
+  /**
+   * Inits sessionArena to a given path.
+   * checks if path is valid.
+   * 
+   * @param path path to a directory to use 
+   * @throws IOException if the path is incorrect
+   */
+  private void  initSessionArena (String path) throws IOException
+  {
     // Check path is valid and read/writeable.
-    File newarena = new File(path);
-    if (newarena.isDirectory() && newarena.canRead() && newarena.canWrite()) {
-      sessionArena = newarena;
-    } else {
-      sessionArena = null;
-      throw(new IOException("Cannot read and write to a directory called "+path));
+    File arenaFile = new File (path);
+    if (!arenaFile.exists())
+    {
+      if (! arenaFile.mkdirs())
+      {
+        this.sessionArena = null;
+        throw(new IOException("Unable to create a directory called "+path));
+      }
     }
+    if (arenaFile.exists() && arenaFile.isDirectory() && arenaFile.canRead() && arenaFile.canWrite()) 
+      {
+        this.sessionArena = arenaFile;
+      } 
+    else
+      {
+      this.sessionArena = null;
+        throw(new IOException("Cannot read and write to a directory called "+path));
+      }
   }
   
-  /* (non-Javadoc)
+  /**
+   * construct SessionFile objects and watchers for each
+   */
+  private void initFactoryObjects() throws IOException {
+    if (this.sessionFile!=null )
+      throw new IOException("initFactoryObjects called for initialised ClientFactory object.");
+    this.sessionFile = new SessionsFile(new File(this.sessionArena,SESSION_LIST));
+
+  }
+  /**
    * @see org.vamsas.client.IClientFactory#getCurrentSessions()
    */
-  public String[] getCurrentSessions() {
-    // TODO look in the arena and enumerate session handles for return.
-    return new String[] {};
+  public String[] getCurrentSessions() 
+  { 
+    String[] sessions = null;
+    if (this.sessionFile!=null )
+      {
+        SessionHandle[] sessionHandles =  this.sessionFile.retrieveSessionsList();
+        if (sessionHandles != null)
+          {
+            sessions = new String[sessionHandles.length];
+            for (int i = sessionHandles.length -1; i > 0; i--)
+              {
+                SessionHandle sessionHandle = sessionHandles[i];
+                sessions [i] = sessionHandle.getSessionUrn();
+              }
+          }
+      }
+    return sessions;
   }
-  /* (non-Javadoc)
+  
+  
+  private void discoverSession()
+  {
+   
+  }
+
+  /**
    * @see org.vamsas.client.IClientFactory#getIClient(org.vamsas.client.ClientHandle)
+   * 
+   * Creates a IClient object, using default UserHandle with system variables:"user.name" or "USERNAME")),
+            "host.name" or "HOSTNAME" 
    */
-  public IClient getIClient(ClientHandle applicationHandle) throws NoDefaultSessionException {
-    // create a new session
-    // register new ClientHandle in session
-    // create SimpleClient instance
-    return null;
+  public IClient getIClient(ClientHandle applicationHandle)
+      throws NoDefaultSessionException {
+    
+    return this.getIClient(applicationHandle, (UserHandle) null);
   }
 
-  /* (non-Javadoc)
+  /**
    * @see org.vamsas.client.IClientFactory#getIClient(org.vamsas.client.ClientHandle, java.lang.String)
    */
   public IClient getIClient(ClientHandle applicationHandle, String sessionUrn) {
-    // locate session from Urn
-    // check that clientHandle is unique (with default user) - if not update the clientHandle urn to make it unique.
-    // wait for lock and attach to session
-    // create SimpleClient instance
+    // TODO Auto-generated method stub
     return null;
   }
 
-  /* (non-Javadoc)
+  /**
    * @see org.vamsas.client.IClientFactory#getIClient(org.vamsas.client.ClientHandle, org.vamsas.client.UserHandle, java.lang.String)
    */
   public IClient getIClient(ClientHandle applicationHandle, UserHandle userId,
       String sessionUrn) {
-    // locate session from Urn
-    // check Uniqueness of user + ClientHandle in the session. Update clientHandle urn accordingly.
-    // wait for lock, attach to session
-    // create client instance
+    // TODO Auto-generated method stub
     return null;
   }
 
-  /* (non-Javadoc)
+  /**
    * @see org.vamsas.client.IClientFactory#getIClient(org.vamsas.client.ClientHandle, org.vamsas.client.UserHandle)
    */
-  public IClient getIClient(ClientHandle applicationHandle, UserHandle userId) throws NoDefaultSessionException {
-    // create new session
-    // register SimpleClient and UserHandles in session
-    // create client instance
-    return null;
+  public IClient getIClient(ClientHandle applicationHandle, UserHandle userId)
+      throws NoDefaultSessionException {
+    SimpleClient client = null;
+    if (this.sessionArena==null)
+      throw new Error("Improperly initialised SimpleClientFactory object - null sessionArena.");
+    
+    ClientHandle clientHandle =applicationHandle;
+    //create default clientHandle with "SimpleVamsasClientApp","0.1",
+    if (clientHandle == null)
+     clientHandle = new ClientHandle("SimpleVamsasClientApp","0.1");
+    
+    //check if any available session(s)
+    String[] availableSessions = this.getCurrentSessions();
+    if (availableSessions != null) 
+      {//there are available sessions
+        if (availableSessions.length>1)
+          {//more than one session if available... can not choose
+          
+          //represents list of session as String
+            StringBuffer sessionURNs = new StringBuffer("");
+            for (int i = 0; i< availableSessions.length ; i++)
+              {
+                sessionURNs.append(availableSessions[i]+" ");
+              }
+            throw new  NoDefaultSessionException("Several sessions available, please pick one: "+sessionURNs);
+          }
+      
+        //check if only one session available. if yes, open it
+        if (availableSessions.length == 1)
+          {
+          //only one session available, open it.
+            return this.getIClient(clientHandle,  availableSessions[0]);
+          }
+      }
+    //no session available  - create a new one
+    
+    
+    try 
+      {
+        //create sessionDirectory
+        File sessdir = File.createTempFile("sess", ".simpleclient", this.sessionArena);
+        log.debug("Creating new session  directory");
+       if (!(sessdir.delete() && sessdir.mkdir()))
+          throw new IOException("Could not make session directory "+sessdir);
+      //create session
+        VamsasSession vamsasSession = new VamsasSession(sessdir);
+      
+        this.getSessionFile().addSession(new SessionHandle(new SessionUrn(vamsasSession).getSessionUrn()), false);
+        if (userId == null)
+          {
+      //create a default userHandle
+      //with current OS user and hostname
+            userId = new UserHandle(System.getProperty("user.name", System.getProperty("USERNAME","Joe Doe")),
+              System.getProperty("host.name",System.getProperty("HOSTNAME", "Unknown") ));// clientName, clientVersion,  sessionPath);
+          }
+     
+      
+      //create simple client
+         client = new SimpleClient(userId,  clientHandle,  vamsasSession);
+      } 
+    catch (IOException e) 
+      {
+        log.error("error while creating new IClient",e);
+      }
+    catch (InvalidSessionUrnException e) 
+      {
+        log.error("Unable to create new IClient. The session urn is incorrect ",e);
+      }
+   
+      return client;
   }
+
+
   /**
-   * make a new vamsas session from the data in the archive vamsasdocument 
-   * @param applicationHandle
-   * @param userId
-   * @param vamsasdocument
-   * @return
+   * @return the sessionFile
    */
-  public IClient openSession(ClientHandle applicationHandle, UserHandle userId, ArchiveUrn vamsasdocument) throws IOException {
-    // verify applicationHandle and userId
-    // TODO: verify applicationHandle and userId
-    // verify vamsasdocument is a valid document.
-    File vamdoc = vamsasdocument.asFile();
-    log.debug("Starting new session with data from "+vamsasdocument.getSessionUrn()+"(File is : "+vamdoc+")");
-    VamsasArchiveReader archive = new VamsasArchiveReader(vamdoc);
-    // TODO: a real validity test. The below just checks it can be read.
-    if (!archive.isValid())
-      throw new IOException(vamsasdocument.getSessionUrn()+" is not a valid vamsasDocument archive.");
-    // create new session directory
-    if (sessionArena==null)
-      throw new Error("Improperly initialised SimpleClientFactory object - null sessionArena.");
-    File sessdir = File.createTempFile("sess", ".simpleclient", sessionArena);
-    if (!(sessdir.delete() && sessdir.mkdir()))
-        throw new IOException("Could not make session directory "+sessdir);
-    VamsasSession sess = new VamsasSession(sessdir);
-    // copy document into session directory
-    sess.setVamsasDocument(vamsasdocument.asFile());
-    // create client instance and return.
-    SimpleClient client=null;
-    try {
-      client = new SimpleClient(userId, applicationHandle, sess);
-    } catch (Exception e) {
-      log.error("Couldn't make a new SimpleClient instance.",e);
-      throw new IOException(e.getMessage());
+  private SessionsFile getSessionFile()  throws IOException
+    {
+      if (this.sessionFile == null)
+        {
+          this.sessionFile = new SessionsFile( new File (this.sessionArena, SESSION_LIST));
+        }
+      return this.sessionFile;
     }
-    return client;
-  }
+
   
-  public static void main(String[] args) {
-  }
+
 }