package com.cadrlife.devsearch.agent.service.ftp; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.SocketException; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.lang.StringUtils; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cadrlife.devsearch.agent.service.RepoService; import com.cadrlife.devsearch.domain.Project; import com.google.common.base.Suppliers; import com.google.common.base.Throwables; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; public class FtpService extends RepoService { private static final Logger LOG = LoggerFactory.getLogger(FtpService.class); private String host; private String username; private String password; private String path; public FtpService(String host, String username, String password, String path) { this.host = host; this.username = username; this.password = password; this.path = path; } public static final List <String> TYPES_TO_INDEX = Arrays.asList("java", "cfm", "cfinc", "cfc", "xml", "xsl", "xslt", "js", "css", "vm", "ftl", "html", "htm", "config", "launch", "cfg", "sql", "jsp", "bat", "cmd", "properties", "groovy", "gs", "gsp", "txt", "sh", "classpath", "xsd", "tld", "mf", "ini", "json", "dtd", "wsdl", "py", "vins", "dat", "gradle", "htc", "vbs", "udf", "haml", "template", "scala", "conf", "fbprefs", "parm", "pl", "pm", "csv", "settings", "setting", "php", // VMS filetypes "inc", "pli", "ds", "cxx", "hxx", "fdl", "com", "c", "h", "cpp", // SQL "pb", "ps", "vw", "con", "grt", "tab", "trg", "pks", "pkb", "grt", "ind", "snp", "syn", "dpd", "synonym", "table", "view", "lst", "sqs", "ddl", "sequence", "schema", "prc", "viw"); public FTPFile[] listFiles() throws SocketException, IOException { FTPClient client = new FTPClient(); try { connectClient(client); return client.listFiles(); } finally { client.disconnect(); } } private void connectClient(FTPClient client) throws SocketException, IOException { client.connect(host); if (!client.isConnected()) { throw new IOException("Unable to connect: " + client.getReplyString()); } client.login(username, password); if (230 != client.getReplyCode()) { throw new IOException("Unable to login: " + client.getReplyString()); } client.changeWorkingDirectory(path); if (250 != client.getReplyCode()) { throw new IOException("Unable to change to directory: " + client.getReplyString()); } } @Override public List <Project> findAllProjects() { return findProjectsByName(getRepoName()); } @Override public void updateProject(File rootFile, Project projectName) { Map<String, FTPFile> files = new HashMap<String, FTPFile>(); LoadingCache <String,Integer> versions = CacheBuilder.newBuilder().build(CacheLoader.from(Suppliers.ofInstance(0))); try { for (FTPFile remoteFile : listFiles()) { if (remoteFile.isFile()) { String name = StringUtils.substringBeforeLast(remoteFile.getName(), ";"); String type = StringUtils.substringAfterLast(name, ".").toLowerCase(); // Weird bug : files that have a ^ in them likely were put into CMS via FTP/SCP if (TYPES_TO_INDEX.contains(type) && !name.contains("^")) { Integer version = Integer.parseInt(StringUtils.substringAfterLast(remoteFile.getName(), ";")); if (version > versions.get(name)) { versions.put(name, version); files.put(name, remoteFile); } } } } for (Entry<String,FTPFile> e : files.entrySet()) { String name = e.getKey(); FTPFile ftpFile = e.getValue(); FTPClient client = new FTPClient(); try { connectClient(client); InputStream fileStream = client.retrieveFileStream(name); if (null == fileStream) { LOG.warn("null stream for {}, bytes {}, reply: {}", ftpFile.getName(), ftpFile.getSize(), client.getReplyString()); } else { LOG.debug("saving to {}",rootFile.toPath().resolve(name)); saveStreamToFile(fileStream, rootFile.toPath().resolve(name).toFile()); } } finally { client.disconnect(); } } } catch (Exception e) { Throwables.propagate(e); } } @Override public String getSourceType() { return "ftp"; } }