001    package railo.commons.io.res.type.ftp;
002    
003    import java.io.IOException;
004    
005    import org.apache.commons.net.ftp.FTPClient;
006    import org.apache.commons.net.ftp.FTPFile;
007    
008    import railo.commons.collections.HashTable;
009    import railo.commons.lang.SerializableObject;
010    import railo.commons.lang.StringUtil;
011    
012    public final class FTPResourceClient extends FTPClient {
013    
014            private String workingDirectory=null;
015            
016            
017            private final FTPConnectionData ftpConnectionData;
018            private long lastAccess;
019            private final Object token=new SerializableObject();
020            private final HashTable files=new HashTable();
021            private final int cacheTimeout;
022    
023            public FTPResourceClient(FTPConnectionData ftpConnectionData,int cacheTimeout) {
024                    this.ftpConnectionData=ftpConnectionData;
025                    this.cacheTimeout=cacheTimeout;
026            }
027    
028            /**
029             * @return the ftpConnectionData
030             */
031            public FTPConnectionData getFtpConnectionData() {
032                    return ftpConnectionData;
033            }
034    
035            public void touch() {
036                    this.lastAccess=System.currentTimeMillis();
037            }
038    
039            /**
040             * @return the lastAccess
041             */
042            public long getLastAccess() {
043                    return lastAccess;
044            }
045    
046            public Object getToken() {
047                    return token;
048            }
049            
050            @Override
051            public boolean changeWorkingDirectory(String pathname) throws IOException {
052                    if(StringUtil.endsWith(pathname,'/') && pathname.length()!=1)pathname=pathname.substring(0,pathname.length()-1);
053                    
054                    if(pathname.equals(workingDirectory)) return true;
055                    workingDirectory=pathname;
056                    return super.changeWorkingDirectory(pathname);
057            }
058    
059            public String id() {
060                    return ftpConnectionData.key();
061            }
062    
063            @Override
064            public boolean equals(Object obj) {
065                    
066                    return ((FTPResourceClient)obj).id().equals(id());
067            }
068    
069            public FTPFile getFTPFile(FTPResource res) throws IOException {
070                    String path=res.getInnerPath();
071                    FTPFileWrap fw = (FTPFileWrap) files.get(path);
072                    
073                    if(fw==null) {
074                            return createFTPFile(res);
075                    }
076                    if(fw.time+cacheTimeout<System.currentTimeMillis()) {
077                            files.remove(path);
078                            return createFTPFile(res);
079                    }
080                    return fw.file;
081            }
082            public void registerFTPFile(FTPResource res,FTPFile file) {
083                    files.put(res.getInnerPath(),new FTPFileWrap(file));    
084            }
085    
086            public void unregisterFTPFile(FTPResource res) {
087                    files.remove(res.getInnerPath());
088            }
089            
090            
091            private FTPFile createFTPFile(FTPResource res) throws IOException {
092                    FTPFile[] children=null;
093                    boolean isRoot=res.isRoot();
094                    String path=isRoot?res.getInnerPath():res.getInnerParent();
095                    
096                    synchronized(getToken()){ 
097                            changeWorkingDirectory(path);
098                            children = listFiles();
099                    }
100                    
101                    if(children.length>0) {
102                            for(int i=0;i<children.length;i++) {
103                                    if(isRoot){
104                                            if(children[i].getName().equals(".")) {
105                                                    registerFTPFile(res, children[i]);
106                                                    return children[i];
107                                            }
108                                    }
109                                    else{
110                                            if(children[i].getName().equals(res.getName())) {
111                                                    registerFTPFile(res, children[i]);
112                                                    return children[i];
113                                            }
114                                    }
115                            }
116                    }
117                    return null;
118            }
119            
120            @Override
121            public boolean deleteFile(String pathname) throws IOException {
122                    files.remove(pathname);
123                    return super.deleteFile(pathname);
124            }
125    
126            class FTPFileWrap {
127    
128                    private FTPFile file;
129                    private long time;
130    
131                    public FTPFileWrap(FTPFile file) {
132                            this.file=file;
133                            this.time=System.currentTimeMillis();
134                    }
135                    
136            }
137    }