001 package railo.commons.lock; 002 003 import java.util.ArrayList; 004 import java.util.HashMap; 005 import java.util.Iterator; 006 import java.util.List; 007 import java.util.Map; 008 import java.util.Map.Entry; 009 010 public class KeyLock<K> { 011 012 private Map<Token<K>,SimpleLock<Token<K>>> locks=new HashMap<Token<K>, SimpleLock<Token<K>>>(); 013 014 015 public Lock lock(K key, long timeout) throws LockException, LockInterruptedException { 016 if(timeout<=0) throw new LockException("timeout must be a postive number"); 017 018 SimpleLock<Token<K>> lock; 019 Token<K> token=new Token<K>(key); 020 synchronized (locks) { 021 lock=locks.get(token); 022 if(lock==null) { 023 locks.put(token, lock=new SimpleLock<Token<K>>(token)); 024 } 025 // ignore inner calls with same id 026 else if(lock.getLabel().getThreadId()==token.getThreadId()) { 027 return null; 028 } 029 } 030 lock.lock(timeout); 031 return lock; 032 } 033 034 public void unlock(Lock lock) { 035 if(lock==null) return; 036 037 synchronized (locks) { 038 if(lock.getQueueLength()==0){ 039 locks.remove(((SimpleLock<Token<K>>)lock).getLabel()); 040 } 041 } 042 lock.unlock(); 043 } 044 045 public List<K> getOpenLockNames() { 046 Iterator<Entry<Token<K>, SimpleLock<Token<K>>>> it = locks.entrySet().iterator(); 047 Entry<Token<K>, SimpleLock<Token<K>>> entry; 048 List<K> list=new ArrayList<K>(); 049 while(it.hasNext()){ 050 entry = it.next(); 051 if(entry.getValue().getQueueLength()>0) 052 list.add(entry.getKey().getKey()); 053 } 054 return list; 055 } 056 057 public void clean() { 058 Iterator<Entry<Token<K>, SimpleLock<Token<K>>>> it = locks.entrySet().iterator(); 059 Entry<Token<K>, SimpleLock<Token<K>>> entry; 060 061 while(it.hasNext()){ 062 entry = it.next(); 063 if(entry.getValue().getQueueLength()==0){ 064 synchronized (locks) { 065 if(entry.getValue().getQueueLength()==0){ 066 locks.remove(entry.getKey()); 067 } 068 } 069 } 070 } 071 } 072 } 073 074 class Token<K> { 075 076 private K key; 077 private long threadid; 078 079 /** 080 * @param key 081 */ 082 public Token(K key) { 083 this.key=key; 084 this.threadid=Thread.currentThread().getId(); 085 } 086 087 /** 088 * @return the id 089 */ 090 public long getThreadId() { 091 return threadid; 092 } 093 public K getKey() { 094 return key; 095 } 096 097 /** 098 * @see java.lang.Object#toString() 099 */ 100 public String toString(){ 101 return key.toString(); 102 } 103 104 /** 105 * @see java.lang.Object#equals(java.lang.Object) 106 */ 107 public boolean equals(Object obj){ 108 if(obj instanceof Token<?>) { 109 Token<?> other=(Token<?>) obj; 110 obj=other.key; 111 } 112 return key.equals(obj); 113 } 114 115 /** 116 * @see java.lang.Object#hashCode() 117 */ 118 public int hashCode(){ 119 return key.hashCode(); 120 } 121 122 123 } 124 125