001 package railo.commons.lock.rw; 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 import railo.commons.lock.Lock; 011 import railo.commons.lock.LockException; 012 import railo.commons.lock.LockInterruptedException; 013 import railo.runtime.exp.PageRuntimeException; 014 import railo.runtime.op.Caster; 015 016 public class RWKeyLock<K> { 017 018 private Map<K,RWLock<K>> locks=new HashMap<K,RWLock<K>>(); 019 020 public Lock lock(K token, long timeout, boolean readOnly) throws LockException, LockInterruptedException { 021 if(timeout<=0) throw new LockException("timeout must be a postive number"); 022 023 RWWrap<K> wrap; 024 //K token=key; 025 synchronized (locks) { 026 RWLock<K> lock; 027 lock=locks.get(token); 028 if(lock==null) { 029 locks.put(token, lock=new RWLock<K>(token)); 030 } 031 lock.inc(); 032 wrap= new RWWrap<K>(lock, readOnly); 033 } 034 try{ 035 wrap.lock(timeout); 036 } 037 catch(LockException e){ 038 synchronized (locks) {wrap.getLock().dec();} 039 throw e; 040 } 041 catch(LockInterruptedException e){ 042 synchronized (locks) {wrap.getLock().dec();} 043 throw e; 044 } 045 catch(Throwable t){ 046 synchronized (locks) {wrap.getLock().dec();} 047 throw new PageRuntimeException(Caster.toPageException(t)); 048 } 049 return wrap; 050 } 051 052 public void unlock(Lock lock) { 053 if(!(lock instanceof RWWrap)) { 054 return; 055 } 056 057 lock.unlock(); 058 059 synchronized (locks) { 060 ((RWWrap)lock).getLock().dec(); 061 if(lock.getQueueLength()==0){ 062 locks.remove(((RWWrap)lock).getLabel()); 063 } 064 } 065 } 066 067 public List<K> getOpenLockNames() { 068 Iterator<Entry<K, RWLock<K>>> it = locks.entrySet().iterator(); 069 Entry<K, RWLock<K>> entry; 070 List<K> list=new ArrayList<K>(); 071 while(it.hasNext()){ 072 entry = it.next(); 073 if(entry.getValue().getQueueLength()>0) 074 list.add(entry.getKey()); 075 } 076 return list; 077 } 078 079 public void clean() { 080 Iterator<Entry<K, RWLock<K>>> it = locks.entrySet().iterator(); 081 Entry<K, RWLock<K>> entry; 082 083 while(it.hasNext()){ 084 entry = it.next(); 085 if(entry.getValue().getQueueLength()==0){ 086 synchronized (locks) { 087 if(entry.getValue().getQueueLength()==0){ 088 locks.remove(entry.getKey()); 089 } 090 } 091 } 092 } 093 } 094 } 095 096 class RWWrap<L> implements Lock { 097 098 private RWLock<L> lock; 099 private boolean readOnly; 100 101 public RWWrap(RWLock<L> lock, boolean readOnly){ 102 this.lock=lock; 103 this.readOnly=readOnly; 104 } 105 106 public void lock(long timeout) throws LockException, LockInterruptedException { 107 lock.lock(timeout, readOnly); 108 } 109 110 public void unlock() { 111 lock.unlock(readOnly); 112 } 113 public int getQueueLength() { 114 return lock.getQueueLength(); 115 } 116 117 public L getLabel(){ 118 return lock.getLabel(); 119 } 120 121 public RWLock<L> getLock(){ 122 return lock; 123 } 124 public boolean isReadOnly(){ 125 return readOnly; 126 } 127 128 }