/* 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 Pierre MARGUERITE
*
* Dec 13, 2006 - VamsasClientV4
*
*/
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;
/**
* @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 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);
}
}
}
}