RWLockMap.java

package eu.javaexperience.collection.map;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import eu.javaexperience.asserts.AssertArgument;

public class RWLockMap<K,V> implements ConcurrentMap<K, V>, ImprovedMap<K, V>
{
	public RWLockMap(Map<K,V> map)
	{
		AssertArgument.assertNotNull(this.map = map, "map");
	}
	
	protected final Map<K,V> map;
	
	protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	protected ReadLock rl = lock.readLock();
	protected WriteLock wl = lock.writeLock();
	
	/**
	 * Only for advanced usage
	 * */
	@Deprecated
	public ReadLock getReadLock()
	{
		return rl;
	}

	/**
	 * Only for advanced usage
	 * */
	@Deprecated
	public WriteLock getWriteLock()
	{
		return wl;
	}

	/**
	 * Only for advanced usage
	 * */
	@Deprecated
	public Map<K,V> getBackendMap()
	{
		return map;
	}
	
	@Override
	public int size()
	{
		rl.lock();
		try
		{
			return map.size();
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public boolean isEmpty()
	{
		rl.lock();
		try
		{
			return map.isEmpty();
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public boolean containsKey(Object key)
	{
		rl.lock();
		try
		{
			return map.containsKey(key);
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public boolean containsValue(Object value)
	{
		rl.lock();
		try
		{
			return map.containsValue(value);
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public V get(Object key)
	{
		rl.lock();
		try
		{
			return map.get(key);
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public V put(K key, V value)
	{
		wl.lock();
		try
		{
			return map.put(key, value);
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public V remove(Object key)
	{
		wl.lock();
		try
		{
			return map.remove(key);
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public void putAll(Map<? extends K, ? extends V> m)
	{
		wl.lock();
		try
		{
			map.putAll(m);
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public void clear()
	{
		wl.lock();
		try
		{
			map.clear();
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public Set<K> keySet()
	{
		rl.lock();
		try
		{
			return map.keySet();
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public Collection<V> values()
	{
		rl.lock();
		try
		{
			return map.values();
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public Set<java.util.Map.Entry<K, V>> entrySet()
	{
		rl.lock();
		try
		{
			return map.entrySet();
		}
		finally
		{
			rl.unlock();
		}
	}

	@Override
	public V putIfAbsent(K key, V value)
	{
		wl.lock();
		try
		{
			/* This class is basically a wrapper for non ConcurrentMaps
			if(map instanceof ConcurrentMap)
			{
				return (V) ((ConcurrentMap)map).putIfAbsent(key, value);
			}
			else*/
			{
				if(!map.containsKey(key))
				{
					return map.put(key, value);
				}
				else
				{
					return null;
				}
			}
		}
		finally
		{
			wl.unlock();
		}
	}
	@Override
	public boolean remove(Object key, Object value)
	{
		wl.lock();
		try
		{
			Object in = map.get(key);
			if(null != value && value.equals(in))
			{
				map.remove(key);
				return true;
			}
			else
			{
				return false;
			}
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public boolean replace(K key, V oldValue, V newValue)
	{
		wl.lock();
		try
		{
			Object in = map.get(key);
			if(null != in && in.equals(oldValue))
			{
				map.put(key, newValue);
				return true;
			}
			else
			{
				return false;
			}
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public V replace(K key, V value)
	{
		wl.lock();
		try
		{
			if(map.containsKey(key))
			{
				return map.put(key, value);
			}
			else
			{
				return null;
			}
		}
		finally
		{
			wl.unlock();
		}
	}

	@Override
	public int copyAll(Map<? super K, ? super V> dst)
	{
		rl.lock();
		try
		{
			int len = dst.size();
			dst.putAll(map);
			return dst.size() - len;
		}
		finally
		{
			rl.unlock();
		}
	}
	
	public String toString()
	{
		return "ReentrantMap:"+MapTools.toStringMultiline(this);
	}
}