View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs.provider.ftp;
18  
19  import org.apache.commons.net.ftp.FTPClient;
20  import org.apache.commons.net.ftp.FTPFile;
21  import org.apache.commons.vfs.FileSystemException;
22  import org.apache.commons.vfs.FileSystemOptions;
23  import org.apache.commons.vfs.UserAuthenticationData;
24  import org.apache.commons.vfs.util.UserAuthenticatorUtils;
25  import org.apache.commons.vfs.provider.GenericFileName;
26  
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.OutputStream;
30  
31  /***
32   * A wrapper to the FTPClient to allow automatic reconnect on connection loss.<br />
33   * I decided to not to use eg. noop() to determine the state of the connection to avoid unnecesary server round-trips.
34   */
35  class FTPClientWrapper implements FtpClient
36  {
37      private final GenericFileName root;
38      private final FileSystemOptions fileSystemOptions;
39  
40      private FTPClient ftpClient = null;
41  
42      FTPClientWrapper(final GenericFileName root, final FileSystemOptions fileSystemOptions) throws FileSystemException
43      {
44          this.root = root;
45          this.fileSystemOptions = fileSystemOptions;
46          getFtpClient(); // fail-fast
47      }
48  
49      public GenericFileName getRoot()
50      {
51          return root;
52      }
53  
54      public FileSystemOptions getFileSystemOptions()
55      {
56          return fileSystemOptions;
57      }
58  
59      private FTPClient createClient() throws FileSystemException
60      {
61          final GenericFileName rootName = getRoot();
62  
63  		UserAuthenticationData authData = null;
64  		try
65  		{
66  			authData = UserAuthenticatorUtils.authenticate(fileSystemOptions, FtpFileProvider.AUTHENTICATOR_TYPES);
67  
68  			return FtpClientFactory.createConnection(rootName.getHostName(),
69  				rootName.getPort(),
70  				UserAuthenticatorUtils.getData(authData, UserAuthenticationData.USERNAME, UserAuthenticatorUtils.toChar(rootName.getUserName())),
71  				UserAuthenticatorUtils.getData(authData, UserAuthenticationData.PASSWORD, UserAuthenticatorUtils.toChar(rootName.getPassword())),
72  				rootName.getPath(),
73  				getFileSystemOptions());
74  		}
75  		finally
76  		{
77  			UserAuthenticatorUtils.cleanup(authData);
78  		}
79  	}
80  
81  	private FTPClient getFtpClient() throws FileSystemException
82      {
83          if (ftpClient == null)
84          {
85              ftpClient = createClient();
86          }
87  
88          return ftpClient;
89      }
90  
91      public boolean isConnected() throws FileSystemException
92      {
93          return getFtpClient().isConnected();
94      }
95  
96      public void disconnect() throws IOException
97      {
98          try
99          {
100             getFtpClient().disconnect();
101         }
102         finally
103         {
104             ftpClient = null;
105         }
106     }
107 
108     public FTPFile[] listFiles(String relPath) throws IOException
109     {
110         try
111         {
112             return getFtpClient().listFiles(relPath);
113         }
114         catch (IOException e)
115         {
116             disconnect();
117             return getFtpClient().listFiles(relPath);
118         }
119     }
120 
121     public boolean removeDirectory(String relPath) throws IOException
122     {
123         try
124         {
125             return getFtpClient().removeDirectory(relPath);
126         }
127         catch (IOException e)
128         {
129             disconnect();
130             return getFtpClient().removeDirectory(relPath);
131         }
132     }
133 
134     public boolean deleteFile(String relPath) throws IOException
135     {
136         try
137         {
138             return getFtpClient().deleteFile(relPath);
139         }
140         catch (IOException e)
141         {
142             disconnect();
143             return getFtpClient().deleteFile(relPath);
144         }
145     }
146 
147     public boolean rename(String oldName, String newName) throws IOException
148     {
149         try
150         {
151             return getFtpClient().rename(oldName, newName);
152         }
153         catch (IOException e)
154         {
155             disconnect();
156             return getFtpClient().rename(oldName, newName);
157         }
158     }
159 
160     public boolean makeDirectory(String relPath) throws IOException
161     {
162         try
163         {
164             return getFtpClient().makeDirectory(relPath);
165         }
166         catch (IOException e)
167         {
168             disconnect();
169             return getFtpClient().makeDirectory(relPath);
170         }
171     }
172 
173     public boolean completePendingCommand() throws IOException
174     {
175         if (ftpClient != null)
176         {
177             return getFtpClient().completePendingCommand();
178         }
179 
180         return true;
181     }
182 
183     public InputStream retrieveFileStream(String relPath) throws IOException
184     {
185         try
186         {
187             return getFtpClient().retrieveFileStream(relPath);
188         }
189         catch (IOException e)
190         {
191             disconnect();
192             return getFtpClient().retrieveFileStream(relPath);
193         }
194     }
195 
196     public InputStream retrieveFileStream(String relPath, long restartOffset) throws IOException
197     {
198         try
199         {
200             FTPClient client = getFtpClient();
201             client.setRestartOffset(restartOffset);
202             return client.retrieveFileStream(relPath);
203         }
204         catch (IOException e)
205         {
206             disconnect();
207 
208             FTPClient client = getFtpClient();
209             client.setRestartOffset(restartOffset);
210             return client.retrieveFileStream(relPath);
211         }
212     }
213 
214     public OutputStream appendFileStream(String relPath) throws IOException
215     {
216         try
217         {
218             return getFtpClient().appendFileStream(relPath);
219         }
220         catch (IOException e)
221         {
222             disconnect();
223             return getFtpClient().appendFileStream(relPath);
224         }
225     }
226 
227     public OutputStream storeFileStream(String relPath) throws IOException
228     {
229         try
230         {
231             return getFtpClient().storeFileStream(relPath);
232         }
233         catch (IOException e)
234         {
235             disconnect();
236             return getFtpClient().storeFileStream(relPath);
237         }
238     }
239 
240     public boolean abort() throws IOException
241     {
242         try
243         {
244             // imario@apache.org: 2005-02-14
245             // it should be better to really "abort" the transfer, but
246             // currently I didnt manage to make it work - so lets "abort" the hard way.
247             // return getFtpClient().abort();
248 
249             disconnect();
250             return true;
251         }
252         catch (IOException e)
253         {
254             disconnect();
255         }
256         return true;
257     }
258 
259     public String getReplyString() throws IOException
260     {
261         return getFtpClient().getReplyString();
262     }
263 }