d33f2f8f123b90e92f9cd41cec300e956f663068
[vamsas.git] / src / org / vamsas / client / simpleclient / SessionFile.java
1 package org.vamsas.client.simpleclient;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10
11 /**
12  * Basic methods for classes handling locked IO on files 
13  * monitored by all (simpleclient) clients in a vamsas session.
14  * @author jimp
15  *TODO: support non nio file locking capable systems
16  */
17 public class SessionFile {
18   private static Log log = LogFactory.getLog(SessionFile.class);
19   protected File sessionFile;
20   protected Lock fileLock = null;
21
22   protected SessionFile(File file) {
23     super();
24     sessionFile = file;
25   }
26
27   protected boolean lockFile(Lock extantlock) {
28     if (fileLock!=null && !fileLock.isLocked()) {
29       fileLock.release();// tidy up invalid lock
30       fileLock=null;
31     }
32     if (extantlock!=null)
33       fileLock=extantlock;
34     return lockFile();
35   }
36
37   /**
38    * Get a lock for the SessionFile
39    * 
40    * @return true if lock was made
41    */
42   protected boolean lockFile() {
43     if (fileLock != null)
44       if (fileLock.isLocked())
45         return true;
46       else 
47         // lock failed for some reason.
48         fileLock.release();
49     fileLock = null;
50     if (sessionFile != null) {
51       if (!sessionFile.exists()) {
52         // create new file
53         try {
54           if (!sessionFile.createNewFile()) {
55             log.error("Failed to create file prior to locking: "+sessionFile);
56             return false;
57           }
58         } catch (IOException e) {
59           log.error("Exception when trying to create file "+sessionFile, e);
60           return false;
61         }
62       }
63       // TODO: see if we need to loop-wait for locks or they just block until
64       // lock is made...
65       long tries=500;
66       do {
67         tries--;
68         if (fileLock!=null && !fileLock.isLocked())
69           fileLock.release();
70           fileLock = new Lock(sessionFile); // TODO: wait around if we can't get the lock.
71       } while (tries>0 && !fileLock.isLocked());
72       if (!fileLock.isLocked())
73         log.error("Failed to get lock for "+sessionFile);
74       // fileLock = new Lock(sessionFile);
75       return fileLock.isLocked();    
76     } else
77       log.error("lockFile called for non-initialised SessionFile!");
78   
79     // no lock possible
80     return false;
81   }
82
83   /**
84    * Explicitly release the SessionFile's lock.
85    * 
86    * @return true if lock was released.
87    */
88   protected void unlockFile() {
89     if (fileLock != null) {
90       fileLock.release();    
91       fileLock = null;
92     }
93   }
94
95   /**
96    * Makes a backup of the sessionFile.
97    * @return Backed up SessionFile or null if failed to make backup.
98    */
99   protected File backupSessionFile() {
100     return backupSessionFile(null, sessionFile.getName(),".old", sessionFile.getParentFile());
101   }
102
103   protected File backupSessionFile(Lock extantLock, String backupPrefix, String backupSuffix, File backupDir) {
104     File tempfile=null;
105     if (lockFile(extantLock)) {
106       try {
107         tempfile = File.createTempFile(backupPrefix, backupSuffix, backupDir);
108         FileOutputStream tos = new FileOutputStream(tempfile);
109         tos.getChannel().transferFrom(fileLock.rafile.getChannel(), 0,
110             fileLock.rafile.length());
111         tos.close();
112       } catch (FileNotFoundException e1) {
113         log.warn("Can't create temp file for "+sessionFile.getName(),e1);
114         tempfile=null;
115       } catch (IOException e1) {
116         log.warn("Error when copying content to temp file for "+sessionFile.getName(),e1);
117         tempfile=null;
118       }
119     }
120     return tempfile;
121   }
122   /**
123    * Replaces data in sessionFile with data from file handled by another sessionFile
124    * passes up any exceptions.
125    * @param newData source for new data
126    */
127   protected void updateFrom(Lock extantLock, SessionFile newData) throws IOException {
128     log.debug("Updating "+sessionFile.getAbsolutePath()+" from "+newData.sessionFile.getAbsolutePath());
129     if (newData==null)
130       throw new IOException("Null newData object.");
131     if (newData.sessionFile==null)
132       throw new IOException("Null SessionFile in newData.");
133       
134     lockFile(extantLock);  
135     newData.lockFile();
136     fileLock.rafile.getChannel().transferFrom(newData.fileLock.rafile.getChannel(), 0, 
137         newData.fileLock.rafile.length());
138   }
139   /**
140    * remove all trace of the sessionFile file
141    *
142    */
143   protected void eraseExistence() {
144     unlockFile();
145     if (sessionFile!=null) {
146       sessionFile.delete();
147       sessionFile = null;
148     }
149   }
150 }