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