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