/* * This file is part of the Vamsas Client version 0.2. * Copyright 2010 by Jim Procter, Iain Milne, Pierre Marguerite, * Andrew Waterhouse and Dominik Lindner. * * Earlier versions have also been incorporated into Jalview version 2.4 * since 2008, and TOPALi version 2 since 2007. * * The Vamsas Client is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Vamsas Client is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Vamsas Client. If not, see . */ package uk.ac.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 uk.ac.vamsas.client.SessionHandle; import uk.ac.vamsas.client.simpleclient.SimpleSessionHandle; /** * @author Pierre MARGUERITE * * */ 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 SimpleSessionHandle[] retrieveSessionHandles() { if (lockFile()) { try { SimpleSessionHandle[] sessions = null; if (this.fileLock.length() > 0) { ObjectInputStream is = new ObjectInputStream(this.fileLock .getBufferedInputStream(true)); Object o; o = is.readObject(); if (o != null) { try { sessions = (SimpleSessionHandle[]) o; } catch (Exception e) { log.error("Garbage in the clientHandle list " + this.sessionFile, e); } } // is.close(); } return sessions; } 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 SimpleSessionHandle[] retrieveSessionsList() { if (lockFile()) { SimpleSessionHandle[] clients = retrieveSessionHandles(); unlockFile(); return clients; } return null; } /** * get list from the locked SessionsList. * * @param extantlock * @return sessionList or null if lock failed (or file was empty) */ public SimpleSessionHandle[] retrieveSessionsList(Lock extantlock) { if (lockFile(extantlock)) { SimpleSessionHandle[] sessions = retrieveSessionHandles(); unlockFile(); return sessions; } return null; } /** * adds SessionHandle me to the sessionList under an existing lock extantLock. * * @param newSession * @param extantLock * @return session index in list or 0 if lock was invalid or addSession * operation failed. */ public int addSession(SimpleSessionHandle newSession, Lock extantLock) { return addSession(newSession, true, extantLock); } /** * adds SessionsHandle me to the sessionsList under an existing lock. * * @param newSession * - sessionsHandle * @param disambig * - if true then add will fail if an identical sessionHandle already * exists * @param extantLock * - existing lock * @return client index in list or 0 if addSession (or the lock) failed. */ public int addSession(SimpleSessionHandle newSession, boolean disambig, Lock extantLock) { if (lockFile(extantLock)) { this.syncnum = addSession(newSession, 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 session * session handle to be removed * @param sessionlock * existing lock passed from watcher. */ public void removeSession(SessionHandle session, Lock sessionlock) { int mynum = -1; if (lockFile(sessionlock)) { SimpleSessionHandle[] sessions = retrieveSessionHandles(); if (sessions != null) { if ((this.syncnum <= 0 || this.syncnum > sessions.length) || !session.equals(sessions[this.syncnum - 1])) { 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) { SimpleSessionHandle[] newlist = new SimpleSessionHandle[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 " + ((this.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 session * @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(SimpleSessionHandle session, boolean disambiguate) { int newsession = 0; int tries = 5; while (tries-- > 0 && !lockFile()) try { Thread.sleep(1); } catch (Exception e) { } ; if (lockFile()) { SimpleSessionHandle[] sessions = retrieveSessionHandles(); if (sessions == null) { sessions = new SimpleSessionHandle[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; SimpleSessionHandle[] newlist = new SimpleSessionHandle[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(SimpleSessionHandle[] 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.flush(); 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); } } } }