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            @Override
029            public void lock(Resource res) {
030                    String path=getPath(res);
031                    
032                    synchronized(token)  {
033                            _read(path);
034                            resources.put(path,Thread.currentThread());
035                    }
036            }
037    
038            private String getPath(Resource res) {
039                    return caseSensitive?res.getPath():res.getPath().toLowerCase();
040            }
041    
042            @Override
043            public void unlock(Resource res) {
044                    String path=getPath(res);
045                    //if(path.endsWith(".dmg"))print.err("unlock:"+path);
046                    synchronized(token)  {
047                            resources.remove(path);
048                            token.notifyAll();
049                    }
050            }
051    
052            @Override
053            public void read(Resource res) {
054                    String path=getPath(res);
055                    synchronized(token)  {
056                            //print.ln(".......");
057                            _read(path);
058                    }
059            }
060    
061            private void _read(String path) {
062                    long start=-1,now;
063                    Thread t;
064                    do {
065                            if((t=resources.get(path))==null) {
066                                    //print.ln("read ok");
067                                    return;
068                            }
069                            if(t==Thread.currentThread()) {
070                                    //aprint.err(path);
071                                    Config config = ThreadLocalPageContext.getConfig();
072                                    if(config!=null)
073                                            SystemOut.printDate(config.getErrWriter(),"conflict in same thread: on "+path);
074                                    //throw new RuntimeException("conflict in same thread: on "+res);
075                                    return;
076                            }
077                            // bugfix when lock von totem thread, wird es ignoriert
078                            if(!t.isAlive()) {
079                                    resources.remove(path);
080                                    return;
081                            }
082                            if(start==-1)start=System.currentTimeMillis();
083                            try {
084                                    token.wait(lockTimeout);
085                                    now=System.currentTimeMillis();
086                                    if((start+lockTimeout)<=now) {
087                                            Config config = ThreadLocalPageContext.getConfig();
088                                            if(config!=null)
089                                                    SystemOut.printDate(config.getErrWriter(),"timeout after "+(now-start)+" ms ("+(lockTimeout)+" ms) occured while accessing file ["+path+"]");
090                                            else 
091                                                    SystemOut.printDate("timeout ("+(lockTimeout)+" ms) occured while accessing file ["+path+"]");
092                                            return;
093                                    }
094                            } 
095                            catch (InterruptedException e) {
096                            }
097                    }
098                    while(true);
099            }
100    
101            @Override
102            public long getLockTimeout() {
103                    return lockTimeout;
104            }
105    
106            /**
107             * @param lockTimeout the lockTimeout to set
108             */
109            public void setLockTimeout(long lockTimeout) {
110                    this.lockTimeout = lockTimeout;
111            }
112    
113            /**
114             * @param caseSensitive the caseSensitive to set
115             */
116            public void setCaseSensitive(boolean caseSensitive) {
117                    this.caseSensitive = caseSensitive;
118            }
119    }