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            /**
051             * @see org.apache.commons.net.ftp.FTPClient#changeWorkingDirectory(java.lang.String)
052             */
053            public boolean changeWorkingDirectory(String pathname) throws IOException {
054                    if(StringUtil.endsWith(pathname,'/') && pathname.length()!=1)pathname=pathname.substring(0,pathname.length()-1);
055                    
056                    if(pathname.equals(workingDirectory)) return true;
057                    workingDirectory=pathname;
058                    return super.changeWorkingDirectory(pathname);
059            }
060    
061            /**
062             *
063             * @see java.lang.Object#equals(java.lang.Object)
064             */
065            public String id() {
066                    return ftpConnectionData.key();
067            }
068    
069            /**
070             *
071             * @see java.lang.Object#equals(java.lang.Object)
072             */
073            public boolean equals(Object obj) {
074                    
075                    return ((FTPResourceClient)obj).id().equals(id());
076            }
077    
078            public FTPFile getFTPFile(FTPResource res) throws IOException {
079                    String path=res.getInnerPath();
080                    FTPFileWrap fw = (FTPFileWrap) files.get(path);
081                    
082                    if(fw==null) {
083                            return createFTPFile(res);
084                    }
085                    if(fw.time+cacheTimeout<System.currentTimeMillis()) {
086                            files.remove(path);
087                            return createFTPFile(res);
088                    }
089                    return fw.file;
090            }
091            public void registerFTPFile(FTPResource res,FTPFile file) {
092                    files.put(res.getInnerPath(),new FTPFileWrap(file));    
093            }
094    
095            public void unregisterFTPFile(FTPResource res) {
096                    files.remove(res.getInnerPath());
097            }
098            
099            
100            private FTPFile createFTPFile(FTPResource res) throws IOException {
101                    FTPFile[] children=null;
102                    boolean isRoot=res.isRoot();
103                    String path=isRoot?res.getInnerPath():res.getInnerParent();
104                    
105                    synchronized(getToken()){ 
106                            changeWorkingDirectory(path);
107                            children = listFiles();
108                    }
109                    
110                    if(children.length>0) {
111                            for(int i=0;i<children.length;i++) {
112                                    if(isRoot){
113                                            if(children[i].getName().equals(".")) {
114                                                    registerFTPFile(res, children[i]);
115                                                    return children[i];
116                                            }
117                                    }
118                                    else{
119                                            if(children[i].getName().equals(res.getName())) {
120                                                    registerFTPFile(res, children[i]);
121                                                    return children[i];
122                                            }
123                                    }
124                            }
125                    }
126                    return null;
127            }
128            
129            /**
130             *
131             * @see org.apache.commons.net.ftp.FTPClient#deleteFile(java.lang.String)
132             */
133            public boolean deleteFile(String pathname) throws IOException {
134                    files.remove(pathname);
135                    return super.deleteFile(pathname);
136            }
137    
138            class FTPFileWrap {
139    
140                    private FTPFile file;
141                    private long time;
142    
143                    public FTPFileWrap(FTPFile file) {
144                            this.file=file;
145                            this.time=System.currentTimeMillis();
146                    }
147                    
148            }
149    }