Hello,
I would like to expose a home-made solution in order to manage the concurrent accesses.
Here, a singleton named LockSingleton used on server side to:
- Put a lock for an user,
- Keep a lock for an user,
- Check the presence of a lock,
- Cleanup the locks every 30 seconds,
package com.ho.security.lock;
import java.util.Calendar;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils;
/**
* Management of lock
*/
public class LockSingleton {
// Locks
private Map<String, Lock> locks = null;
// Cleanup interval = every 30s
private static final long DELAY = 30*1000;
// A lock older than 30s is considered as a dead lock ; it should be killed
protected static final long DELAY_TO_KILL_LOCK = 30*1000;
private static LockSingleton instance = null;
private LockSingleton(){
locks=new ConcurrentHashMap<String, Lock>();
cleanLocks();
}
/**
* Cleanup the locks
*/
private void cleanLocks() {
Timer timer = new Timer();
TimerTask task = new TimerTask(){
@Override
public void run() {
long nowInMillis = Calendar.getInstance().getTimeInMillis();
synchronized (locks) {
for (Lock tLock : locks.values()) {
if (tLock.getUser()!=null){
if(nowInMillis-tLock.getCheckTime().getTimeInMillis() > DELAY_TO_KILL_LOCK){
System.out.println("Remove old lock:"+tLock.id+" for "+tLock.user);
locks.remove(tLock.id);
}
}
}
}
}//end-method
};
timer.schedule(task, DELAY, DELAY);
}
public static synchronized LockSingleton getInstance(){
if (instance==null){
instance = new LockSingleton();
}
return instance;
}
public boolean check(String lockId){
return locks.containsKey(lockId);
}
public boolean check(Lock lock){
return check(lock.getId());
}
public void add(Lock lock){
synchronized (locks) {
locks.put(lock.id, lock);
}
}
public String putLock(String docId, String username) throws Exception {
String lockId = java.util.UUID.randomUUID().toString();
//Find a lock on this documentId
String userLocked = getUserLocked(docId, username);
if (StringUtils.isNotBlank(userLocked)) {
//Locked by another person
throw new Exception("Document locked by another person : "+userLocked);
}
//create new Lock for this user
add(new Lock(lockId,docId,username));
System.out.println("New lock set for "+username+" on "+docId);
return lockId;
}
public void update(String lockId, String docId, String username) throws Exception {
Lock lock = locks.get(lockId);
if (lock==null){
throw new Exception("No lock matches");
}else{
if (!username.equals(lock.getUser())){
//user different- collision
throw new Exception("This document lock does not belong to you");
}
if (!docId.equals(lock.getDocId())){
//Conflict of document Id: hacking ?
throw new Exception("Conflict on locked documents");
}
//Update check time
lock.setCheckTime(Calendar.getInstance());
System.out.println("Lock updated for "+username+" on "+docId);
}
}
public String getUserLocked(String docId, String username) {
synchronized (locks) {
//Find a lock on this documentId
for (Lock tLock : locks.values()) {
if (tLock.getDocId().equals(docId)){
if (!tLock.getUser().equals(username)){
//Locked by another person
return tLock.getUser();
}
}
}
}
return "";
}
/*
* Class du lock
*/
private class Lock {
// ...
}
}
…With the lock class:
private class Lock {
private String id;
private String docId;
private String user;
private Calendar checkTime;
public Lock(String id, String docId, String user) {
this.id = id;
this.docId = docId;
this.user = user;
setCheckTime(Calendar.getInstance());
}
public String getId() {
return id;
}
public String getDocId() {
return docId;
}
public String getUser() {
return user;
}
/**
* @param checkTime the checkTime to set
*/
public void setCheckTime(Calendar checkTime) {
this.checkTime = checkTime;
}
/**
* @return the checkTime
*/
public Calendar getCheckTime() {
return checkTime;
}
public void setUser(String user) {
this.user = user;
}
}
That’s all!!!
Huseyin OZVEREN
