001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.commons.io.res.type.ftp; 020 021import java.io.IOException; 022import java.util.Map; 023 024import lucee.commons.collection.MapFactory; 025import lucee.commons.lang.SerializableObject; 026import lucee.commons.lang.StringUtil; 027 028import org.apache.commons.net.ftp.FTPClient; 029import org.apache.commons.net.ftp.FTPFile; 030 031public final class FTPResourceClient extends FTPClient { 032 033 private String workingDirectory=null; 034 035 036 private final FTPConnectionData ftpConnectionData; 037 private long lastAccess; 038 private final Object token=new SerializableObject(); 039 private final Map<String,FTPFileWrap> files=MapFactory.<String,FTPFileWrap>getConcurrentMap(); 040 private final int cacheTimeout; 041 042 public FTPResourceClient(FTPConnectionData ftpConnectionData,int cacheTimeout) { 043 this.ftpConnectionData=ftpConnectionData; 044 this.cacheTimeout=cacheTimeout; 045 } 046 047 /** 048 * @return the ftpConnectionData 049 */ 050 public FTPConnectionData getFtpConnectionData() { 051 return ftpConnectionData; 052 } 053 054 public void touch() { 055 this.lastAccess=System.currentTimeMillis(); 056 } 057 058 /** 059 * @return the lastAccess 060 */ 061 public long getLastAccess() { 062 return lastAccess; 063 } 064 065 public Object getToken() { 066 return token; 067 } 068 069 @Override 070 public boolean changeWorkingDirectory(String pathname) throws IOException { 071 if(StringUtil.endsWith(pathname,'/') && pathname.length()!=1)pathname=pathname.substring(0,pathname.length()-1); 072 073 if(pathname.equals(workingDirectory)) return true; 074 workingDirectory=pathname; 075 return super.changeWorkingDirectory(pathname); 076 } 077 078 public String id() { 079 return ftpConnectionData.key(); 080 } 081 082 @Override 083 public boolean equals(Object obj) { 084 085 return ((FTPResourceClient)obj).id().equals(id()); 086 } 087 088 public FTPFile getFTPFile(FTPResource res) throws IOException { 089 String path=res.getInnerPath(); 090 FTPFileWrap fw = files.get(path); 091 092 if(fw==null) { 093 return createFTPFile(res); 094 } 095 if(fw.time+cacheTimeout<System.currentTimeMillis()) { 096 files.remove(path); 097 return createFTPFile(res); 098 } 099 return fw.file; 100 } 101 public void registerFTPFile(FTPResource res,FTPFile file) { 102 files.put(res.getInnerPath(),new FTPFileWrap(file)); 103 } 104 105 public void unregisterFTPFile(FTPResource res) { 106 files.remove(res.getInnerPath()); 107 } 108 109 110 private FTPFile createFTPFile(FTPResource res) throws IOException { 111 FTPFile[] children=null; 112 boolean isRoot=res.isRoot(); 113 String path=isRoot?res.getInnerPath():res.getInnerParent(); 114 115 synchronized(getToken()){ 116 changeWorkingDirectory(path); 117 children = listFiles(); 118 } 119 120 if(children.length>0) { 121 for(int i=0;i<children.length;i++) { 122 if(isRoot){ 123 if(children[i].getName().equals(".")) { 124 registerFTPFile(res, children[i]); 125 return children[i]; 126 } 127 } 128 else{ 129 if(children[i].getName().equals(res.getName())) { 130 registerFTPFile(res, children[i]); 131 return children[i]; 132 } 133 } 134 } 135 } 136 return null; 137 } 138 139 @Override 140 public boolean deleteFile(String pathname) throws IOException { 141 files.remove(pathname); 142 return super.deleteFile(pathname); 143 } 144 145 class FTPFileWrap { 146 147 private FTPFile file; 148 private long time; 149 150 public FTPFileWrap(FTPFile file) { 151 this.file=file; 152 this.time=System.currentTimeMillis(); 153 } 154 155 } 156}