// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.core.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.logging.Logger;
import org.openstreetmap.osmosis.core.OsmosisRuntimeException;
import org.openstreetmap.osmosis.core.lifecycle.Closeable;
/**
* This class provides a mechanism to use simple files as locks to prevent
* multiple threads or processes from updating common files.
*
* @author Brett Henderson
*/
public class FileBasedLock implements Closeable {
private static final Logger LOG = Logger.getLogger(FileBasedLock.class.getName());
private File lockFile;
private FileOutputStream outputStream;
private FileChannel fileChannel;
private FileLock fileLock;
private boolean initialized;
/**
* Creates a new instance.
*
* @param lockFile
* The file to use for locking.
*/
public FileBasedLock(File lockFile) {
this.lockFile = lockFile;
initialized = false;
}
/**
* Creates the file resources used internally for implementing the lock.
*/
private void initialize() {
if (!initialized) {
try {
outputStream = new FileOutputStream(lockFile);
} catch (IOException e) {
throw new OsmosisRuntimeException("Unable to open lock file " + lockFile + ".");
}
fileChannel = outputStream.getChannel();
initialized = true;
}
}
/**
* Obtain an exclusive lock. This will fail if another thread or process
* already has a lock.
*/
public void lock() {
initialize();
if (fileLock != null) {
throw new OsmosisRuntimeException("A lock has already been obtained on file " + lockFile + ".");
}
try {
fileLock = fileChannel.tryLock();
if (fileLock == null) {
throw new OsmosisRuntimeException("A exclusive lock already exists on file " + lockFile + ".");
}
} catch (IOException e) {
throw new OsmosisRuntimeException(
"An error occurred while trying to obtain an exclusive lock on file " + lockFile + ".");
}
}
/**
* Release the lock.
*/
public void unlock() {
initialize();
try {
fileLock.release();
fileLock = null;
} catch (IOException e) {
throw new OsmosisRuntimeException("Unable to release lock on file " + lockFile + ".");
}
}
/**
* {@inheritDoc}
*/
public void close() {
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
LOG.warning("Unable to close lock stream on file " + lockFile + ".");
} finally {
outputStream = null;
fileChannel = null;
fileLock = null;
initialized = false;
}
}
}
}