/** * Copyright (c) 2015, Lucee Assosication Switzerland. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.commons.lock; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class KeyLockImpl<K> implements KeyLock<K> { private Map<Token<K>,SimpleLock<Token<K>>> locks=new HashMap<Token<K>, SimpleLock<Token<K>>>(); @Override public Lock lock(K key, long timeout) throws LockException { if(timeout<=0) throw new LockException("timeout must be a postive number"); SimpleLock<Token<K>> lock; Token<K> token=new Token<K>(key); synchronized (locks) { lock=locks.get(token); if(lock==null) { locks.put(token, lock=new SimpleLock<Token<K>>(token)); } // ignore inner calls with same id else if(lock.getLabel().getThreadId()==token.getThreadId()) { return null; } } lock.lock(timeout); return lock; } @Override public void unlock(Lock lock) { if(lock==null) return; synchronized (locks) { if(lock.getQueueLength()==0){ locks.remove(((SimpleLock<Token<K>>)lock).getLabel()); } } lock.unlock(); } @Override public List<K> getOpenLockNames() { Iterator<Entry<Token<K>, SimpleLock<Token<K>>>> it = locks.entrySet().iterator(); Entry<Token<K>, SimpleLock<Token<K>>> entry; List<K> list=new ArrayList<K>(); while(it.hasNext()){ entry = it.next(); if(entry.getValue().getQueueLength()>0) list.add(entry.getKey().getKey()); } return list; } @Override public void clean() { Iterator<Entry<Token<K>, SimpleLock<Token<K>>>> it = locks.entrySet().iterator(); Entry<Token<K>, SimpleLock<Token<K>>> entry; while(it.hasNext()){ entry = it.next(); if(entry.getValue().getQueueLength()==0){ synchronized (locks) { if(entry.getValue().getQueueLength()==0){ locks.remove(entry.getKey()); } } } } } } class Token<K> { private K key; private long threadid; /** * @param key */ public Token(K key) { this.key=key; this.threadid=Thread.currentThread().getId(); } /** * @return the id */ public long getThreadId() { return threadid; } public K getKey() { return key; } @Override public String toString(){ return key.toString(); } @Override public boolean equals(Object obj){ if(obj instanceof Token<?>) { Token<?> other=(Token<?>) obj; obj=other.key; } return key.equals(obj); } @Override public int hashCode(){ return key.hashCode(); } }