1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.provider.ftp;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.time.Instant;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.commons.net.ftp.FTPClient;
27 import org.apache.commons.net.ftp.FTPFile;
28 import org.apache.commons.net.ftp.FTPReply;
29 import org.apache.commons.vfs2.FileSystemException;
30 import org.apache.commons.vfs2.FileSystemOptions;
31 import org.apache.commons.vfs2.UserAuthenticationData;
32 import org.apache.commons.vfs2.provider.GenericFileName;
33 import org.apache.commons.vfs2.util.UserAuthenticatorUtils;
34
35
36
37
38
39
40
41 public class FTPClientWrapper implements FtpClient {
42
43 private static final Log LOG = LogFactory.getLog(FTPClientWrapper.class);
44
45 protected final FileSystemOptions fileSystemOptions;
46 private FTPClient ftpClient;
47 private final GenericFileName root;
48
49 protected FTPClientWrapper(final GenericFileName root, final FileSystemOptions fileSystemOptions)
50 throws FileSystemException {
51 this.root = root;
52 this.fileSystemOptions = fileSystemOptions;
53 getFtpClient();
54 }
55
56 @Override
57 public boolean abort() throws IOException {
58 try {
59
60
61
62
63
64 disconnect();
65 return true;
66 } catch (final IOException e) {
67 disconnect();
68 }
69 return true;
70 }
71
72 @Override
73 public OutputStream appendFileStream(final String relPath) throws IOException {
74 try {
75 return getFtpClient().appendFileStream(relPath);
76 } catch (final IOException e) {
77 disconnect();
78 return getFtpClient().appendFileStream(relPath);
79 }
80 }
81
82 @Override
83 public boolean completePendingCommand() throws IOException {
84 if (ftpClient != null) {
85 return getFtpClient().completePendingCommand();
86 }
87
88 return true;
89 }
90
91 private FTPClient createClient() throws FileSystemException {
92 final GenericFileName rootName = getRoot();
93
94 UserAuthenticationData authData = null;
95 try {
96 authData = UserAuthenticatorUtils.authenticate(fileSystemOptions, FtpFileProvider.AUTHENTICATOR_TYPES);
97
98 return createClient(rootName, authData);
99 } finally {
100 UserAuthenticatorUtils.cleanup(authData);
101 }
102 }
103
104 protected FTPClient createClient(final GenericFileName rootName, final UserAuthenticationData authData)
105 throws FileSystemException {
106 return FtpClientFactory.createConnection(rootName.getHostName(), rootName.getPort(),
107 UserAuthenticatorUtils.getData(authData, UserAuthenticationData.USERNAME,
108 UserAuthenticatorUtils.toChar(rootName.getUserName())),
109 UserAuthenticatorUtils.getData(authData, UserAuthenticationData.PASSWORD,
110 UserAuthenticatorUtils.toChar(rootName.getPassword())),
111 rootName.getPath(), getFileSystemOptions());
112 }
113
114 @Override
115 public boolean deleteFile(final String relPath) throws IOException {
116 try {
117 return getFtpClient().deleteFile(relPath);
118 } catch (final IOException e) {
119 disconnect();
120 return getFtpClient().deleteFile(relPath);
121 }
122 }
123
124 @Override
125 public void disconnect() throws IOException {
126 try {
127 getFtpClient().quit();
128 } catch (final IOException e) {
129 LOG.debug("I/O exception while trying to quit, probably it's a timed out connection, ignoring.", e);
130 } finally {
131 try {
132 getFtpClient().disconnect();
133 } catch (final IOException e) {
134 LOG.warn("I/O exception while trying to disconnect, probably it's a closed connection, ignoring.", e);
135 } finally {
136 ftpClient = null;
137 }
138 }
139 }
140
141 public FileSystemOptions getFileSystemOptions() {
142 return fileSystemOptions;
143 }
144
145 private FTPClient getFtpClient() throws FileSystemException {
146 if (ftpClient == null) {
147 ftpClient = createClient();
148 }
149
150 return ftpClient;
151 }
152
153 @Override
154 public int getReplyCode() throws IOException {
155 return getFtpClient().getReplyCode();
156 }
157
158 @Override
159 public String getReplyString() throws IOException {
160 return getFtpClient().getReplyString();
161 }
162
163 public GenericFileName getRoot() {
164 return root;
165 }
166
167
168
169
170 @Override
171 public boolean hasFeature(final String feature) throws IOException {
172 try {
173 return getFtpClient().hasFeature(feature);
174 } catch (final IOException ex) {
175 disconnect();
176 return getFtpClient().hasFeature(feature);
177 }
178 }
179
180 @Override
181 public boolean isConnected() throws FileSystemException {
182 return ftpClient != null && ftpClient.isConnected();
183 }
184
185 @Override
186 public FTPFile[] listFiles(final String relPath) throws IOException {
187 try {
188
189 return listFilesInDirectory(relPath);
190 } catch (final IOException e) {
191 disconnect();
192 return listFilesInDirectory(relPath);
193 }
194 }
195
196 private FTPFile[] listFilesInDirectory(final String relPath) throws IOException {
197
198 FTPFile[] ftpFiles = getFtpClient().listFiles(relPath);
199 if (FTPReply.isPositiveCompletion(getFtpClient().getReplyCode())) {
200 return ftpFiles;
201 }
202
203
204
205
206 String workingDirectory = null;
207 if (relPath != null) {
208 workingDirectory = getFtpClient().printWorkingDirectory();
209 if (!getFtpClient().changeWorkingDirectory(relPath)) {
210 return null;
211 }
212 }
213
214 ftpFiles = getFtpClient().listFiles();
215
216 if (relPath != null && !getFtpClient().changeWorkingDirectory(workingDirectory)) {
217 throw new FileSystemException("vfs.provider.ftp.wrapper/change-work-directory-back.error",
218 workingDirectory);
219 }
220 return ftpFiles;
221 }
222
223 @Override
224 public boolean makeDirectory(final String relPath) throws IOException {
225 try {
226 return getFtpClient().makeDirectory(relPath);
227 } catch (final IOException e) {
228 disconnect();
229 return getFtpClient().makeDirectory(relPath);
230 }
231 }
232
233
234
235
236 @Override
237 public Instant mdtmInstant(final String relPath) throws IOException {
238 try {
239 return getFtpClient().mdtmCalendar(relPath).toInstant();
240 } catch (final IOException ex) {
241 disconnect();
242 return getFtpClient().mdtmCalendar(relPath).toInstant();
243 }
244 }
245
246 @Override
247 public boolean removeDirectory(final String relPath) throws IOException {
248 try {
249 return getFtpClient().removeDirectory(relPath);
250 } catch (final IOException e) {
251 disconnect();
252 return getFtpClient().removeDirectory(relPath);
253 }
254 }
255
256 @Override
257 public boolean rename(final String oldName, final String newName) throws IOException {
258 try {
259 return getFtpClient().rename(oldName, newName);
260 } catch (final IOException e) {
261 disconnect();
262 return getFtpClient().rename(oldName, newName);
263 }
264 }
265
266 @Override
267 public InputStream retrieveFileStream(final String relPath) throws IOException {
268 try {
269 return getFtpClient().retrieveFileStream(relPath);
270 } catch (final IOException e) {
271 disconnect();
272 return getFtpClient().retrieveFileStream(relPath);
273 }
274 }
275
276 @Override
277 public InputStream retrieveFileStream(final String relPath, final int bufferSize) throws IOException {
278 try {
279 final FTPClient client = getFtpClient();
280 client.setBufferSize(bufferSize);
281 return client.retrieveFileStream(relPath);
282 } catch (final IOException e) {
283 disconnect();
284 final FTPClient client = getFtpClient();
285 client.setBufferSize(bufferSize);
286 return client.retrieveFileStream(relPath);
287 }
288 }
289
290 @Override
291 public InputStream retrieveFileStream(final String relPath, final long restartOffset) throws IOException {
292 try {
293 final FTPClient client = getFtpClient();
294 client.setRestartOffset(restartOffset);
295 return client.retrieveFileStream(relPath);
296 } catch (final IOException e) {
297 disconnect();
298 final FTPClient client = getFtpClient();
299 client.setRestartOffset(restartOffset);
300 return client.retrieveFileStream(relPath);
301 }
302 }
303
304 @Override
305 public void setBufferSize(final int bufferSize) throws FileSystemException {
306 getFtpClient().setBufferSize(bufferSize);
307 }
308
309 @Override
310 public OutputStream storeFileStream(final String relPath) throws IOException {
311 try {
312 return getFtpClient().storeFileStream(relPath);
313 } catch (final IOException e) {
314 disconnect();
315 return getFtpClient().storeFileStream(relPath);
316 }
317 }
318 }