package de.uni_goettingen.sub.commons.ocr.abbyy.server.multiuser;
import java.io.IOException;
import java.util.ConcurrentModificationException;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hazelcast.core.HazelcastInstance;
import de.uni_goettingen.sub.commons.ocr.abbyy.server.LockFileHandler;
import de.uni_goettingen.sub.commons.ocr.abbyy.server.hotfolder.HotfolderProvider;
public class HazelcastLockFileHandler extends LockFileHandler {
private final static Logger logger = LoggerFactory.getLogger(HazelcastLockFileHandler.class);
private HazelcastInstance hazelcast;
// for unit tests
void setProvider(HotfolderProvider newProvider) {
hotfolderProvider = newProvider;
}
public HazelcastLockFileHandler(HazelcastInstance hazelcast) {
this.hazelcast = hazelcast;
}
/**
* Handles the server lock with Hazelcast in mind.
*
*/
@Override
public void createOrOverwriteLock(boolean overwriteLock) {
boolean threwException = false;
// we need to synchronize cluster-wide
Lock monitor = hazelcast.getLock("monitor");
monitor.lock();
try {
if (overwriteLock) {
// the lock is deleted here, but a new one is created later
hotfolder.deleteIfExists(lockUri);
}
// the set is used as a hint for incoming instances that
// it is OK to ignore the lock file on the server
Set<String> lockRegisteringSet = hazelcast.getSet("lockSet");
boolean lockExists = hotfolder.exists(lockUri);
if (!lockExists) {
// no lock file, ie no other processes running, so write it
writeLockFile();
// just add some string so that the next instances can check if it's there.
// "Registering" the external lock inside the current Hazelcast cluster
lockRegisteringSet.add("lockEntry");
} else if (lockExists && !lockRegisteringSet.contains("lockEntry")) {
// there is a lock file, but it is not "registered" in the running cluster
// which means another cluster or program instance is running.
threwException = true;
throw new ConcurrentModificationException("Another client instance is running! See the lock file at " + lockUri);
}
// last case: lock exists and is "registered". Lock can be ignored,
// because we are part of the right cluster.
} catch (IOException e) {
logger.error("Error with server lock file: " + lockUri, e);
} finally {
// can only use the lock if hazelcast is still active
monitor.unlock();
if (threwException) {
hazelcast.getLifecycleService().shutdown();
}
}
}
@Override
public void deleteLockAndCleanUp() {
// we need to synchronize cluster-wide
Lock monitor = hazelcast.getLock("monitor");
monitor.lock();
try {
if (hazelcast.getCluster().getMembers().size() == 1) {
// the current instance is the only one in the cluster, so the
// lock file can be deleted.
hotfolder.delete(lockUri);
}
} catch (IOException e) {
logger.error("Error while deleting lock file: " + lockUri, e);
} finally {
monitor.unlock();
hazelcast.getLifecycleService().shutdown();
}
}
}