/* * Copyright 2011 Esri. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.esri.gpt.control.webharvest.client.waf; import com.esri.gpt.framework.http.CredentialProvider; import com.esri.gpt.framework.util.Val; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.SocketException; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPConnectionClosedException; import org.apache.commons.net.ftp.FTPFile; /** * FTP request. */ class FtpClientRequest { private static final Logger LOG = Logger.getLogger(FtpClientRequest.class.getCanonicalName()); private static final int DEFAULT_NO_OF_ATTEMPTS = 5; private FTPClient client = new FTPClient(); private String protocol; private String host; private int port; private String root; private CredentialProvider cp; private int noOfAttempts = DEFAULT_NO_OF_ATTEMPTS; private boolean aborted; /** * Creates instance of the request. * @param url url * @param cp credential provider */ public FtpClientRequest(URL url, CredentialProvider cp) { this.protocol = Val.chkStr(url.getProtocol()); this.host = Val.chkStr(url.getHost()); this.port = url.getPort() >= 0 ? url.getPort() : 21; this.root = Val.chkStr(url.getPath()).replaceAll("/$", ""); this.cp = cp; } /** * Gets number of attempts. * @return number of attempts */ public int getNoOfAttempts() { return noOfAttempts; } /** * Sets number of attempts. * @param noOfAttempts number of attempts */ public void setNoOfAttempts(int noOfAttempts) { this.noOfAttempts = noOfAttempts; } /** * Gets server. * @return server */ public String getServer() { return protocol + "://" + host + (port != 21 ? ":" + port : ""); } /** * Gets folder. * @return folder */ public String getRootFolder() { return root; } /** * Checks if connected. * @return <code>true</code> if connected */ public boolean isConnected() { return client.isConnected(); } /** * Checks if aborted. * @return <code>true</code> if aborted */ public boolean isAborted() { return aborted; } /** * Connects to the server. * @throws IOException if connecting fails */ public void connect() throws IOException { aborted = false; try { LOG.log(Level.INFO, "Connecting to: {0}", host); client.connect(host, port); if (cp == null) { client.login("anonymous", "anonymous"); } else { client.login(cp.getUsername(), cp.getPassword()); } client.setKeepAlive(true); client.enterLocalPassiveMode(); } catch (IOException ex) { aborted = true; throw ex; } } /** * Disconnects from the server. */ public void disconnect() { aborted = false; LOG.log(Level.INFO, "Disconnecting from: {0}", host); try { client.logout(); } catch (Exception ex) { LOG.log(Level.FINE, "Error disconnecting from the host: " + host, ex); } try { client.disconnect(); } catch (Exception ex) { LOG.log(Level.FINE, "Error disconnecting from the host: " + host, ex); } } public FTPFile[] listFiles(String pathName) throws IOException { try { LOG.log(Level.FINE, "Listing files on: {0} from the path: {1}", new Object[]{host, pathName}); return listFiles(1, pathName); } catch (IOException ex) { aborted = true; throw ex; } } protected FTPFile[] listFiles(int attempt, String pathName) throws IOException { try { stayOpen(); return client.listFiles(pathName); } catch (SocketException ex) { if (attempt < getNoOfAttempts()) { LOG.log(Level.INFO, "Listing files [attempt: {2}] on: {0} from the path: {1}", new Object[]{host, pathName, attempt + 1}); reConnect(); return listFiles(attempt + 1, pathName); } else { throw ex; } } catch (FTPConnectionClosedException ex) { if (attempt < getNoOfAttempts()) { LOG.log(Level.INFO, "Listing files [attempt: {2}] on: {0} from the path: {1}", new Object[]{host, pathName, attempt + 1}); reConnect(); return listFiles(attempt + 1, pathName); } else { throw ex; } } } public String readTextFile(String pathName) throws IOException { try { LOG.log(Level.FINE, "Reading text file on: {0} from the path: {1}", new Object[]{host, pathName}); return readTextFile(1, pathName); } catch (IOException ex) { aborted = true; throw ex; } } protected String readTextFile(int attempt, String pathName) throws IOException { InputStream input = null; Reader reader = null; try { stayOpen(); StringBuilder sb = new StringBuilder(); input = client.retrieveFileStream(pathName); if (input != null) { reader = new InputStreamReader(input, "UTF-8"); char[] buff = new char[1000]; int length = 0; while ((length = reader.read(buff)) >= 0) { sb.append(buff, 0, length); } } return sb.toString(); } catch (SocketException ex) { if (attempt < getNoOfAttempts()) { LOG.log(Level.INFO, "Reading text file [attempt: {2}] on: {0} from the path: {1}", new Object[]{host, pathName, attempt + 1}); reConnect(); return readTextFile(attempt + 1, pathName); } else { throw ex; } } catch (FTPConnectionClosedException ex) { if (attempt < getNoOfAttempts()) { LOG.log(Level.INFO, "Reading text file [attempt: {2}] on: {0} from the path: {1}", new Object[]{host, pathName, attempt + 1}); reConnect(); return readTextFile(attempt + 1, pathName); } else { throw ex; } } finally { if (reader != null) { try { reader.close(); } catch (IOException ex) { LOG.log(Level.FINE, "Error closing reader on: " + host, ex); } } if (input != null) { try { input.close(); } catch (IOException ex) { LOG.log(Level.FINE, "Error closing input on: " + host, ex); } } try { client.completePendingCommand(); } catch (IOException ex) { LOG.log(Level.FINE, "Error completing pending command: " + host, ex); } } } protected void reConnect() throws IOException { disconnect(); connect(); } protected void stayOpen() throws IOException { if (!isConnected()) { connect(); } } }