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.sftpbrowse;
26  
27  import java.awt.Component;
28  import java.io.File;
29  import java.io.IOException;
30  import java.net.PasswordAuthentication;
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.logging.Level;
34  import java.util.logging.Logger;
35  
36  import javax.swing.filechooser.FileSystemView;
37  
38  import com.mindtree.techworks.insight.download.SshKnownHostKeyVerification;
39  import com.sshtools.j2ssh.SftpClient;
40  import com.sshtools.j2ssh.SshClient;
41  import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
42  import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient;
43  import com.sshtools.j2ssh.configuration.SshConnectionProperties;
44  import com.sshtools.j2ssh.sftp.FileAttributes;
45  import com.sshtools.j2ssh.sftp.SftpFile;
46  
47  
48  /**
49   * This class is used for browsing a remote file system. This class uses an
50   * instance of the {@link com.sshtools.j2ssh.SftpClient SftpClient} to
51   * connect to the underlying FTP Source. Connection timeouts may occur.
52   * 
53   * @see javax.swing.filechooser.FileSystemView FileSystemView
54   * 
55   * @author Bindul Bhowmik
56   * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
57   * 
58   */
59  public class SFTPRemoteFileSystemView extends FileSystemView {
60  	//
61  	// Constants
62  	//
63  
64  	/**
65  	 * The logger instance for this class
66  	 */
67  	protected static final Logger logger = Logger
68  			.getLogger(SFTPRemoteFileSystemView.class.getName());
69  	
70  	/**
71  	 * Password Authentication to use for anonymous access
72  	 */
73  	public static final PasswordAuthentication anonPassAuth = new PasswordAuthentication(
74  			"anonymous", "insight@mindtree.com".toCharArray());
75  
76  	/**
77  	 * The root file system path
78  	 */
79  	protected static final String FILE_SYSTEM_ROOT_NAME = "/";
80  
81  	/**
82  	 * Seperator character between files
83  	 */
84  	public static final String FILE_SEPERATOR = "/";
85  	
86  	//
87  	// Instance variables
88  	//
89  
90  	/**
91  	 * Parent component used for messages
92  	 */
93  	private Component parentComponent;
94  	
95  	/**
96  	 * The SSH Client used to create the SFTP Client
97  	 */
98  	private SshClient sshClient;
99  	
100 	/**
101 	 * The SftpClient Object used to browse the underlying source.
102 	 */
103 	private SftpClient sftpClient;
104 
105 	/**
106 	 * The host to connect to
107 	 */
108 	private String host;
109 	
110 	/**
111 	 * The port to connect to
112 	 */
113 	private int port = -1;
114 	
115 	/**
116 	 * The directory to start browsing in
117 	 */
118 	private String startDirectory;
119 	
120 	/**
121 	 * The Authentication information
122 	 */
123 	private PasswordAuthentication passwordAuthentication;
124 
125 	/**
126 	 * The default directory of the connection
127 	 */
128 	private String homeDirectory;
129 
130 	//
131 	// Constructors
132 	//
133 
134 	/**
135 	 * Creates an instance of the <code>FTPRemoteFileSystemView</code>. The
136 	 * host name supplied should be the same as one would pass to construct an
137 	 * URL object.
138 	 * 
139 	 * @param host The address of the host. This can be a host name or IP
140 	 *            address.
141 	 * @param port The port to connect to.
142 	 * @param startDirectory The directory to start browsing in
143 	 * @param passwordAuthentication The credentials to connect with. This can
144 	 *            be null.
145 	 * @param parentComponent Parent component used for messages
146 	 * @throws SFTPBrowseException If the host is null.
147 	 */
148 	public SFTPRemoteFileSystemView (String host, int port, String startDirectory, 
149 			PasswordAuthentication passwordAuthentication, Component parentComponent)
150 			throws SFTPBrowseException {
151 
152 
153 		if (host == null || host.length() == 0) {
154 			throw new SFTPBrowseException("Host null!");
155 		}
156 		
157 		this.host = host;
158 		this.startDirectory = startDirectory;
159 		this.port = port;
160 		this.parentComponent = parentComponent;
161 		if (null != passwordAuthentication) {
162 			this.passwordAuthentication = passwordAuthentication;
163 		} else {
164 			this.passwordAuthentication = anonPassAuth;
165 		}
166 	}
167 
168 	/**
169 	 * Creates an instance of the <code>FTPRemoteFileSystemView</code>. The
170 	 * host name supplied should be the same as one would pass to construct an
171 	 * URL object.
172 	 * 
173 	 * @param host The address of the host. This can be a host name or IP
174 	 *            address.
175 	 * @param startDirectory The directory to start browsing in
176 	 * @param passwordAuthentication The credentials to use to connect. Can be
177 	 *            null.
178 	 * @param parentComponent Parent component used for messages
179 	 * @throws SFTPBrowseException if the host is null
180 	 */
181 	public SFTPRemoteFileSystemView (String host, String startDirectory, 
182 			PasswordAuthentication passwordAuthentication, Component parentComponent)
183 			throws SFTPBrowseException {
184 
185 		if (host == null || host.length() == 0) {
186 			throw new SFTPBrowseException("Host null!");
187 		}
188 
189 		this.host = host;
190 		this.parentComponent = parentComponent;
191 		this.startDirectory = startDirectory;
192 		if (null != passwordAuthentication) {
193 			this.passwordAuthentication = passwordAuthentication;
194 		} else {
195 			this.passwordAuthentication = anonPassAuth;
196 		}
197 
198 	}
199 	
200 	//
201 	// Accessors
202 	//
203 
204 	/**
205 	 * @return Returns the passwordAuthentication.
206 	 */
207 	public PasswordAuthentication getPasswordAuthentication () {
208 
209 		return passwordAuthentication;
210 	}
211 	
212 	/**
213 	 * @return Returns the host.
214 	 */
215 	public String getHost () {
216 
217 		return this.host;
218 	}
219 	
220 	/**
221 	 * @return The port to connect to.
222 	 */
223 	public int getPort() {
224 		return this.port;
225 	}
226 	
227 	//
228 	// Utility Methods
229 	//
230 
231 	/**
232 	 * Creates an SFTP Connection
233 	 * 
234 	 * @throws SFTPBrowseException If the connection cannot be opened
235 	 */
236 	private synchronized void createSftpConnection () throws SFTPBrowseException {
237 
238 		sshClient = new SshClient();
239 		
240 		// Properties to connect.
241 		SshConnectionProperties sshConnectionProperties = new SshConnectionProperties();
242 		sshConnectionProperties.setHost(this.host);
243 		// The user might have specified the port to connect to (if other
244 		// than the default SFTP port). URL API specifies that -1 is returned
245 		// if no port is set. Otherwise the use the port.
246 		if (this.port != -1) {
247 			sshConnectionProperties.setPort(this.port);
248 		}
249 		
250 		// TODO Explore proxy connections and add here.
251 		
252 		try {
253 			sshClient.connect(sshConnectionProperties, new SshKnownHostKeyVerification(parentComponent));
254 
255 
256 			// Authentication
257 			// TODO Check if other authentication mechanishms are required
258 			PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
259 			passwordAuthenticationClient.setUsername(passwordAuthentication
260 					.getUserName());
261 			passwordAuthenticationClient.setPassword(new StringBuffer().append(
262 					passwordAuthentication.getPassword()).toString());
263 
264 			if (sshClient.authenticate(passwordAuthenticationClient) != AuthenticationProtocolState.COMPLETE) {
265 				throw new SFTPBrowseException(
266 						"Could not complete authentication!");
267 			}
268 
269 			sftpClient = sshClient.openSftpClient();
270 
271 			// Change directory if required
272 			if (null != this.startDirectory && this.startDirectory.length() > 0) {
273 				sftpClient.cd(this.startDirectory);
274 			}
275 
276 			homeDirectory = sftpClient.pwd();
277 		} catch (IOException e) {
278 			throw new SFTPBrowseException(e.getMessage());
279 		}
280 	}
281 
282 	/**
283 	 * Private method used to check if an open connection is present, else
284 	 * creates one.
285 	 * 
286 	 * @throws SFTPBrowseException SFTPBrowseException is thrown if the connection
287 	 *             cannot be opened.
288 	 */
289 	private void checkConnection () throws SFTPBrowseException {
290 
291 		if (null == sshClient || !sshClient.isConnected()) {
292 			createSftpConnection();
293 		}
294 	}
295 	
296 	//
297 	// Public Methods
298 	//
299 	
300 	/**
301 	 * If a connection to the server is still open, disconnects it.
302 	 */
303 	public void disconnect () {
304 
305 		if (null != sshClient && sshClient.isConnected()) {
306 			try {
307 				sftpClient.quit();
308 			} catch (IOException e) {
309 				// Can't do anything here... just log it.
310 				logger.log(Level.WARNING, "Could not close connection", e);
311 			}
312 			sshClient.disconnect();
313 		}
314 	}
315 	
316 	//
317 	// Overridden methods from FileSystemView
318 	//
319 
320 	/**
321 	 * @see javax.swing.filechooser.FileSystemView#createNewFolder(java.io.File)
322 	 */
323 	public File createNewFolder (File containingDir) throws IOException {
324 
325 		// This is a read only view of the remote system only.
326 		throw new SFTPBrowseException(
327 				"This file system view supports READ ONLY support ONLY!");
328 	}
329 
330 	/**
331 	 * In the remote view home and default directory are considered to be the
332 	 * same.
333 	 * 
334 	 * @see javax.swing.filechooser.FileSystemView#getDefaultDirectory()
335 	 */
336 	public File getDefaultDirectory () {
337 
338 		return getHomeDirectory();
339 	}
340 
341 	/**
342 	 * @see javax.swing.filechooser.FileSystemView#getHomeDirectory()
343 	 */
344 	public File getHomeDirectory () {
345 
346 		try {
347 			checkConnection();
348 			//If home directory is the root directory then return that
349 			if (homeDirectory.equals(FILE_SYSTEM_ROOT_NAME)) {
350 				return getRoots()[0];
351 			}
352 
353 			// Get the file information
354 			SFTPFileFile sftpFileFile = null;
355 			try {
356 				String parent = homeDirectory.substring(0, homeDirectory
357 						.lastIndexOf(FILE_SEPERATOR));
358 				
359 				// FIXME Correct this
360 				List returnedFiles = sftpClient.ls(parent);
361 				String dirName = homeDirectory.substring(homeDirectory
362 						.lastIndexOf(FILE_SEPERATOR) + 1);
363 				for (int i = 0; i < returnedFiles.size(); i++ ) {
364 					SftpFile returnedFile = (SftpFile) returnedFiles.get(i);
365 					if (returnedFile.getFilename().equals(dirName)) {
366 						sftpFileFile = new SFTPFileFile(returnedFile, this);
367 					}
368 				}
369 			} catch (SFTPBrowseException e) {
370 				logger.log(Level.WARNING, "Problem browsing file system", e);
371 			} catch (IOException e) {
372 				logger.log(Level.WARNING, "Problem browsing file system", e);
373 			}
374 
375 			return sftpFileFile;
376 		} catch (SFTPBrowseException e) {
377 			logger.log(Level.WARNING, "FTBEx", e);
378 		}
379 
380 		return null;
381 	}
382 
383 	/**
384 	 * @see javax.swing.filechooser.FileSystemView#getRoots()
385 	 */
386 	public File [] getRoots () {
387 
388 		SFTPFileFile [] sftpFiles = null;
389 		try {
390 			checkConnection();
391 
392 			sftpClient.cd(FILE_SYSTEM_ROOT_NAME);
393 			SftpFile sSftpFile = new SftpFile(sftpClient.pwd(), sftpClient.stat(FILE_SYSTEM_ROOT_NAME));
394 			sSftpFile.getAttributes().setPermissions(String.valueOf(FileAttributes.S_IFDIR));
395 			SFTPFileFile sSFTPFileFile = new SFTPFileFile(sSftpFile, this);
396 			sftpFiles = new SFTPFileFile [1];
397 			sftpFiles[0] = sSFTPFileFile;
398 		} catch (SFTPBrowseException e) {
399 			logger.log(Level.WARNING, "Could not get root file", e);
400 		} catch (IOException e) {
401 			logger.log(Level.WARNING, "Could not get root file", e);
402 		} 
403 		return sftpFiles;
404 	}
405 
406 	/**
407 	 * @see javax.swing.filechooser.FileSystemView#createFileObject(java.io.File,
408 	 *      java.lang.String)
409 	 */
410 	public File createFileObject (File dir, String filename) {
411 
412 		// We should never get here. If we ever do, call the parent and hope for
413 		// the best!!!
414 		logger.fine("Calling Super with: " + dir.toString() + " " + filename);
415 		return super.createFileObject(dir, filename);
416 	}
417 
418 	/**
419 	 * @see javax.swing.filechooser.FileSystemView#createFileObject(java.lang.String)
420 	 */
421 	public File createFileObject (String path) {
422 
423 		// We should never get here. If we ever do, call the parent and hope for
424 		// the best!!!
425 		logger.fine("Calling Super with: " + path);
426 		return super.createFileObject(path);
427 	}
428 
429 	/**
430 	 * @see javax.swing.filechooser.FileSystemView#getChild(java.io.File,
431 	 *      java.lang.String)
432 	 */
433 	public File getChild (File parent, String fileName) {
434 
435 		if (parent instanceof SFTPFileFile) {
436 			SftpFile parentDir = ((SFTPFileFile) parent).getSftpFile();
437 			SFTPFileFile returnedFile = null;
438 			try {
439 				checkConnection();
440 				List returnedFiles = sftpClient.ls(parentDir.getAbsolutePath());
441 				
442 				// Check if a path name is present.
443 				if (fileName.indexOf(FILE_SEPERATOR) > -1) {
444 					fileName = fileName.substring(fileName
445 							.lastIndexOf(FILE_SEPERATOR) + 1);
446 				}
447 				for (int i = 0; i < returnedFiles.size(); i++ ) {
448 					SftpFile returnedSftpFile = (SftpFile) returnedFiles.get(i);
449 					if (returnedSftpFile.getFilename().equals(fileName)) {
450 						returnedFile = new SFTPFileFile(returnedSftpFile, this);
451 					}
452 				}
453 			} catch (SFTPBrowseException e) {
454 				logger.log(Level.WARNING, "Problem browsing file system", e);
455 			} catch (IOException e) {
456 				logger.log(Level.WARNING, "Problem browsing file system", e);
457 			}
458 			return returnedFile;
459 		} else {
460 			// Should never get here!!!
461 			logger.fine("Calling Super with: " + parent.toString() + " " + fileName);
462 			return super.getChild(parent, fileName);
463 		}
464 	}
465 
466 	/**
467 	 * @see javax.swing.filechooser.FileSystemView#getFiles(java.io.File,
468 	 *      boolean)
469 	 */
470 	public synchronized File [] getFiles (File dir, boolean useFileHiding) {
471 
472 		if (dir instanceof SFTPFileFile && dir.isDirectory()) {
473 			SftpFile sftpFile = ((SFTPFileFile) dir).getSftpFile();
474 			String name = sftpFile.getAbsolutePath();
475 			try {
476 				checkConnection();
477 
478 				// FIXME Fix parsing
479 				List returnedFiles = sftpClient.ls(name);
480 //				SFTPFileFile [] sftpFiles = new SFTPFileFile [returnedFiles.size()];
481 				List modifiedFileList = new ArrayList(returnedFiles.size());
482 				for (int i = 0; i < returnedFiles.size(); i++ ) {
483 					SftpFile returnedFile = (SftpFile) returnedFiles.get(i);
484 					String returnedFileName = returnedFile.getFilename();
485 					if (returnedFileName.equals(".") || returnedFileName.equals("..")) {
486 						continue;
487 					}
488 					modifiedFileList.add(new SFTPFileFile(returnedFile, this));
489 				}
490 				
491 				SFTPFileFile [] sftpFiles = (SFTPFileFile[]) modifiedFileList.toArray(new SFTPFileFile[modifiedFileList.size()]); 
492 				
493 				return sftpFiles;
494 
495 			} catch (SFTPBrowseException e) {
496 				logger.log(Level.WARNING, "Could not connect to host", e);
497 				return new SFTPFileFile [0];
498 			} catch (IOException e) {
499 				logger.log(Level.WARNING, "Could not operate on host", e);
500 				return new SFTPFileFile [0];
501 			} catch (Exception e) {
502 				logger.log(Level.WARNING, "Could not operate on host", e);
503 				return new SFTPFileFile [0];
504 			}
505 		}
506 		// Should never get here
507 		logger.fine("Calling Super with: " + dir.toString() + " " + String.valueOf(useFileHiding));
508 		return super.getFiles(dir, useFileHiding);
509 
510 	}
511 
512 	/**
513 	 * @see javax.swing.filechooser.FileSystemView#getParentDirectory(java.io.File)
514 	 */
515 	public File getParentDirectory (File dir) {
516 
517 		if (dir instanceof SFTPFileFile) {
518 
519 			SftpFile sftpFile = ((SFTPFileFile) dir).getSftpFile();
520 			String name = sftpFile.getAbsolutePath();
521 			if (name.equals(FILE_SYSTEM_ROOT_NAME)) {
522 				return null;
523 			}
524 
525 			String parent = name.substring(0, name.lastIndexOf(FILE_SEPERATOR));
526 
527 			// Parent is the root
528 			if (parent.equals(FILE_SYSTEM_ROOT_NAME)) {
529 				return getRoots()[0];
530 			}
531 
532 			// Parent of the parent to list the parent
533 			String pparent = parent.substring(0, parent
534 					.lastIndexOf(FILE_SEPERATOR));
535 			if (pparent.length() == 0) {
536 				pparent = FILE_SYSTEM_ROOT_NAME;
537 			}
538 
539 			SFTPFileFile parentFile = null;
540 
541 			try {
542 				checkConnection();
543 				// FIXME Correct list parsing
544 				List returnedFiles = sftpClient.ls(pparent);
545 				
546 				String parentName = parent.substring(parent
547 						.lastIndexOf(FILE_SEPERATOR) + 1);
548 				for (int i = 0; i < returnedFiles.size(); i++ ) {
549 					SftpFile returnedFile = (SftpFile) returnedFiles.get(i);
550 					if (returnedFile.getFilename().equals(parentName)) {
551 						parentFile = new SFTPFileFile(returnedFile, this);
552 					}
553 				}
554 			} catch (SFTPBrowseException e) {
555 				logger.log(Level.WARNING, "Problem browsing file system", e);
556 			} catch (IOException e) {
557 				logger.log(Level.WARNING, "Problem browsing file system", e);
558 			}
559 
560 			if (null == parentFile) {
561 				parentFile = (SFTPFileFile) getRoots()[0];
562 			}
563 
564 			return parentFile;
565 		}
566 		
567 		logger.fine("Calling Super with: " + dir.toString());
568 		return super.getParentDirectory(dir);
569 	}
570 
571 	/**
572 	 * @see javax.swing.filechooser.FileSystemView#getSystemDisplayName(java.io.File)
573 	 */
574 	public String getSystemDisplayName (File f) {
575 
576 		if (f instanceof SFTPFileFile) {
577 			SftpFile sftpFile = ((SFTPFileFile) f).getSftpFile();
578 			String name = sftpFile.getAbsolutePath();
579 			if (FILE_SYSTEM_ROOT_NAME.equals(name)) {
580 				return this.host;
581 			} else {
582 				return f.getName();
583 			}
584 		} else {
585 			logger.fine("Calling Super with: " + f.getPath());
586 			return super.getSystemDisplayName(f);
587 		}
588 	}
589 
590 	/**
591 	 * Always returns null. The super class uses this to return special folder
592 	 * names such as 'Desktop' on Windows.
593 	 * 
594 	 * @see javax.swing.filechooser.FileSystemView#getSystemTypeDescription(java.io.File)
595 	 */
596 	public String getSystemTypeDescription (File f) {
597 
598 		return null;
599 	}
600 
601 	/**
602 	 * @see javax.swing.filechooser.FileSystemView#isComputerNode(java.io.File)
603 	 */
604 	public boolean isComputerNode (File dir) {
605 
606 		if (dir instanceof SFTPFileFile) {
607 			SftpFile sftpFile = ((SFTPFileFile) dir).getSftpFile();
608 			String name = sftpFile.getAbsolutePath();
609 			if (FILE_SYSTEM_ROOT_NAME.equals(name)) {
610 				return true;
611 			} else {
612 				return false;
613 			}
614 
615 		} else {
616 			return super.isComputerNode(dir);
617 		}
618 	}
619 
620 	/**
621 	 * Returns false, drives not supported on remote systems
622 	 * 
623 	 * @see javax.swing.filechooser.FileSystemView#isDrive(java.io.File)
624 	 */
625 	public boolean isDrive (File dir) {
626 
627 		return false;
628 	}
629 
630 	/**
631 	 * Determines if the file is a real file or a link to another file.
632 	 * 
633 	 * @see javax.swing.filechooser.FileSystemView#isFileSystem(java.io.File)
634 	 * @return <code>true</code> if it is an absolute file or
635 	 *         <code>false</code>
636 	 */
637 	public boolean isFileSystem (File f) {
638 
639 		if (f instanceof SFTPFileFile) {
640 			SftpFile sftpFile = ((SFTPFileFile) f).getSftpFile();
641 			return !sftpFile.isLink();
642 		}
643 		logger.fine("Calling Super for: " + f.toString());
644 		return super.isFileSystem(f);
645 	}
646 
647 	/**
648 	 * @see javax.swing.filechooser.FileSystemView#isFileSystemRoot(java.io.File)
649 	 */
650 	public boolean isFileSystemRoot (File dir) {
651 
652 		if (dir instanceof SFTPFileFile) {
653 			SftpFile sftpFile = ((SFTPFileFile) dir).getSftpFile();
654 			String name = sftpFile.getAbsolutePath();
655 			if (FILE_SYSTEM_ROOT_NAME.equals(name)) {
656 				return true;
657 			} else {
658 				return false;
659 			}
660 		}
661 		logger.fine("Calling Super for: " + dir.toString());
662 		return super.isFileSystemRoot(dir);
663 	}
664 
665 	/**
666 	 * Returns false. No floppy drives are viewable.
667 	 * 
668 	 * @see javax.swing.filechooser.FileSystemView#isFloppyDrive(java.io.File)
669 	 */
670 	public boolean isFloppyDrive (File dir) {
671 
672 		return false;
673 	}
674 
675 	/**
676 	 * Hidden files are not supported now. Maybe later!
677 	 * 
678 	 * @see javax.swing.filechooser.FileSystemView#isHiddenFile(java.io.File)
679 	 */
680 	public boolean isHiddenFile (File f) {
681 
682 		return false;
683 	}
684 
685 	/**
686 	 * @see javax.swing.filechooser.FileSystemView#isParent(java.io.File,
687 	 *      java.io.File)
688 	 */
689 	public boolean isParent (File folder, File file) {
690 
691 		if (folder instanceof SFTPFileFile && file instanceof SFTPFileFile) {
692 			// If file is a SFTPFileFile, you will always get back an SFTPFileFile
693 			SFTPFileFile calculatedParent = (SFTPFileFile) getParentDirectory(file);
694 			String parentPath = ((SFTPFileFile) folder).getSftpFile().getAbsolutePath();
695 			if (parentPath.equals(calculatedParent.getSftpFile().getAbsolutePath())) {
696 				return true;
697 			} else {
698 				return false;
699 			}
700 		}
701 		logger.fine("Calling Super for: " + folder.toString() + " " + file.toString());
702 		return super.isParent(folder, file);
703 	}
704 
705 	/**
706 	 * @see javax.swing.filechooser.FileSystemView#isRoot(java.io.File)
707 	 */
708 	public boolean isRoot (File f) {
709 
710 		if (null == f) {
711 			return false;
712 		}
713 		
714 		if (f instanceof SFTPFileFile) {
715 			SftpFile sftpFile = ((SFTPFileFile) f).getSftpFile();
716 			String name = sftpFile.getAbsolutePath();
717 			if (FILE_SYSTEM_ROOT_NAME.equals(name)) {
718 				return true;
719 			} else {
720 				return false;
721 			}
722 		}
723 		logger.fine("Calling super for: " + f.toString());
724 		return super.isRoot(f);
725 	}
726 
727 	/**
728 	 * @see javax.swing.filechooser.FileSystemView#isTraversable(java.io.File)
729 	 */
730 	public Boolean isTraversable (File f) {
731 
732 		if (f instanceof SFTPFileFile) {
733 			SftpFile sftpFile = ((SFTPFileFile) f).getSftpFile();
734 			return new Boolean(sftpFile.isDirectory());
735 		}
736 		logger.fine("Calling super for: " + f.toString());
737 		return super.isTraversable(f);
738 	}
739 
740 }