View Javadoc

1   /*
2    * $HeadURL: $
3    * $Date: $
4    * $Revision: $
5    * $Author: $
6    * 
7    * Copyright (c) 2005 MindTree Consulting Ltd. 
8    * 
9    * This file is part of Insight.
10   * 
11   * Insight is free software: you can redistribute it and/or modify it under the 
12   * terms of the GNU General Public License as published by the Free Software 
13   * Foundation, either version 3 of the License, or (at your option) any later 
14   * version.
15   * 
16   * Insight is distributed in the hope that it will be useful, but 
17   * WITHOUT ANY WARRANTY; without even the implied warranty of 
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
19   * Public License for more details.
20   * 
21   * You should have received a copy of the GNU General Public License along with 
22   * Insight.  If not, see <http://www.gnu.org/licenses/>.
23   */
24  
25  package com.mindtree.techworks.insight.download;
26  
27  import java.io.File;
28  import java.io.FileNotFoundException;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.net.PasswordAuthentication;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import com.mindtree.techworks.insight.receiver.WildCardMatcher;
36  import com.sshtools.j2ssh.SftpClient;
37  import com.sshtools.j2ssh.SshClient;
38  import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
39  import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient;
40  import com.sshtools.j2ssh.configuration.SshConnectionProperties;
41  import com.sshtools.j2ssh.sftp.SftpFile;
42  
43  
44  /**
45   * TODO
46   * 
47   * @see com.mindtree.techworks.insight.download.RemoteClient RemoteClient
48   * @author Bindul Bhowmik
49   * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
50   */
51  public class SFTPRemoteClient extends RemoteClient {
52  
53  	//
54  	// Static block to register with the factory
55  	//
56  
57  	static {
58  		// This class handles only SFTP filesets
59  		RemoteClientFactory.registerClient("SFTP_CLIENT",
60  				SFTPRemoteClient.class);
61  	}
62  
63  	//
64  	// Constants
65  	//
66  
67  	/**
68  	 * Password Authentication to use for anonymous access
69  	 */
70  	public static final PasswordAuthentication anonPassAuth = new PasswordAuthentication(
71  			"anonymous", "insight@mindtree.com".toCharArray());
72  
73  	//
74  	// Instance variables
75  	//
76  
77  	/**
78  	 * SSH Client instance for the host
79  	 */
80  	private SshClient sshClient;
81  
82  	/**
83  	 * The fileset driving this client
84  	 */
85  	SFTPFileset fileset;
86  
87  	/**
88  	 * The SFTP Client
89  	 */
90  	private SftpClient sftpClient;
91  
92  	//
93  	// Implemented abstract methods
94  	//
95  
96  	/**
97  	 * @see com.mindtree.techworks.insight.download.RemoteClient#setFileset(com.mindtree.techworks.insight.download.Fileset)
98  	 */
99  	protected void setFileset (Fileset fileset) throws RemoteClientException {
100 
101 		if (fileset.getType() != Fileset.SFTP_FILESET
102 				|| !(fileset instanceof SFTPFileset)) {
103 			throw new RemoteClientException(
104 					"This client can handle only SFTPFileset");
105 		}
106 		this.fileset = (SFTPFileset) fileset;
107 
108 	}
109 	
110 	/**
111 	 * @see com.mindtree.techworks.insight.download.RemoteClient#downloadFile(java.lang.String)
112 	 */
113 	/*
114 	 * The return type of this method is changed from String to String[]
115 	 * in support of wild cards.
116 	 */
117 	protected String[] downloadFile (String fileName)
118 			throws RemoteClientException {
119 
120 		isBusy = true;
121 		checkConnection();
122 		//Vector for storing the file names matching with the given pattern.
123 		List matchingFileNames = new ArrayList(5);
124 		//Vector for storing the file names of all the downloaded files.
125 		List downloadedFiles = new ArrayList(5);
126 		List remoteFiles;
127 		File destinationFile = null;
128 		FileOutputStream fos = null;
129 		//Checks whether the file name has any wild cards. Currently supporting only the wild card '*'.
130 		if(WildCardMatcher.hasWildCardEntries(fileName)){
131 			int fileSeperatorIndex = (fileName.lastIndexOf('\\') == -1) ? fileName.lastIndexOf('/') : fileName.lastIndexOf('\\');  
132 			String remoteDirectory = (fileName.substring(0, fileSeperatorIndex));
133 			String pattern = (fileName.substring(fileSeperatorIndex + 1));
134 			try{
135 				//Fetches the file list from the remote directory
136 				remoteFiles = sftpClient.ls(remoteDirectory);
137 				//Gets the names of the files matching with the given pattern.
138 				matchingFileNames = getMatchingFiles(remoteFiles, pattern);
139 			}
140 			catch(IOException ie){
141 				throw new RemoteClientException("Could not read remote fileset", ie);
142 			}
143 		}
144 		else{
145 			matchingFileNames.add(fileName);
146 		}
147 		
148 		for(int i = 0; i < matchingFileNames.size(); i++){
149 			fileName = (String)matchingFileNames.get(i);
150 			//Get the destination file
151 			try {
152 				destinationFile = getDestinationFile(fileName, '/');
153 				fos = new FileOutputStream(destinationFile);
154 			} catch (FileNotFoundException e) {
155 				// Should never get here...
156 				throw new RemoteClientException(
157 						"Could not write to temporary file.", e);
158 			} catch (IOException e) {
159 				throw new RemoteClientException("Could not create temporary file.",
160 						e);
161 			}
162 
163 			try {
164 				// Get the destination file
165 				sftpClient.get(fileName, fos);
166 				downloadedFiles.add(destinationFile.getAbsolutePath());
167 
168 			} catch (IOException e) {
169 				throw new RemoteClientException("Could not download file", e);
170 			} finally {
171 				isBusy = false;
172 				// The stream is closed by the get method
173 				try {
174 					// Close the streams
175 					fos.close();
176 				} catch (IOException e1) {
177 					// Cant do anything here... just ignore it
178 				}
179 			}
180 		}
181 		//Converts the vector downloaded Files to a string array.
182 		String[] downloadedFileNames = new String[downloadedFiles.size()];
183 		for(int i = 0; i < downloadedFiles.size(); i++){
184 			downloadedFileNames[i] = (String)downloadedFiles.get(i);
185 		}
186 		// Return the paths of all files to the downloaded file.
187 		return downloadedFileNames;
188 	}
189 
190 	/**
191 	 * Returns a vector of filenames matching the given pattern. 
192 	 * @param remoteFiles	The list of remote files.
193 	 * @param pattern	The pattern to be matched with.
194 	 * @return	The matching file names as a vector.
195 	 */
196 	private List getMatchingFiles(List remoteFiles, String pattern){
197 		//Vector for storing the file names matching the given pattern
198 		List matchingFiles = new ArrayList(5);
199 		for(int i = 0; i < remoteFiles.size(); i++){
200 			String filePath = ((SftpFile)remoteFiles.get(i)).getAbsolutePath();
201 			String fileName = ((SftpFile)remoteFiles.get(i)).getFilename();
202 			//Checks whether the fileName matches the given wild card. 
203 			WildCardMatcher matcher = new WildCardMatcher(pattern);
204 			if(matcher.matches(fileName)){
205 				matchingFiles.add(filePath);
206 			}
207 			else{
208 			}
209 		}
210 		return matchingFiles;
211 	}
212 	
213 	/**
214 	 * @see com.mindtree.techworks.insight.download.RemoteClient#closeConnection()
215 	 */
216 	protected void closeConnection () throws RemoteClientException {
217 
218 		if (null != sshClient && sshClient.isConnected()) {
219 			try {
220 				sftpClient.quit();
221 			} catch (IOException e) {
222 				// Can't do anything here... just log it.
223 				e.printStackTrace(System.err);
224 			}
225 			sshClient.disconnect();
226 		}
227 
228 	}
229 
230 	//
231 	// Private util methods
232 	//
233 
234 	/**
235 	 * Creates an SFTP Connection
236 	 * 
237 	 * @throws RemoteClientException If the connection cannot be opened
238 	 */
239 	private synchronized void createSftpConnection ()
240 			throws RemoteClientException {
241 
242 		sshClient = new SshClient();
243 
244 		String host = fileset.getHost();
245 		int port = fileset.getPort();
246 		String startDirectory = fileset.getDefaultDirectory();
247 		PasswordAuthentication passwordAuthentication = fileset
248 				.getPasswordAuthentication();
249 
250 		// If the password is not set, use anonymous login
251 		if (null == passwordAuthentication) {
252 			passwordAuthentication = anonPassAuth;
253 		}
254 
255 		// Properties to connect.
256 		SshConnectionProperties sshConnectionProperties = new SshConnectionProperties();
257 		sshConnectionProperties.setHost(host);
258 		// The user might have specified the port to connect to (if other
259 		// than the default SFTP port). URL API specifies that -1 is returned
260 		// if no port is set. Otherwise the use the port.
261 		if (port != -1) {
262 			sshConnectionProperties.setPort(port);
263 		}
264 
265 		// TODO Explore proxy connections and add here.
266 
267 		try {
268 			sshClient.connect(sshConnectionProperties,
269 					new SshKnownHostKeyVerification(insight));
270 
271 
272 			// Authentication
273 			// TODO Check if other authentication mechanishms are required
274 			PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
275 			passwordAuthenticationClient.setUsername(passwordAuthentication
276 					.getUserName());
277 			passwordAuthenticationClient.setPassword(new StringBuffer().append(
278 					passwordAuthentication.getPassword()).toString());
279 
280 			if (sshClient.authenticate(passwordAuthenticationClient) != AuthenticationProtocolState.COMPLETE) {
281 				throw new RemoteClientException(
282 						"Could not complete authentication!");
283 			}
284 
285 			sftpClient = sshClient.openSftpClient();
286 
287 			// Change directory if required
288 			if (null != startDirectory && startDirectory.length() > 0) {
289 				sftpClient.cd(startDirectory);
290 			}
291 
292 		} catch (IOException e) {
293 			throw new RemoteClientException("Cannot open connection", e);
294 		}
295 	}
296 
297 	/**
298 	 * Private method used to check if an open connection is present, else
299 	 * creates one.
300 	 * 
301 	 * @throws RemoteClientException SFTPBrowseException is thrown if the
302 	 *             connection cannot be opened.
303 	 */
304 	private void checkConnection () throws RemoteClientException {
305 
306 		if (null == sshClient || !sshClient.isConnected()) {
307 			createSftpConnection();
308 		}
309 	}
310 
311 	//
312 	// Class to monitor progress
313 	//
314 
315 //	/**
316 //	 * This class notifies the instance of progress.
317 //	 * 
318 //	 * @see FileTransferProgress FileTransferProgress
319 //	 * @author Bindul Bhowmik
320 //	 * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
321 //	 */
322 //	protected class SFTPTransferProgressMonitor implements FileTransferProgress {
323 //
324 //		/**
325 //		 * Indicates total bytes to download
326 //		 */
327 //		private long totalBytes;
328 //
329 //		/**
330 //		 * The file being downloaded
331 //		 */
332 //		private String fileName;
333 //
334 //		/**
335 //		 * Creates a SFTPTransferProgressMonitor instance
336 //		 */
337 //		public SFTPTransferProgressMonitor () {
338 //
339 //			// Nothing to do
340 //		}
341 //
342 //		/**
343 //		 * @see com.sshtools.j2ssh.FileTransferProgress#started(long,
344 //		 *      java.lang.String)
345 //		 */
346 //		public void started (long bytesTotal, String remoteFile) {
347 //
348 //			this.totalBytes = bytesTotal;
349 //			this.fileName = remoteFile;
350 //			if (null != statusBar) {
351 //				statusBar.setDisplayText(1, InsightConstants
352 //						.getLiteral("DOWNLOAD_SFTP_FILE")
353 //						+ fileName, true);
354 //			}
355 //
356 //		}
357 //
358 //		/**
359 //		 * @see com.sshtools.j2ssh.FileTransferProgress#isCancelled()
360 //		 */
361 //		public boolean isCancelled () {
362 //
363 //			//If cancel option is to be provided, modify here.
364 //			return false;
365 //		}
366 //
367 //		/**
368 //		 * @see com.sshtools.j2ssh.FileTransferProgress#progressed(long)
369 //		 */
370 //		public void progressed (long bytesSoFar) {
371 //
372 //			long progress = Math.round(((float)bytesSoFar / totalBytes) * 100);
373 //			if (null != statusBar) {
374 //				statusBar
375 //						.setDisplayText(1, InsightConstants
376 //								.getLiteral("DOWNLOAD_SFTP_FILE")
377 //								+ fileName
378 //								+ " "
379 //								+ String.valueOf(progress)
380 //								+ "%", true);
381 //			}
382 //
383 //		}
384 //
385 //		/**
386 //		 * @see com.sshtools.j2ssh.FileTransferProgress#completed()
387 //		 */
388 //		public void completed () {
389 //
390 //			if (null != statusBar) {
391 //				statusBar.setDisplayText(0, InsightConstants
392 //						.getLiteral("DOWNLOAD_SFTP_FILE_COMPLETE" + fileName),
393 //						false);
394 //				statusBar.clearDisplay(1);
395 //			}
396 //		}
397 //	}
398 
399 }