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    }