content: /**
   * Alipay.com Inc.
   * Copyright (c) 2004-2012 All Rights Reserved.
   */
  package com.alipay.rdf.file.util;
  
  import java.io.File;
  import java.util.Vector;
  
  import org.apache.commons.io.FilenameUtils;
  
  import com.alipay.rdf.file.exception.RdfErrorEnum;
  import com.alipay.rdf.file.exception.RdfFileException;
  import com.alipay.rdf.file.operation.SftpFileEntry;
  import com.jcraft.jsch.ChannelSftp;
  import com.jcraft.jsch.ChannelSftp.LsEntry;
  import com.jcraft.jsch.SftpException;
  
  /**
   * SFTP文件传输帮助类。
   * 
   * <p>
   * 通过JSch实现SFTP文件上传和下载功能。
   * </p>
   * 
   * @author haofan.whf
   * @version $Id: SFTPHelper.java, v 0.1 2018-10-4 下午20:04:06 haofan.whf Exp $
   */
  public class SFTPHelper {
  
  
  	/**
  	 * 创建本地目录，如果目录不存在。
  	 * 
  	 * @param file
  	 * @return true表示创建成功或目录已存在，false表示失败
  	 */
  	public static boolean createLocalDirIfnotExist(String file) {
  		boolean success = false;
  		// 取文件的路径
  		String path = FilenameUtils.getFullPath(file);
  		try {
  			File dir = new File(path);
  			// 目录不存在，则创建之。
  			if (!dir.exists()) {
  				dir.mkdirs();
  			}
  			success = true;
  		} catch (Throwable e) {
  			RdfFileLogUtil.common.warn("rdf-file#SFTPHelper.createLocalDirIfnotExist异常,"
  					+ ",file={" + file + "}");
  			success = false;
  		}
  		return success;
  	}
  
  	/**
  	 * 创建FTP目录，如果目录不存在。
  	 *
  	 * @param sftp
  	 * @throws SftpException
  	 */
  	public static void createFTPDirIfnotExist(ChannelSftp sftp, String file) {
  		// 取出文件目录
  		String dir = FilenameUtils.getFullPath(file);
  
  		if (RdfFileUtil.isNotBlank(dir)) {
  			mkdirs(sftp, dir, 3);
  		}
  	}
  
  	/**
  	 * mkdir -p dir
  	 */
  	private static void mkdirs(ChannelSftp sftp, String dir, int retryTime){
  		String separator = "/"; // File.separator;
  		String[] names = dir.split(separator);
  		if (names != null && names.length > 0) {
  			boolean success = false;
  			while (!success && --retryTime >= 0) {
  				String parent = separator;
  				String current = null;
  				success = true;
  				for (int i = 0; i < names.length; i++) {
  					if (RdfFileUtil.isNotBlank(names[i])) {
  						current = parent + names[i] + separator;
  						parent = current;
  						try{
  							mkdirIfNotExist(sftp, current);
  						}catch (SftpException e){
  							RdfFileLogUtil.common.warn("rdf-file#SFTPHelper.mkdirs"
  									+ "创建SFTP目录失败，3秒后尝试再次创建，剩余创建尝试次数：{" + retryTime + "}"
  									+ ",current={" + current + "},dir={" + dir + "}", e);
  							success = false;
  							try {
  								Thread.sleep(3000);
  							} catch (InterruptedException e1) {
  								RdfFileLogUtil.common.warn("rdf-file#SFTPHelper.mkdirs"
  										+ "等待中断dir={" + dir + "}", e1);
  							}
  						}
  					}
  				}
  			}
  			if(!success){
  				throw new RdfFileException("rdf-file#SFTPHelper.mkdirs,创建SFTP目录彻底失败,dir={" + dir + "}"
  						, RdfErrorEnum.UNKOWN);
  			}
  		}
  	}
  
  	/**
  	 * 当前路径下创建文件夹
  	 * @param sftp
  	 * @param currentPath
  	 * @throws SftpException
  	 */
  	private synchronized static void mkdirIfNotExist(ChannelSftp sftp, String currentPath) throws SftpException{
  		try {
  			sftp.cd(currentPath);
  		} catch (SftpException e) {
  			// 如目录不存在，则创建之
  			try {
  				sftp.cd("/");
  				sftp.mkdir(currentPath);
  				RdfFileLogUtil.common.info("rdf-file#SFTPHelper"
  						+ ".mkdirIfNotExist,create path={" + currentPath + "} success.", e);
  			} catch (SftpException e1) {
  				RdfFileLogUtil.common.warn("rdf-file#SFTPHelper"
  						+ ".mkdirIfNotExist,create path={" + currentPath + "} failed.");
  				throw e1;
  			}
  		}
  	}
  
  	/**
  	 *
  	 * @param sftp
  	 * @param dir
  	 * @param recursiveList  递归查询
  	 * @return
  	 * @throws SftpException
  	 */
  	public static Vector<SftpFileEntry> listFiles(ChannelSftp sftp, String dir, boolean recursiveList) throws SftpException {
  		Vector<SftpFileEntry> fileEntries = new Vector<SftpFileEntry>();
  		listAllFiles(sftp, dir, fileEntries, recursiveList);
  		return fileEntries;
  	}
  
  	private static void listAllFiles(ChannelSftp sftp, String dir, Vector<SftpFileEntry> fileEntries, boolean recursiveList) throws SftpException {
  		// 如果参数不是目录则抛出异常
  		if (!sftp.stat(dir).isDir()) {
  			throw new RdfFileException("target is not dir, target=" + dir, RdfErrorEnum.UNSUPPORTED_OPERATION);
  		}
  		Vector<LsEntry> currentLsEntryVec = sftp.ls(dir);
  		for(LsEntry lsEntry : currentLsEntryVec){
  			SftpFileEntry sftpFileEntry = SftpFileEntry
  					.buildFileEntry(RdfFileUtil.combinePath(dir, lsEntry.getFilename()), lsEntry);
  			if(sftpFileEntry.isDir()){
  				if(recursiveList && (!sftpFileEntry.isCurrentDir() && !sftpFileEntry.isPrevDir())) {
  					listAllFiles(sftp, sftpFileEntry.getFullFileName(), fileEntries, true);
  				}
  			}else{
  				fileEntries.add(sftpFileEntry);
  			}
  		}
  	}
  
  	/**
  	 * 递归删除目录下的所有目录和文件
  	 * @param sftp
  	 * @param dir
  	 * @throws SftpException
  	 */
  	public static void removeDir(ChannelSftp sftp, String dir) throws SftpException {
  		doRemove(sftp, dir);
  	}
  
  	private static void doRemove(ChannelSftp sftp, String dir) throws SftpException{
  		// 如果参数不是目录则抛出异常
  		if (!sftp.stat(dir).isDir()) {
  			throw new RdfFileException("target is not dir, target=" + dir, RdfErrorEnum.UNSUPPORTED_OPERATION);
  		}
  		Vector<LsEntry> currentLsEntryVec = sftp.ls(dir);
  		for(LsEntry lsEntry : currentLsEntryVec){
  			SftpFileEntry sftpFileEntry = SftpFileEntry
  					.buildFileEntry(RdfFileUtil.combinePath(dir, lsEntry.getFilename()), lsEntry);
  			if(sftpFileEntry.isDir()){
  				if((!sftpFileEntry.isCurrentDir() && !sftpFileEntry.isPrevDir())){
  					doRemove(sftp, sftpFileEntry.getFullFileName());
  				}
  			}else{
  				sftp.rm(sftpFileEntry.getFullFileName());
  			}
  		}
  		sftp.rmdir(dir);
  	}
  
  	/**
  	 * sftp based on UNIX-like naming scheme for file pathname
  	 * so we translate all filePath into unix-like scheme
  	 * @param filePath
  	 * @return
  	 */
  	public static String toSFTPPath(String filePath) {
  		filePath = filePath.replaceAll("\\\\", "/");
  		return filePath;
  	}
  
  }
  