001 package railo.commons.io.res.util; 002 003 import java.util.HashMap; 004 import java.util.Map; 005 006 import railo.commons.io.res.Resource; 007 import railo.commons.io.res.ResourceLock; 008 import railo.commons.lang.SerializableObject; 009 import railo.commons.lang.SystemOut; 010 import railo.runtime.config.Config; 011 import railo.runtime.engine.ThreadLocalPageContext; 012 013 public final class ResourceLockImpl implements ResourceLock { 014 015 private static final long serialVersionUID = 6888529579290798651L; 016 017 private long lockTimeout; 018 private boolean caseSensitive; 019 020 public ResourceLockImpl(long timeout,boolean caseSensitive) { 021 this.lockTimeout=timeout; 022 this.caseSensitive=caseSensitive; 023 } 024 025 private Object token=new SerializableObject(); 026 private Map<String,Thread> resources=new HashMap<String,Thread>(); 027 028 /** 029 * @see railo.commons.io.res.ResourceLock#lock(railo.commons.io.res.Resource) 030 */ 031 public void lock(Resource res) { 032 String path=getPath(res); 033 034 synchronized(token) { 035 _read(path); 036 resources.put(path,Thread.currentThread()); 037 } 038 } 039 040 private String getPath(Resource res) { 041 return caseSensitive?res.getPath():res.getPath().toLowerCase(); 042 } 043 044 /** 045 * @see railo.commons.io.res.ResourceLock#unlock(railo.commons.io.res.Resource) 046 */ 047 public void unlock(Resource res) { 048 String path=getPath(res); 049 //if(path.endsWith(".dmg"))print.err("unlock:"+path); 050 synchronized(token) { 051 resources.remove(path); 052 token.notifyAll(); 053 } 054 } 055 056 /** 057 * @see railo.commons.io.res.ResourceLock#read(railo.commons.io.res.Resource) 058 */ 059 public void read(Resource res) { 060 String path=getPath(res); 061 synchronized(token) { 062 //print.ln("......."); 063 _read(path); 064 } 065 } 066 067 private void _read(String path) { 068 long start=-1,now; 069 Thread t; 070 do { 071 if((t=resources.get(path))==null) { 072 //print.ln("read ok"); 073 return; 074 } 075 if(t==Thread.currentThread()) { 076 //aprint.err(path); 077 Config config = ThreadLocalPageContext.getConfig(); 078 if(config!=null) 079 SystemOut.printDate(config.getErrWriter(),"conflict in same thread: on "+path); 080 //throw new RuntimeException("conflict in same thread: on "+res); 081 return; 082 } 083 // bugfix when lock von totem thread, wird es ignoriert 084 if(!t.isAlive()) { 085 resources.remove(path); 086 return; 087 } 088 if(start==-1)start=System.currentTimeMillis(); 089 try { 090 token.wait(lockTimeout); 091 now=System.currentTimeMillis(); 092 if((start+lockTimeout)<=now) { 093 Config config = ThreadLocalPageContext.getConfig(); 094 if(config!=null) 095 SystemOut.printDate(config.getErrWriter(),"timeout after "+(now-start)+" ms ("+(lockTimeout)+" ms) occured while accessing file ["+path+"]"); 096 else 097 SystemOut.printDate("timeout ("+(lockTimeout)+" ms) occured while accessing file ["+path+"]"); 098 return; 099 } 100 } 101 catch (InterruptedException e) { 102 } 103 } 104 while(true); 105 } 106 107 /** 108 * @see railo.commons.io.res.ResourceLock#getLockTimeout() 109 */ 110 public long getLockTimeout() { 111 return lockTimeout; 112 } 113 114 /** 115 * @param lockTimeout the lockTimeout to set 116 */ 117 public void setLockTimeout(long lockTimeout) { 118 this.lockTimeout = lockTimeout; 119 } 120 121 /** 122 * @param caseSensitive the caseSensitive to set 123 */ 124 public void setCaseSensitive(boolean caseSensitive) { 125 this.caseSensitive = caseSensitive; 126 } 127 }