package er.extensions.eof;
import java.io.File;
import java.io.IOException;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSLocking;
/**
* Simple lock to sync access for multiple instances on one machine. This implementation
* uses a lock file with the given name in the temp directory. In case of a VM crash, the file
* is *not* deleted, so you have to do this yourself.<br>
* Additionally, you can't use it reliably on an NFS server. The lock otherwise behaves like an
* NSRecursiveLock in that the same thread can re-lock as often as he wants.
* <pre><code>
* App1:
* NSLocking lock = ERXGlobalLock.lockForName("test");
* lock.lock();
* ...
* lock.unlock();
* App2:
* NSLocking lock = ERXGlobalLock.lockForName("test");
* lock.lock();
* ...
* lock.unlock();
* </code></pre>
* @author ak
*/
public class ERXGlobalLock implements NSLocking {
private File _lockfile;
private int _lockcnt;
private Thread _owner;
public ERXGlobalLock(String name) {
_lockfile = new File(System.getProperty("java.io.tmpdir") + File.separator + "ERXGlobalLock_" + name);
_lockcnt = 0;
}
public void lock() {
if(_owner == Thread.currentThread() && _lockcnt > 0) {
_lockcnt++;
return;
}
try {
while(!(_lockfile.createNewFile())) {
Thread.sleep(5);
}
} catch (InterruptedException e) {
throw new NSForwardException(e, "Error while locking " + _lockfile);
} catch (IOException e) {
throw new NSForwardException(e, "Error while locking " + _lockfile);
}
_lockfile.deleteOnExit();
_lockcnt++;
_owner = Thread.currentThread();
}
public void unlock() {
if(_lockcnt == 0) {
throw new IllegalStateException("Can't unlock without lock");
}
if(_owner != Thread.currentThread()) {
throw new IllegalStateException("Can't unlock, not owner");
}
_lockcnt--;
if(_lockcnt == 0) {
_owner = null;
if(!_lockfile.delete()) {
throw new IllegalStateException("Error can't delete "+ _lockfile);
}
}
}
/**
* Call this on startup.
*/
public boolean cleanup() {
return _lockfile.delete();
}
public static NSLocking lockForName(String name) {
return new ERXGlobalLock(name);
}
}