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